synapto-hub 0.1.0__tar.gz
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.
- synapto_hub-0.1.0/.gitignore +10 -0
- synapto_hub-0.1.0/LICENSE +21 -0
- synapto_hub-0.1.0/PKG-INFO +125 -0
- synapto_hub-0.1.0/README.md +97 -0
- synapto_hub-0.1.0/pyproject.toml +65 -0
- synapto_hub-0.1.0/src/synapto/__init__.py +1 -0
- synapto_hub-0.1.0/src/synapto/bundle/__init__.py +1 -0
- synapto_hub-0.1.0/src/synapto/bundle/decisions.py +86 -0
- synapto_hub-0.1.0/src/synapto/bundle/models.py +346 -0
- synapto_hub-0.1.0/src/synapto/bundle/validator.py +553 -0
- synapto_hub-0.1.0/src/synapto/cli.py +287 -0
- synapto_hub-0.1.0/src/synapto/environment.py +150 -0
- synapto_hub-0.1.0/src/synapto/server/__init__.py +1 -0
- synapto_hub-0.1.0/src/synapto/server/app.py +480 -0
- synapto_hub-0.1.0/src/synapto/server/decide.py +120 -0
- synapto_hub-0.1.0/src/synapto/server/kernels.py +472 -0
- synapto_hub-0.1.0/src/synapto/server/lessons.py +148 -0
- synapto_hub-0.1.0/src/synapto/server/notebook.py +195 -0
- synapto_hub-0.1.0/src/synapto/server/testrunner.py +130 -0
- synapto_hub-0.1.0/src/synapto/store.py +370 -0
- synapto_hub-0.1.0/src/synapto/web/assets/abnfDiagram-VCTEODGH-BzgVtRmZ.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/arc-DFmK96o1.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/architecture-7GRP2DOG-zrp1H6CK.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/architectureDiagram-5GKGNRK7-BuosZEl4.js +36 -0
- synapto_hub-0.1.0/src/synapto/web/assets/array-BifhSqXX.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/blockDiagram-I7D4REHJ-CudPrqYF.js +129 -0
- synapto_hub-0.1.0/src/synapto/web/assets/c4Diagram-7LVT6UL2-Bx9Z0loF.js +38 -0
- synapto_hub-0.1.0/src/synapto/web/assets/channel-BTnE_K1L.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-4HAMMTFA-Dz7u9Mh-.js +62 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-75Z2AOVW-OWQ1EWdD.js +2 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-DU6HZSFF-BZ1HqZRP.js +127 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-F27PBJKO-Ccq5rdp_.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-FOHPRMQF-DzxwRta7.js +161 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-GMAD6QVW-hqv2YP-U.js +72 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-GVQU2GXP-BKNvYVBm.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-IMKFNOWR-Bnq6oZC5.js +231 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-L3NEJ4N5-5DkzRzcD.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-OSK3NFVY-Dgs8_itk.js +10 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-P2QGCYS3-BnDhWDjc.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-POPQ4Y6H-CPRdMj-E.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-PWAF6VOD-_mML4Cuz.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-SHT3W25Y-Bxo-Luh8.js +168 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-SVP7TREG-CjpZezPs.js +88 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-TICWLB2K-B1wqeAp7.js +206 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-XXDRQBXY-D6dcpnCk.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/classDiagram-ZZMXUADV-CwKhe2OP.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/classDiagram-v2-VYDZK3BY-CwKhe2OP.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/cose-bilkent-JH36ORCC-sM2bRXS2.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/cynefin-OW5HDTMX-C4-KIuR1.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/cynefinDiagram-5FMLGOSQ-Dhh1dIM1.js +62 -0
- synapto_hub-0.1.0/src/synapto/web/assets/cytoscape.esm-Yq6u8L66.js +321 -0
- synapto_hub-0.1.0/src/synapto/web/assets/dagre-C-rnJpZF.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/dagre-GXQ25YYZ-C49ZzWYh.js +4 -0
- synapto_hub-0.1.0/src/synapto/web/assets/defaultLocale-BFoDCU3G.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/diagram-S7CK7UJ4-D9nA4BRW.js +30 -0
- synapto_hub-0.1.0/src/synapto/web/assets/diagram-UQ7AKVKN-BJxJAwtj.js +41 -0
- synapto_hub-0.1.0/src/synapto/web/assets/diagram-VSXAHHWV-ClFLSDld.js +3 -0
- synapto_hub-0.1.0/src/synapto/web/assets/diagram-VX7I27RA-DN55aHJQ.js +24 -0
- synapto_hub-0.1.0/src/synapto/web/assets/diagram-Z3DM3KII-Dpm1Nkf_.js +24 -0
- synapto_hub-0.1.0/src/synapto/web/assets/dist-C9N7pTDR.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/ebnfDiagram-PWID7BFC-DYKaLaoe.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/erDiagram-RLTQ6QDP-86iSEqmb.js +99 -0
- synapto_hub-0.1.0/src/synapto/web/assets/eventmodeling-NTZA5JFV-hYD5h-3e.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/flowDiagram-HODETNUW-CHqQ1Ofw.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/ganttDiagram-EL5Y4UJY-BO-2pK_a.js +292 -0
- synapto_hub-0.1.0/src/synapto/web/assets/gitGraph-4MIJSDKK-Dckmqhtr.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/gitGraphDiagram-WWUBYQGX-CjM7tH7V.js +106 -0
- synapto_hub-0.1.0/src/synapto/web/assets/graphlib-DS17s2tU.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/index-B7xe8VDD.js +67 -0
- synapto_hub-0.1.0/src/synapto/web/assets/index-DrdFz88Z.css +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/info-A6RAGUB7-Sp5Hh0xb.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/infoDiagram-27XIBGKW-B5bXC6xW.js +2 -0
- synapto_hub-0.1.0/src/synapto/web/assets/init-C-OQMol4.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/ishikawaDiagram-5VMMS53U-DlLxyIRL.js +70 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/journeyDiagram-3NMN7TZE-Cn7GmHUK.js +139 -0
- synapto_hub-0.1.0/src/synapto/web/assets/kanban-definition-UXKFOSKX-CB63Fceu.js +89 -0
- synapto_hub-0.1.0/src/synapto/web/assets/katex-ZlcWpGUi.js +257 -0
- synapto_hub-0.1.0/src/synapto/web/assets/line-aNxvPf-1.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/linear-CBnI93jZ.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/mermaid-parser.core-N0YHHR1_.js +7 -0
- synapto_hub-0.1.0/src/synapto/web/assets/mermaid.core-DBmdoC-V.js +44 -0
- synapto_hub-0.1.0/src/synapto/web/assets/mindmap-definition-YA3MSWOX-BbJAJ-59.js +96 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-500-normal-CyGtXmN9.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-500-normal-T0SG181k.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-600-normal-CQEPC0hM.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-600-normal-DUglwBrH.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-ext-500-normal-11xBT7e1.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-ext-500-normal-DOzfAZ45.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-ext-600-normal-BtBW-rpm.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-cyrillic-ext-600-normal-wReYPmz2.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-500-normal-DRFEGfly.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-500-normal-Dok2oTci.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-600-normal-CdhFl4lI.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-600-normal-UVxSCcoG.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-ext-500-normal-BKtbrd6n.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-ext-500-normal-DWPqqZgs.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-ext-600-normal-CSDhkhgS.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-latin-ext-600-normal-DSkTqI9L.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-vietnamese-500-normal-DpeZlV_K.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-vietnamese-500-normal-NT-t8RG1.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-vietnamese-600-normal-DKe6qT_E.woff2 +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/montserrat-vietnamese-600-normal-SJ-HTWuM.woff +0 -0
- synapto_hub-0.1.0/src/synapto/web/assets/ordinal-BDEzSJ7C.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/packet-AYTQ26CC-DB9KOyQ4.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/path-fybaL0A-.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/pegDiagram-XKGWAZYB-DXlT0oJF.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/pie-WAS4IAKB-sUrEgbC4.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/pieDiagram-E7YTZNPT-Dt-p3aTR.js +39 -0
- synapto_hub-0.1.0/src/synapto/web/assets/plotly.min-C0VrWA2L.js +3526 -0
- synapto_hub-0.1.0/src/synapto/web/assets/quadrantDiagram-AXDQQJYC-CVhdtPco.js +7 -0
- synapto_hub-0.1.0/src/synapto/web/assets/radar-RG4KPBEZ-DXQf618d.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/railroad-74A4TZTK-D1T4x4-K.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/railroad-abnf-HS5TGJTU-CErj6ZIe.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/railroad-ebnf-LZEXJU2U-DEPob5Ru.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/railroad-peg-WCYAUIDC-CH7u0Yg6.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/railroadDiagram-O6MQD6OU-BDfEX1zC.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/requirementDiagram-BXWQKSXE-0PWnZ_PF.js +84 -0
- synapto_hub-0.1.0/src/synapto/web/assets/rough.esm-Dy-Kn_BL.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/sankeyDiagram-P5KCCOFB-CzmXAlwy.js +40 -0
- synapto_hub-0.1.0/src/synapto/web/assets/sequenceDiagram-WJ2MYXX4-C4kwKBBc.js +162 -0
- synapto_hub-0.1.0/src/synapto/web/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/src-DYcutCTp.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/stateDiagram-D77RDMKH-DbpLbOeP.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/stateDiagram-v2-MP3YSRHH-DNx3ipBZ.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/swimlanes-42K2YHIH-DFi8XeS0.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/swimlanesDiagram-VR7AAH4N-D1QzFjWS.js +8 -0
- synapto_hub-0.1.0/src/synapto/web/assets/timeline-definition-24CTP7MA-CRE5CG6g.js +120 -0
- synapto_hub-0.1.0/src/synapto/web/assets/treeView-Q6P3EWNA-DT2EnW9L.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/treemap-WGGIJYW6-BCPoUUJE.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/vennDiagram-4TSXK5OY-CE-jGbnB.js +34 -0
- synapto_hub-0.1.0/src/synapto/web/assets/wardley-WFR3VGLG-CTplXEkW.js +1 -0
- synapto_hub-0.1.0/src/synapto/web/assets/wardleyDiagram-VM6X3IG4-C_tavznA.js +78 -0
- synapto_hub-0.1.0/src/synapto/web/assets/xychartDiagram-S5SC5T6Z-B4LGptT4.js +7 -0
- synapto_hub-0.1.0/src/synapto/web/index.html +17 -0
- synapto_hub-0.1.0/src/synapto/web/synapto-logo-lockup.png +0 -0
- synapto_hub-0.1.0/src/synapto/web/synapto-mark.png +0 -0
- synapto_hub-0.1.0/tests/conftest.py +69 -0
- synapto_hub-0.1.0/tests/example/bundle/decisions.md +7 -0
- synapto_hub-0.1.0/tests/example/bundle/diagrams/grid.svg +11 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/01-voxel-key/exercise.json +12 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/01-voxel-key/solution.py +13 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/01-voxel-key/stub.py +10 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/01-voxel-key/test_exercise.py +20 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/02-downsample/exercise.json +12 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/02-downsample/solution.py +17 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/02-downsample/stub.py +10 -0
- synapto_hub-0.1.0/tests/example/bundle/exercises/02-downsample/test_exercise.py +20 -0
- synapto_hub-0.1.0/tests/example/bundle/explanation.md +39 -0
- synapto_hub-0.1.0/tests/example/bundle/fixtures/points.xyz +11 -0
- synapto_hub-0.1.0/tests/example/bundle/lesson.json +42 -0
- synapto_hub-0.1.0/tests/example/bundle/notebook.ipynb +157 -0
- synapto_hub-0.1.0/tests/example/bundle/quiz.json +71 -0
- synapto_hub-0.1.0/tests/example/decision/explanation.md +13 -0
- synapto_hub-0.1.0/tests/example/decision/lesson.json +14 -0
- synapto_hub-0.1.0/tests/example/decision/options.json +43 -0
- synapto_hub-0.1.0/tests/example/decision/quiz.json +104 -0
- synapto_hub-0.1.0/tests/example/project/src/gridsnap/__init__.py +1 -0
- synapto_hub-0.1.0/tests/example/project/src/gridsnap/snap.py +45 -0
- synapto_hub-0.1.0/tests/test_bundle.py +351 -0
- synapto_hub-0.1.0/tests/test_decide.py +245 -0
- synapto_hub-0.1.0/tests/test_decisions.py +66 -0
- synapto_hub-0.1.0/tests/test_environment.py +54 -0
- synapto_hub-0.1.0/tests/test_exercises.py +142 -0
- synapto_hub-0.1.0/tests/test_kernels.py +184 -0
- synapto_hub-0.1.0/tests/test_notebook.py +252 -0
- synapto_hub-0.1.0/tests/test_server.py +234 -0
- synapto_hub-0.1.0/tests/test_store.py +107 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rick-scheper
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: synapto-hub
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn what your coding agent just built into an interactive lesson.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rick-scheper/synapto
|
|
6
|
+
Project-URL: Issues, https://github.com/rick-scheper/synapto/issues
|
|
7
|
+
Author: rick-scheper
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: claude-code,coding-agents,jupyter,learning,lessons
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Framework :: Jupyter
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Education
|
|
18
|
+
Classifier: Topic :: Software Development
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: fastapi>=0.115
|
|
21
|
+
Requires-Dist: jupyter-client>=8.6
|
|
22
|
+
Requires-Dist: nbformat>=5.10
|
|
23
|
+
Requires-Dist: pydantic>=2.7
|
|
24
|
+
Requires-Dist: typer>=0.12
|
|
25
|
+
Requires-Dist: uvicorn>=0.30
|
|
26
|
+
Requires-Dist: websockets>=13
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="https://raw.githubusercontent.com/rick-scheper/synapto/main/docs/design/design-system/assets/logos/synapto-logo-lockup.png" alt="Synapto" width="360">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
**Understand the code your coding agent writes.**
|
|
34
|
+
|
|
35
|
+
After Claude Code has built something, run `/debrief`. The agent writes a lesson about exactly what it just built and publishes it to Synapto, a learning hub that runs on your own machine. In the lesson you can:
|
|
36
|
+
|
|
37
|
+
- **Explain:** read a walkthrough of the build, with diagrams.
|
|
38
|
+
- **Decisions:** review the architectural choices the agent made, and the alternatives it rejected.
|
|
39
|
+
- **Notebook:** run and edit the built code, split into functions. It runs in your project's own venv, on fixtures or on your real data.
|
|
40
|
+
- **Quiz:** check that you understood it.
|
|
41
|
+
- **Rebuild:** rewrite the key functions from a stub until the tests pass.
|
|
42
|
+
|
|
43
|
+
<!-- Demo GIF: record docs/demo.gif (see "Recording the demo" below), then uncomment:
|
|
44
|
+
<p align="center"><img src="https://raw.githubusercontent.com/rick-scheper/synapto/main/docs/demo.gif" alt="Running /debrief and opening the lesson" width="800"></p>
|
|
45
|
+
-->
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
You need [uv](https://docs.astral.sh/uv/), Python ≥ 3.11 and [Claude Code](https://claude.com/claude-code).
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
uv tool install synapto-hub
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This installs the `synapto` command. Next, add the Claude Code plugin, which provides the `/debrief` and `/decide` skills. Run these inside Claude Code:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/plugin marketplace add rick-scheper/synapto
|
|
59
|
+
/plugin install synapto@synapto
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Your project's venv needs `ipykernel` and `pytest`. `synapto doctor` checks for them and prints the install command if one is missing. The skill runs this check for you.
|
|
63
|
+
|
|
64
|
+
## Use it
|
|
65
|
+
|
|
66
|
+
1. In your project, let the agent build something.
|
|
67
|
+
2. Type `/debrief`. The agent asks which parts you want: explanation, decisions, notebook, quiz and rebuild exercises. To skip that question, name them: `/debrief only explain,quiz`. To narrow the scope, use `/debrief since a1b2c3d` or `/debrief src/pkg/module.py`.
|
|
68
|
+
3. The agent writes the lesson, checks it with `synapto validate` and publishes it with `synapto publish`. It then gives you the lesson URL.
|
|
69
|
+
4. Start the hub with `synapto serve --open`. It serves on http://127.0.0.1:8765.
|
|
70
|
+
|
|
71
|
+
### Before you build: `/decide`
|
|
72
|
+
|
|
73
|
+
Facing a choice before any code exists, such as which database to use? Type `/decide "which database fits this project?"`, optionally followed by the candidates you have in mind. The agent researches the strongest candidates and publishes a **decision lesson**: an explanation of the problem space, the options compared on criteria that matter for your project, and a quiz.
|
|
74
|
+
|
|
75
|
+
- `/decide guided "…"`: the lesson leads you to the agent's recommendation.
|
|
76
|
+
- `/decide open "…"`: you make the call. Pick an option on the lesson's Options tab and write down why, then run `/decide review <lesson id>`. The agent challenges your reasoning in Claude Code, and the hub then shows its verdict next to the recommendation it wrote down *before* you chose. At the end it offers to record the decision as an ADR in your project.
|
|
77
|
+
|
|
78
|
+
| Command | What it does |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `synapto serve [--open] [--port N] [--reload]` | Start the hub on 127.0.0.1; `--reload` restarts a hub that's already running |
|
|
81
|
+
| `synapto doctor [--python PATH]` | Check that a project interpreter can run lessons |
|
|
82
|
+
| `synapto validate <bundle>` | Check a lesson bundle: it runs the notebook, and checks that the tests pass on the solution and fail on the stub |
|
|
83
|
+
| `synapto publish <bundle> [--force]` | Validate a bundle and add it to your library |
|
|
84
|
+
| `synapto decision show <id>` / `synapto decision verdict <id> <file>` | Read and store the review of an open decision (used by `/decide review`) |
|
|
85
|
+
| `synapto remove <id> [--yes]` | Delete a lesson and your progress in it (or use **Delete lesson** in the hub) |
|
|
86
|
+
|
|
87
|
+
Lessons and your progress live in `~/.synapto` (override with `SYNAPTO_HOME`).
|
|
88
|
+
|
|
89
|
+
## Scope and safety
|
|
90
|
+
|
|
91
|
+
Synapto v1 supports Python projects with Claude Code, for a single local user. Lesson code runs **with your own permissions** in your project's interpreter, with no sandbox. Lessons are generated from your own code. The server binds only to `127.0.0.1` and rejects cross-site and DNS-rebinding requests. See [spec §11](docs/spec.md#11-security-model).
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
uv sync # Python deps + dev tools
|
|
97
|
+
uv run pytest
|
|
98
|
+
claude --plugin-dir ./plugin # run from a project to try the skill from this checkout
|
|
99
|
+
uv tool install --editable . # puts this checkout's `synapto` on PATH
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The UI is a React + Vite app in `web/` ([ADR-0005](docs/adr/0005-frontend-react-vite.md)). Its design reference is in [docs/design/](docs/design/README.md). You only need Node to work on the UI:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
cd web && npm install
|
|
106
|
+
npm run build # writes the app to src/synapto/web/, which `synapto serve` serves and the wheel ships
|
|
107
|
+
npm run dev # hot-reloading UI on :5173; proxies /api to a running `synapto serve`
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
[docs/spec.md](docs/spec.md) is the full specification, and [docs/adr/](docs/adr/README.md) holds the architecture decisions.
|
|
111
|
+
|
|
112
|
+
### Releasing
|
|
113
|
+
|
|
114
|
+
1. Bump `version` in `pyproject.toml`, `plugin/.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`.
|
|
115
|
+
2. Tag and push: `git tag v0.1.0 && git push origin main v0.1.0`.
|
|
116
|
+
|
|
117
|
+
The `release` workflow builds the UI, runs the tests and builds the wheel. It checks that the wheel contains the UI and that the tag matches the version, then publishes `synapto-hub` to PyPI through [trusted publishing](https://docs.pypi.org/trusted-publishers/). Set this up once on PyPI for the repo, the `release.yml` workflow and the `pypi` environment. The plugin goes live when its manifest reaches `main` on GitHub.
|
|
118
|
+
|
|
119
|
+
### Recording the demo
|
|
120
|
+
|
|
121
|
+
`docs/demo.gif` is about 20–30 s at 800 px wide. It shows: `/debrief` finishing in Claude Code with a `Lesson URL:` → the Library → Explain → running a Notebook cell → a passing Rebuild test run.
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/rick-scheper/synapto/main/docs/design/design-system/assets/logos/synapto-logo-lockup.png" alt="Synapto" width="360">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
**Understand the code your coding agent writes.**
|
|
6
|
+
|
|
7
|
+
After Claude Code has built something, run `/debrief`. The agent writes a lesson about exactly what it just built and publishes it to Synapto, a learning hub that runs on your own machine. In the lesson you can:
|
|
8
|
+
|
|
9
|
+
- **Explain:** read a walkthrough of the build, with diagrams.
|
|
10
|
+
- **Decisions:** review the architectural choices the agent made, and the alternatives it rejected.
|
|
11
|
+
- **Notebook:** run and edit the built code, split into functions. It runs in your project's own venv, on fixtures or on your real data.
|
|
12
|
+
- **Quiz:** check that you understood it.
|
|
13
|
+
- **Rebuild:** rewrite the key functions from a stub until the tests pass.
|
|
14
|
+
|
|
15
|
+
<!-- Demo GIF: record docs/demo.gif (see "Recording the demo" below), then uncomment:
|
|
16
|
+
<p align="center"><img src="https://raw.githubusercontent.com/rick-scheper/synapto/main/docs/demo.gif" alt="Running /debrief and opening the lesson" width="800"></p>
|
|
17
|
+
-->
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
You need [uv](https://docs.astral.sh/uv/), Python ≥ 3.11 and [Claude Code](https://claude.com/claude-code).
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
uv tool install synapto-hub
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This installs the `synapto` command. Next, add the Claude Code plugin, which provides the `/debrief` and `/decide` skills. Run these inside Claude Code:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
/plugin marketplace add rick-scheper/synapto
|
|
31
|
+
/plugin install synapto@synapto
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Your project's venv needs `ipykernel` and `pytest`. `synapto doctor` checks for them and prints the install command if one is missing. The skill runs this check for you.
|
|
35
|
+
|
|
36
|
+
## Use it
|
|
37
|
+
|
|
38
|
+
1. In your project, let the agent build something.
|
|
39
|
+
2. Type `/debrief`. The agent asks which parts you want: explanation, decisions, notebook, quiz and rebuild exercises. To skip that question, name them: `/debrief only explain,quiz`. To narrow the scope, use `/debrief since a1b2c3d` or `/debrief src/pkg/module.py`.
|
|
40
|
+
3. The agent writes the lesson, checks it with `synapto validate` and publishes it with `synapto publish`. It then gives you the lesson URL.
|
|
41
|
+
4. Start the hub with `synapto serve --open`. It serves on http://127.0.0.1:8765.
|
|
42
|
+
|
|
43
|
+
### Before you build: `/decide`
|
|
44
|
+
|
|
45
|
+
Facing a choice before any code exists, such as which database to use? Type `/decide "which database fits this project?"`, optionally followed by the candidates you have in mind. The agent researches the strongest candidates and publishes a **decision lesson**: an explanation of the problem space, the options compared on criteria that matter for your project, and a quiz.
|
|
46
|
+
|
|
47
|
+
- `/decide guided "…"`: the lesson leads you to the agent's recommendation.
|
|
48
|
+
- `/decide open "…"`: you make the call. Pick an option on the lesson's Options tab and write down why, then run `/decide review <lesson id>`. The agent challenges your reasoning in Claude Code, and the hub then shows its verdict next to the recommendation it wrote down *before* you chose. At the end it offers to record the decision as an ADR in your project.
|
|
49
|
+
|
|
50
|
+
| Command | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `synapto serve [--open] [--port N] [--reload]` | Start the hub on 127.0.0.1; `--reload` restarts a hub that's already running |
|
|
53
|
+
| `synapto doctor [--python PATH]` | Check that a project interpreter can run lessons |
|
|
54
|
+
| `synapto validate <bundle>` | Check a lesson bundle: it runs the notebook, and checks that the tests pass on the solution and fail on the stub |
|
|
55
|
+
| `synapto publish <bundle> [--force]` | Validate a bundle and add it to your library |
|
|
56
|
+
| `synapto decision show <id>` / `synapto decision verdict <id> <file>` | Read and store the review of an open decision (used by `/decide review`) |
|
|
57
|
+
| `synapto remove <id> [--yes]` | Delete a lesson and your progress in it (or use **Delete lesson** in the hub) |
|
|
58
|
+
|
|
59
|
+
Lessons and your progress live in `~/.synapto` (override with `SYNAPTO_HOME`).
|
|
60
|
+
|
|
61
|
+
## Scope and safety
|
|
62
|
+
|
|
63
|
+
Synapto v1 supports Python projects with Claude Code, for a single local user. Lesson code runs **with your own permissions** in your project's interpreter, with no sandbox. Lessons are generated from your own code. The server binds only to `127.0.0.1` and rejects cross-site and DNS-rebinding requests. See [spec §11](docs/spec.md#11-security-model).
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
uv sync # Python deps + dev tools
|
|
69
|
+
uv run pytest
|
|
70
|
+
claude --plugin-dir ./plugin # run from a project to try the skill from this checkout
|
|
71
|
+
uv tool install --editable . # puts this checkout's `synapto` on PATH
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The UI is a React + Vite app in `web/` ([ADR-0005](docs/adr/0005-frontend-react-vite.md)). Its design reference is in [docs/design/](docs/design/README.md). You only need Node to work on the UI:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
cd web && npm install
|
|
78
|
+
npm run build # writes the app to src/synapto/web/, which `synapto serve` serves and the wheel ships
|
|
79
|
+
npm run dev # hot-reloading UI on :5173; proxies /api to a running `synapto serve`
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
[docs/spec.md](docs/spec.md) is the full specification, and [docs/adr/](docs/adr/README.md) holds the architecture decisions.
|
|
83
|
+
|
|
84
|
+
### Releasing
|
|
85
|
+
|
|
86
|
+
1. Bump `version` in `pyproject.toml`, `plugin/.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`.
|
|
87
|
+
2. Tag and push: `git tag v0.1.0 && git push origin main v0.1.0`.
|
|
88
|
+
|
|
89
|
+
The `release` workflow builds the UI, runs the tests and builds the wheel. It checks that the wheel contains the UI and that the tag matches the version, then publishes `synapto-hub` to PyPI through [trusted publishing](https://docs.pypi.org/trusted-publishers/). Set this up once on PyPI for the repo, the `release.yml` workflow and the `pypi` environment. The plugin goes live when its manifest reaches `main` on GitHub.
|
|
90
|
+
|
|
91
|
+
### Recording the demo
|
|
92
|
+
|
|
93
|
+
`docs/demo.gif` is about 20–30 s at 800 px wide. It shows: `/debrief` finishing in Claude Code with a `Lesson URL:` → the Library → Explain → running a Notebook cell → a passing Rebuild test run.
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "synapto-hub"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Turn what your coding agent just built into an interactive lesson."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [{ name = "rick-scheper" }]
|
|
9
|
+
keywords = ["claude-code", "coding-agents", "learning", "jupyter", "lessons"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Environment :: Web Environment",
|
|
13
|
+
"Framework :: FastAPI",
|
|
14
|
+
"Framework :: Jupyter",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Topic :: Education",
|
|
18
|
+
"Topic :: Software Development",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"fastapi>=0.115",
|
|
22
|
+
"jupyter_client>=8.6",
|
|
23
|
+
"nbformat>=5.10",
|
|
24
|
+
"pydantic>=2.7",
|
|
25
|
+
"typer>=0.12",
|
|
26
|
+
"uvicorn>=0.30",
|
|
27
|
+
# uvicorn needs it to serve the kernel WebSocket (spec §9.1).
|
|
28
|
+
"websockets>=13",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/rick-scheper/synapto"
|
|
33
|
+
Issues = "https://github.com/rick-scheper/synapto/issues"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
synapto = "synapto.cli:app"
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=8",
|
|
41
|
+
"pytest-asyncio>=0.24",
|
|
42
|
+
# The test suite uses the dev venv as the "project venv", so it needs
|
|
43
|
+
# what synapto doctor requires of a project interpreter.
|
|
44
|
+
"ipykernel>=6.29",
|
|
45
|
+
"httpx>=0.27",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[build-system]
|
|
49
|
+
requires = ["hatchling"]
|
|
50
|
+
build-backend = "hatchling.build"
|
|
51
|
+
|
|
52
|
+
[tool.hatch.build.targets.sdist]
|
|
53
|
+
include = ["/src/synapto", "/tests", "/README.md", "/LICENSE"]
|
|
54
|
+
artifacts = ["/src/synapto/web/**"]
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/synapto"]
|
|
58
|
+
# The built web UI is gitignored but ships in the wheel (ADR-0005).
|
|
59
|
+
artifacts = ["/src/synapto/web/**"]
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
testpaths = ["tests"]
|
|
63
|
+
asyncio_mode = "auto"
|
|
64
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
65
|
+
markers = ["slow: creates a separate venv"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Synapto: interactive lessons from what your coding agent just built."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""The lesson bundle: the contract between the /debrief skill and the hub (spec §5)."""
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Parse ``decisions.md`` (spec §5.3) into one record per decision.
|
|
2
|
+
|
|
3
|
+
The template is a ``## <title>`` section per decision with ``**Context:**``,
|
|
4
|
+
``**Options:**``, ``**Chosen:**``, ``**Why:**``, ``**Trade-offs:**`` and
|
|
5
|
+
``**ADR:**`` fields. The validator doesn't enforce it, so parsing is lenient:
|
|
6
|
+
anything it can't place stays available as the section's raw Markdown, and a
|
|
7
|
+
file without sections (the "no decisions were made" case) becomes a note.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel
|
|
15
|
+
|
|
16
|
+
_SECTION = re.compile(r"^##[ \t]+(.+?)[ \t]*#*[ \t]*$", re.MULTILINE)
|
|
17
|
+
_FIELD = re.compile(r"^\*\*(Context|Options|Chosen|Why|Trade-offs|ADR):?\*\*:?[ \t]*", re.MULTILINE | re.IGNORECASE)
|
|
18
|
+
# "A — text", "(C — text)"; the dash may be an em dash, en dash or hyphen.
|
|
19
|
+
_OPTION = re.compile(r"^\(?\s*([A-Za-z0-9]{1,3})\s*[—–-]\s*(.+?)\s*\)?\.?$", re.DOTALL)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DecisionOption(BaseModel):
|
|
23
|
+
id: str
|
|
24
|
+
label: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Decision(BaseModel):
|
|
28
|
+
title: str
|
|
29
|
+
context: str | None = None
|
|
30
|
+
options: list[DecisionOption] = []
|
|
31
|
+
chosen: str | None = None
|
|
32
|
+
why: str | None = None
|
|
33
|
+
tradeoffs: str | None = None
|
|
34
|
+
adr: str | None = None
|
|
35
|
+
body: str
|
|
36
|
+
"""The section's Markdown without its heading, for when the fields don't parse."""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Decisions(BaseModel):
|
|
40
|
+
decisions: list[Decision]
|
|
41
|
+
note: str | None = None
|
|
42
|
+
"""Text before the first section, e.g. "No architectural decisions were made."."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def parse_decisions(text: str) -> Decisions:
|
|
46
|
+
sections = list(_SECTION.finditer(text))
|
|
47
|
+
intro = text[: sections[0].start()] if sections else text
|
|
48
|
+
intro = re.sub(r"^#[ \t].*$", "", intro, flags=re.MULTILINE).strip() # drop a "# Decisions" title
|
|
49
|
+
decisions = []
|
|
50
|
+
for i, match in enumerate(sections):
|
|
51
|
+
end = sections[i + 1].start() if i + 1 < len(sections) else len(text)
|
|
52
|
+
decisions.append(_parse_section(match[1], text[match.end():end].strip()))
|
|
53
|
+
return Decisions(decisions=decisions, note=intro or None)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _parse_section(title: str, body: str) -> Decision:
|
|
57
|
+
fields: dict[str, str] = {}
|
|
58
|
+
marks = list(_FIELD.finditer(body))
|
|
59
|
+
for i, mark in enumerate(marks):
|
|
60
|
+
end = marks[i + 1].start() if i + 1 < len(marks) else len(body)
|
|
61
|
+
fields[mark[1].lower()] = " ".join(body[mark.end():end].split())
|
|
62
|
+
|
|
63
|
+
options = _parse_options(fields.get("options", ""))
|
|
64
|
+
chosen = fields.get("chosen")
|
|
65
|
+
if chosen and options:
|
|
66
|
+
# "B", "B — dict accumulation", "Option B"
|
|
67
|
+
ids = {o.id.lower(): o.id for o in options}
|
|
68
|
+
head = re.match(r"^(?:option\s+)?([A-Za-z0-9]{1,3})\b", chosen, re.IGNORECASE)
|
|
69
|
+
chosen = ids.get(head[1].lower()) if head else None
|
|
70
|
+
elif not options:
|
|
71
|
+
chosen = None
|
|
72
|
+
|
|
73
|
+
return Decision(
|
|
74
|
+
title=title, context=fields.get("context"), options=options, chosen=chosen,
|
|
75
|
+
why=fields.get("why"), tradeoffs=fields.get("trade-offs"), adr=fields.get("adr"), body=body,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _parse_options(text: str) -> list[DecisionOption]:
|
|
80
|
+
options = []
|
|
81
|
+
for part in (p.strip() for p in text.split(";")):
|
|
82
|
+
match = _OPTION.match(part)
|
|
83
|
+
if match is None:
|
|
84
|
+
return [] # one unrecognised part means the list isn't in the template's shape
|
|
85
|
+
options.append(DecisionOption(id=match[1], label=match[2]))
|
|
86
|
+
return options
|