nextclaw 0.30.0 → 0.32.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/dist/cli/app/index.js +1 -1
- package/dist/cli/launcher/index.js +1 -1
- package/dist/{nextclaw-distribution.utils-D6Rz73fp.js → nextclaw-distribution.utils-CfUuTwjt.js} +3 -2
- package/dist/{nextclaw-distribution.utils-D6Rz73fp.js.map → nextclaw-distribution.utils-CfUuTwjt.js.map} +1 -1
- package/package.json +16 -16
- package/resources/USAGE.md +4 -4
- package/resources/apps/nextclaw-personal-organizer/README.md +24 -0
- package/resources/apps/nextclaw-personal-organizer/assets/icon.svg +13 -0
- package/resources/apps/nextclaw-personal-organizer/manifest.json +44 -0
- package/resources/apps/nextclaw-personal-organizer/marketplace.json +18 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-calendar.panel/index.html +24 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-calendar.panel/panel-app.json +21 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-favorites.panel/index.html +23 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-favorites.panel/panel-app.json +18 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-notes.panel/index.html +28 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-notes.panel/panel-app.json +18 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-todos.panel/index.html +43 -0
- package/resources/apps/nextclaw-personal-organizer/panels/nextclaw-personal-organizer-todos.panel/panel-app.json +18 -0
- package/resources/apps/nextclaw-personal-organizer/service-components/nextclaw-personal-organizer-data/calendar-subscription.service.mjs +152 -0
- package/resources/apps/nextclaw-personal-organizer/service-components/nextclaw-personal-organizer-data/index.mjs +341 -0
- package/resources/apps/nextclaw-personal-organizer/service-components/nextclaw-personal-organizer-data/service-app.json +35 -0
- package/ui-dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-BcFJp_1X.js} +1 -1
- package/ui-dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-Dp2ezlQn.js} +1 -1
- package/ui-dist/assets/{api-BxPNDp30.js → api-CK3Fro7z.js} +6 -6
- package/ui-dist/assets/appearance-settings-page-zqwWO8Dy.js +1 -0
- package/ui-dist/assets/{arc-BvhODBXv.js → arc-CkgyPMyW.js} +1 -1
- package/ui-dist/assets/architecture-TIHT7OUA-DO2x53FK.js +1 -0
- package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-CMd4cIjI.js} +1 -1
- package/ui-dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-Bz3tbhet.js} +1 -1
- package/ui-dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-D9hFNAGv.js} +1 -1
- package/ui-dist/assets/channel-nBvMaVyP.js +1 -0
- package/ui-dist/assets/{channels-list-page-DRaNWAxC.js → channels-list-page-CVCZBlCL.js} +2 -2
- package/ui-dist/assets/chat-page-D4wehRTz.js +1 -0
- package/ui-dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +1 -0
- package/ui-dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-7NrjEITq.js} +1 -1
- package/ui-dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-viIcqj9q.js} +1 -1
- package/ui-dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-Vsu4J-VM.js} +1 -1
- package/ui-dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-C-w6CQZK.js} +1 -1
- package/ui-dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-CuKgJQ4W.js} +1 -1
- package/ui-dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CYeiWZKb.js} +1 -1
- package/ui-dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-DRCbfwIn.js} +1 -1
- package/ui-dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-BvydOcm3.js} +1 -1
- package/ui-dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-RlppOXKo.js} +1 -1
- package/ui-dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-DAizzYwr.js} +1 -1
- package/ui-dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-5eChJHca.js} +1 -1
- package/ui-dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-YHPr53fv.js} +1 -1
- package/ui-dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CK4D7Hz5.js} +1 -1
- package/ui-dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-BmlDFIRW.js} +1 -1
- package/ui-dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-D0ksHZZ9.js} +2 -2
- package/ui-dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-DPkq8FCm.js} +1 -1
- package/ui-dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-FAatv5fC.js} +1 -1
- package/ui-dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DLkIi4F7.js} +1 -1
- package/ui-dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DawOjNE3.js} +1 -1
- package/ui-dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-Di52TorW.js} +1 -1
- package/ui-dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-PfyK9w1-.js} +1 -1
- package/ui-dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-C3jdH3Ty.js} +1 -1
- package/ui-dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-CecHo-f0.js} +1 -1
- package/ui-dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-f3IJh3sN.js} +1 -1
- package/ui-dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DQFeUPxZ.js} +1 -1
- package/ui-dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-BhUeG0y2.js} +1 -1
- package/ui-dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-C3XpZ-2u.js} +1 -1
- package/ui-dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-CAqa5klQ.js} +1 -1
- package/ui-dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-D_WXezeD.js} +1 -1
- package/ui-dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-CZ70oOtp.js} +1 -1
- package/ui-dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +1 -0
- package/ui-dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-B7AHEYYk.js} +1 -1
- package/ui-dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-Dn9To_OI.js} +2 -2
- package/ui-dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +1 -0
- package/ui-dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BYEgRBk3.js} +1 -1
- package/ui-dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-C6YtZDU0.js} +1 -1
- package/ui-dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-DMuYtnHF.js} +1 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +1 -0
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +1 -0
- package/ui-dist/assets/config-split-page-CceNFvlY.js +1 -0
- package/ui-dist/assets/confirm-dialog-CWeNYWZY.js +5 -0
- package/ui-dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-Bc2Ex5Y3.js} +1 -1
- package/ui-dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +1 -0
- package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-DVysQoGz.js} +1 -1
- package/ui-dist/assets/{dagre-CMe101gk.js → dagre-CMhQ1cAG.js} +1 -1
- package/ui-dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-RYyWpPJZ.js} +1 -1
- package/ui-dist/assets/desktop-update-config-Dirc3bpt.js +1 -0
- package/ui-dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-BD6KONdF.js} +1 -1
- package/ui-dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-CGB2ptRR.js} +1 -1
- package/ui-dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-DnkOI6cU.js} +1 -1
- package/ui-dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-DF82RZ7P.js} +1 -1
- package/ui-dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-Be2v7Ck9.js} +1 -1
- package/ui-dist/assets/{dist-B4Pf5X3Q.js → dist-AYxkFx2B.js} +1 -1
- package/ui-dist/assets/{dist-DHEWkGWX.js → dist-D9xtGgdL.js} +1 -1
- package/ui-dist/assets/doc-browser-4Sud6dWw.js +1 -0
- package/ui-dist/assets/doc-browser-D4x_yH5F.js +1 -0
- package/ui-dist/assets/doc-browser-context-Cb7Z0j90.js +1 -0
- package/ui-dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-BqwAjrj3.js} +1 -1
- package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-CP98OYk8.js} +1 -1
- package/ui-dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-ZLlx8xfs.js} +1 -1
- package/ui-dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +1 -0
- package/ui-dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +1 -0
- package/ui-dist/assets/form-actions-B2q4jgjE.js +1 -0
- package/ui-dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-DXCDjHR2.js} +1 -1
- package/ui-dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +1 -0
- package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-l2HWrTJp.js} +1 -1
- package/ui-dist/assets/index-CdyTsSBu.css +1 -0
- package/ui-dist/assets/index-Das_bw2h.js +107 -0
- package/ui-dist/assets/info-DKCQHKI2-BIporNWb.js +1 -0
- package/ui-dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-D-DjX-bn.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-y_Xy128F.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-DJn5xYcQ.js} +1 -1
- package/ui-dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-DJVIOR21.js} +1 -1
- package/ui-dist/assets/{line-CbyFs065.js → line-Cos7PIOj.js} +1 -1
- package/ui-dist/assets/{linear-4DKtnZBS.js → linear-BtDLqtzF.js} +1 -1
- package/ui-dist/assets/loader-circle-CpmBdaon.js +1 -0
- package/ui-dist/assets/{map-CcZzEoz6.js → map-BKnQyvd0.js} +1 -1
- package/ui-dist/assets/mcp-marketplace-page-CdOY3Sop.js +1 -0
- package/ui-dist/assets/mcp-marketplace-page-DvjrfqEt.js +9 -0
- package/ui-dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-XUNZhr2W.js} +2 -2
- package/ui-dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-ySrvolIe.js} +3 -3
- package/ui-dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-BypL9tei.js} +1 -1
- package/ui-dist/assets/model-config-page-DfOLyQqR.js +1 -0
- package/ui-dist/assets/{navigation-link-CAFOcXNg.js → navigation-link-MiiyoIjH.js} +2 -2
- package/ui-dist/assets/{ordinal-BgLYtOZE.js → ordinal-CxxVWxYU.js} +1 -1
- package/ui-dist/assets/packet-7NZHBO7P-CuFMADV0.js +1 -0
- package/ui-dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-D-U2KBGv.js} +1 -1
- package/ui-dist/assets/pie-RZYD4A2V-XUeIXhM9.js +1 -0
- package/ui-dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-CBi3GusJ.js} +1 -1
- package/ui-dist/assets/plus-C8FkjpSZ.js +1 -0
- package/ui-dist/assets/provider-scoped-model-input-DXzjr5l0.js +1 -0
- package/ui-dist/assets/providers-config-page-CaO8WfZH.js +1 -0
- package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js} +1 -1
- package/ui-dist/assets/radar-I7S5WNFK-D-NNGh1k.js +1 -0
- package/ui-dist/assets/railroad-3IZDKUUU-C67_uDaM.js +1 -0
- package/ui-dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +1 -0
- package/ui-dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +1 -0
- package/ui-dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +1 -0
- package/ui-dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-D7Y2EqSd.js} +1 -1
- package/ui-dist/assets/react-C8XFFvuz.js +8 -0
- package/ui-dist/assets/{refresh-cw-CWDp_JnN.js → refresh-cw-a2VVeeAF.js} +1 -1
- package/ui-dist/assets/remote-BJHXa4mB.js +1 -0
- package/ui-dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
- package/ui-dist/assets/rotate-cw-DJ7UF3F2.js +1 -0
- package/ui-dist/assets/runtime-config-page-BuA4A02z.js +1 -0
- package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
- package/ui-dist/assets/{save-Cnr71JON.js → save-CGm23Yww.js} +1 -1
- package/ui-dist/assets/{search-CCX11X2m.js → search-CH2t--sH.js} +1 -1
- package/ui-dist/assets/search-config-page-BAmYqoAz.js +1 -0
- package/ui-dist/assets/secrets-config-page-BlPOuql_.js +3 -0
- package/ui-dist/assets/security-config-CbDiY2xr.js +1 -0
- package/ui-dist/assets/{select-DvwBu99K.js → select-DnxxDpcV.js} +2 -2
- package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
- package/ui-dist/assets/{settings-2-Dmv6zMne.js → settings-2-agnMYc8a.js} +1 -1
- package/ui-dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
- package/ui-dist/assets/skeleton-XpqeWL62.js +1 -0
- package/ui-dist/assets/{src-vgz8E_-O.js → src-Bw-mzbQb.js} +1 -1
- package/ui-dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-BJ-mFeOz.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +1 -0
- package/ui-dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-BsucVOO2.js} +2 -2
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +8 -0
- package/ui-dist/assets/{tag-chip-gMPvx7n_.js → tag-chip-CPOc8b2N.js} +1 -1
- package/ui-dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-Bicewlzo.js} +1 -1
- package/ui-dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +1 -0
- package/ui-dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +1 -0
- package/ui-dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-BxOOnO9x.js} +1 -1
- package/ui-dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +1 -0
- package/ui-dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-Cl7NltMv.js} +1 -1
- package/ui-dist/assets/x-odTHAtLZ.js +1 -0
- package/ui-dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-DiMIxQ7N.js} +1 -1
- package/ui-dist/index.html +21 -22
- package/ui-dist/assets/appearance-settings-page-DpVJjvkB.js +0 -1
- package/ui-dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
- package/ui-dist/assets/channel-5T3pdR-s.js +0 -1
- package/ui-dist/assets/chat-page-BuFDmG5_.js +0 -1
- package/ui-dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
- package/ui-dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
- package/ui-dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
- package/ui-dist/assets/config-split-page-BVWVDbvG.js +0 -1
- package/ui-dist/assets/confirm-dialog-mA2iVzxh.js +0 -5
- package/ui-dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
- package/ui-dist/assets/desktop-update-config-DyQb1LXr.js +0 -1
- package/ui-dist/assets/doc-browser-CtO_HtRy.js +0 -1
- package/ui-dist/assets/doc-browser-context-CuGI6PQc.js +0 -1
- package/ui-dist/assets/doc-browser-eMUagyBV.js +0 -1
- package/ui-dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
- package/ui-dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
- package/ui-dist/assets/form-actions-BOfIyG3O.js +0 -1
- package/ui-dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
- package/ui-dist/assets/index-BjBdWHV1.js +0 -107
- package/ui-dist/assets/index-DmpmjAGQ.css +0 -1
- package/ui-dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
- package/ui-dist/assets/loader-circle-Df8wF2Pr.js +0 -1
- package/ui-dist/assets/mcp-marketplace-page-DI49IKxp.js +0 -1
- package/ui-dist/assets/mcp-marketplace-page-ofDqbOIF.js +0 -9
- package/ui-dist/assets/model-config-page-D73Tu3jW.js +0 -1
- package/ui-dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
- package/ui-dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
- package/ui-dist/assets/plus-DVU5RLCS.js +0 -1
- package/ui-dist/assets/provider-scoped-model-input-BaJJJYMX.js +0 -1
- package/ui-dist/assets/providers-config-page-BL6IRVBm.js +0 -1
- package/ui-dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
- package/ui-dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
- package/ui-dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
- package/ui-dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
- package/ui-dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
- package/ui-dist/assets/react-BC_orpAj.js +0 -8
- package/ui-dist/assets/remote-T24O58lH.js +0 -1
- package/ui-dist/assets/rotate-cw-BqhwSV5p.js +0 -1
- package/ui-dist/assets/runtime-config-page-CXUx017t.js +0 -1
- package/ui-dist/assets/search-config-page-BB6d5gT7.js +0 -1
- package/ui-dist/assets/secrets-config-page-DYsDeT9K.js +0 -3
- package/ui-dist/assets/security-config-CVPgqL7G.js +0 -1
- package/ui-dist/assets/skeleton-C5tWata3.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
- package/ui-dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
- package/ui-dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
- package/ui-dist/assets/use-confirm-dialog-D_3-QpZU.js +0 -1
- package/ui-dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
- package/ui-dist/assets/x-BEWSqeux.js +0 -1
- /package/ui-dist/assets/{array-NADKd9aU.js → array-BQVzeGRt.js} +0 -0
- /package/ui-dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
- /package/ui-dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
- /package/ui-dist/assets/{config-hints-BcfVUMij.js → config-hints-nV5HPOvq.js} +0 -0
- /package/ui-dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-0uDtdD0l.js} +0 -0
- /package/ui-dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-DSWXGgt0.js} +0 -0
- /package/ui-dist/assets/{dist-DAPEIJbz.js → dist--ta5rX12.js} +0 -0
- /package/ui-dist/assets/{graphlib-ChqXg0dI.js → graphlib-CQ6QV4yP.js} +0 -0
- /package/ui-dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-Tk038i04.js} +0 -0
- /package/ui-dist/assets/{init-D8wZg9xq.js → init-Y6h9jGtZ.js} +0 -0
- /package/ui-dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-8hyJpgpx.js} +0 -0
- /package/ui-dist/assets/{katex-TZJFa0J_.js → katex-ARhY9PS1.js} +0 -0
- /package/ui-dist/assets/{middleware-B3k-TSmZ.js → middleware-DXsbf9xI.js} +0 -0
- /package/ui-dist/assets/{path-DodfxcX7.js → path-10BjdyLh.js} +0 -0
- /package/ui-dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DxgC_14r.js} +0 -0
- /package/ui-dist/assets/{xlsx-CxByi7bR.js → xlsx-DrDuDNAa.js} +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { lookup } from "node:dns/promises";
|
|
3
|
+
import { isIP } from "node:net";
|
|
4
|
+
|
|
5
|
+
const MAX_ICS_BYTES = 5 * 1024 * 1024;
|
|
6
|
+
|
|
7
|
+
export class CalendarSubscriptionService {
|
|
8
|
+
constructor({ normalizeHttpUrl, now, toIso }) {
|
|
9
|
+
this.normalizeHttpUrl = normalizeHttpUrl;
|
|
10
|
+
this.now = now;
|
|
11
|
+
this.toIso = toIso;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
sync = async (state, subscription) => {
|
|
15
|
+
try {
|
|
16
|
+
const content = await this.fetchCalendarText(subscription.url);
|
|
17
|
+
const events = this.parseIcs(content, subscription);
|
|
18
|
+
state.items = state.items.filter((item) => item.subscriptionId !== subscription.id);
|
|
19
|
+
state.items.push(...events);
|
|
20
|
+
subscription.lastSyncedAt = this.now();
|
|
21
|
+
subscription.lastError = "";
|
|
22
|
+
} catch (error) {
|
|
23
|
+
subscription.lastError = error instanceof Error ? error.message : String(error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
fetchCalendarText = async (url) => {
|
|
29
|
+
let currentUrl = await this.requirePublicHttpUrl(url);
|
|
30
|
+
for (let redirectCount = 0; redirectCount <= 3; redirectCount += 1) {
|
|
31
|
+
const response = await fetch(currentUrl, {
|
|
32
|
+
redirect: "manual",
|
|
33
|
+
signal: globalThis.AbortSignal.timeout(12_000),
|
|
34
|
+
});
|
|
35
|
+
if (response.status >= 300 && response.status < 400) {
|
|
36
|
+
const location = response.headers.get("location");
|
|
37
|
+
if (!location || redirectCount === 3) {
|
|
38
|
+
throw new Error("calendar redirected too many times");
|
|
39
|
+
}
|
|
40
|
+
currentUrl = await this.requirePublicHttpUrl(
|
|
41
|
+
new URL(location, currentUrl).toString(),
|
|
42
|
+
);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`calendar returned HTTP ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
49
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_ICS_BYTES) {
|
|
50
|
+
throw new Error(`calendar exceeds ${MAX_ICS_BYTES} bytes`);
|
|
51
|
+
}
|
|
52
|
+
const content = await response.text();
|
|
53
|
+
if (Buffer.byteLength(content, "utf8") > MAX_ICS_BYTES) {
|
|
54
|
+
throw new Error(`calendar exceeds ${MAX_ICS_BYTES} bytes`);
|
|
55
|
+
}
|
|
56
|
+
return content;
|
|
57
|
+
}
|
|
58
|
+
throw new Error("calendar redirect resolution failed");
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
requirePublicHttpUrl = async (value) => {
|
|
62
|
+
const url = new URL(this.normalizeHttpUrl(value));
|
|
63
|
+
if (url.username || url.password) {
|
|
64
|
+
throw new Error("calendar url cannot include credentials");
|
|
65
|
+
}
|
|
66
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
67
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost")) {
|
|
68
|
+
throw new Error("calendar url must use a public host");
|
|
69
|
+
}
|
|
70
|
+
const addresses = isIP(hostname)
|
|
71
|
+
? [{ address: hostname }]
|
|
72
|
+
: await lookup(hostname, { all: true, verbatim: true });
|
|
73
|
+
if (addresses.length === 0 || addresses.some(({ address }) => !isPublicIpAddress(address))) {
|
|
74
|
+
throw new Error("calendar url must resolve to a public host");
|
|
75
|
+
}
|
|
76
|
+
return url.toString();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
parseIcs = (raw, subscription) => {
|
|
80
|
+
const lines = raw.replace(/\r\n[ \t]/g, "").split(/\r?\n/);
|
|
81
|
+
const events = [];
|
|
82
|
+
let current = null;
|
|
83
|
+
for (const line of lines) {
|
|
84
|
+
if (line === "BEGIN:VEVENT") {
|
|
85
|
+
current = {};
|
|
86
|
+
} else if (line === "END:VEVENT" && current) {
|
|
87
|
+
if (current.DTSTART && current.SUMMARY) {
|
|
88
|
+
const start = this.parseIcsDate(current.DTSTART);
|
|
89
|
+
events.push({
|
|
90
|
+
id: `ics:${subscription.id}:${current.UID || randomUUID()}`,
|
|
91
|
+
title: current.SUMMARY,
|
|
92
|
+
start,
|
|
93
|
+
end: this.parseIcsDate(current.DTEND || current.DTSTART),
|
|
94
|
+
allDay: /^\d{8}$/.test(current.DTSTART),
|
|
95
|
+
location: current.LOCATION || "",
|
|
96
|
+
notes: current.DESCRIPTION || "",
|
|
97
|
+
source: "ics",
|
|
98
|
+
subscriptionId: subscription.id,
|
|
99
|
+
subscriptionName: subscription.name,
|
|
100
|
+
createdAt: this.now(),
|
|
101
|
+
updatedAt: this.now(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
current = null;
|
|
105
|
+
} else if (current) {
|
|
106
|
+
const separator = line.indexOf(":");
|
|
107
|
+
if (separator > 0) {
|
|
108
|
+
current[line.slice(0, separator).split(";")[0]] = line
|
|
109
|
+
.slice(separator + 1)
|
|
110
|
+
.replace(/\\n/g, "\n")
|
|
111
|
+
.replace(/\\,/g, ",");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return events;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
parseIcsDate = (value) => {
|
|
119
|
+
if (/^\d{8}$/.test(value)) {
|
|
120
|
+
return new Date(
|
|
121
|
+
`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00Z`,
|
|
122
|
+
).toISOString();
|
|
123
|
+
}
|
|
124
|
+
const match = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z?$/.exec(value);
|
|
125
|
+
if (!match) {
|
|
126
|
+
return this.toIso(value, "ICS date");
|
|
127
|
+
}
|
|
128
|
+
const timezone = value.endsWith("Z") ? "Z" : "";
|
|
129
|
+
return new Date(
|
|
130
|
+
`${match[1]}-${match[2]}-${match[3]}T${match[4]}:${match[5]}:${match[6]}${timezone}`,
|
|
131
|
+
).toISOString();
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isPublicIpAddress(address) {
|
|
136
|
+
if (isIP(address) === 4) {
|
|
137
|
+
const [first, second] = address.split(".").map(Number);
|
|
138
|
+
return !(first === 0 || first === 10 || first === 127 || first >= 224 ||
|
|
139
|
+
(first === 100 && second >= 64 && second <= 127) ||
|
|
140
|
+
(first === 169 && second === 254) ||
|
|
141
|
+
(first === 172 && second >= 16 && second <= 31) ||
|
|
142
|
+
(first === 192 && second === 168) ||
|
|
143
|
+
(first === 198 && (second === 18 || second === 19)));
|
|
144
|
+
}
|
|
145
|
+
const normalized = address.toLowerCase();
|
|
146
|
+
return isIP(address) === 6 &&
|
|
147
|
+
normalized !== "::" && normalized !== "::1" &&
|
|
148
|
+
!normalized.startsWith("fc") && !normalized.startsWith("fd") &&
|
|
149
|
+
!normalized.startsWith("fe8") && !normalized.startsWith("fe9") &&
|
|
150
|
+
!normalized.startsWith("fea") && !normalized.startsWith("feb") &&
|
|
151
|
+
!normalized.startsWith("::ffff:");
|
|
152
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { CalendarSubscriptionService } from "./calendar-subscription.service.mjs";
|
|
7
|
+
|
|
8
|
+
const dataDirectory = process.env.NEXTCLAW_APP_DATA_DIR?.trim();
|
|
9
|
+
const MAX_NOTE_BYTES = 2 * 1024 * 1024;
|
|
10
|
+
if (!dataDirectory) {
|
|
11
|
+
throw new Error("NEXTCLAW_APP_DATA_DIR is required.");
|
|
12
|
+
}
|
|
13
|
+
await mkdir(dataDirectory, { recursive: true });
|
|
14
|
+
|
|
15
|
+
const files = {
|
|
16
|
+
todos: path.join(dataDirectory, "todos.json"),
|
|
17
|
+
favorites: path.join(dataDirectory, "favorites.json"),
|
|
18
|
+
calendar: path.join(dataDirectory, "calendar.json"),
|
|
19
|
+
notesIndex: path.join(dataDirectory, "notes-index.json"),
|
|
20
|
+
notesDirectory: path.join(dataDirectory, "notes"),
|
|
21
|
+
};
|
|
22
|
+
await mkdir(files.notesDirectory, { recursive: true });
|
|
23
|
+
|
|
24
|
+
const objectSchema = (properties, required = []) => ({
|
|
25
|
+
type: "object",
|
|
26
|
+
properties,
|
|
27
|
+
required,
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
});
|
|
30
|
+
const string = { type: "string" };
|
|
31
|
+
const boolean = { type: "boolean" };
|
|
32
|
+
|
|
33
|
+
const tools = [
|
|
34
|
+
["todo_list", "List todos", objectSchema({ status: { type: "string", enum: ["all", "open", "completed"] } })],
|
|
35
|
+
["todo_create", "Create a todo", objectSchema({ title: string, notes: string, dueDate: string, priority: { type: "string", enum: ["low", "normal", "high"] } }, ["title"])],
|
|
36
|
+
["todo_update", "Update a todo", objectSchema({ id: string, title: string, notes: string, dueDate: string, priority: { type: "string", enum: ["low", "normal", "high"] }, completed: boolean }, ["id"])],
|
|
37
|
+
["todo_delete", "Delete a todo", objectSchema({ id: string }, ["id"])],
|
|
38
|
+
["note_list", "List Markdown notes", objectSchema({ query: string })],
|
|
39
|
+
["note_read", "Read a Markdown note", objectSchema({ id: string }, ["id"])],
|
|
40
|
+
["note_save", "Create or update a Markdown note", objectSchema({ id: string, title: string, content: string }, ["title", "content"])],
|
|
41
|
+
["note_delete", "Delete a Markdown note", objectSchema({ id: string }, ["id"])],
|
|
42
|
+
["favorite_list", "List favorites", objectSchema({ query: string, tag: string })],
|
|
43
|
+
["favorite_save", "Save a favorite", objectSchema({ url: string, title: string, note: string, tags: { type: "array", items: string } }, ["url", "title"])],
|
|
44
|
+
["favorite_update", "Update a favorite", objectSchema({ id: string, url: string, title: string, note: string, tags: { type: "array", items: string } }, ["id"])],
|
|
45
|
+
["favorite_delete", "Delete a favorite", objectSchema({ id: string }, ["id"])],
|
|
46
|
+
["event_list", "List calendar events", objectSchema({ start: string, end: string })],
|
|
47
|
+
["event_create", "Create an event", objectSchema({ title: string, start: string, end: string, allDay: boolean, location: string, notes: string }, ["title", "start"])],
|
|
48
|
+
["event_update", "Update an event", objectSchema({ id: string, title: string, start: string, end: string, allDay: boolean, location: string, notes: string }, ["id"])],
|
|
49
|
+
["event_delete", "Delete an event", objectSchema({ id: string }, ["id"])],
|
|
50
|
+
["calendar_subscribe", "Connect an ICS calendar URL", objectSchema({ name: string, url: string }, ["name", "url"])],
|
|
51
|
+
["calendar_sync", "Sync connected ICS calendars", objectSchema({ id: string })],
|
|
52
|
+
["calendar_unsubscribe", "Disconnect an ICS calendar", objectSchema({ id: string }, ["id"])],
|
|
53
|
+
].map(([name, description, inputSchema]) => ({ name, description, inputSchema }));
|
|
54
|
+
|
|
55
|
+
async function readJson(filePath, fallback) {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error?.code === "ENOENT") return structuredClone(fallback);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function writeJson(filePath, value) {
|
|
65
|
+
await writeTextAtomic(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function writeTextAtomic(filePath, value) {
|
|
69
|
+
const tempPath = `${filePath}.${randomUUID()}.tmp`;
|
|
70
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
71
|
+
try {
|
|
72
|
+
await writeFile(tempPath, value, { encoding: "utf8", mode: 0o600 });
|
|
73
|
+
await rename(tempPath, filePath);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
await rm(tempPath, { force: true }).catch(() => undefined);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const now = () => new Date().toISOString();
|
|
81
|
+
const requireText = (value, field) => {
|
|
82
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
|
|
83
|
+
return value.trim();
|
|
84
|
+
};
|
|
85
|
+
const optionalText = (value) => typeof value === "string" ? value.trim() : "";
|
|
86
|
+
const requireId = (value) => requireText(value, "id");
|
|
87
|
+
const requireNoteId = (value) => {
|
|
88
|
+
const noteId = requireId(value);
|
|
89
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(noteId) || noteId === "." || noteId === "..") {
|
|
90
|
+
throw new Error("note id is invalid");
|
|
91
|
+
}
|
|
92
|
+
return noteId;
|
|
93
|
+
};
|
|
94
|
+
const normalizeTags = (value) => Array.isArray(value)
|
|
95
|
+
? [...new Set(value.map((entry) => optionalText(entry)).filter(Boolean))].slice(0, 20)
|
|
96
|
+
: [];
|
|
97
|
+
const assertHttpUrl = (value) => {
|
|
98
|
+
const url = new URL(requireText(value, "url"));
|
|
99
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("url must use http or https");
|
|
100
|
+
return url.toString();
|
|
101
|
+
};
|
|
102
|
+
const calendarSubscriptionService = new CalendarSubscriptionService({
|
|
103
|
+
normalizeHttpUrl: assertHttpUrl,
|
|
104
|
+
now,
|
|
105
|
+
toIso,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
async function mutateCollection(filePath, callback) {
|
|
109
|
+
const state = await readJson(filePath, { schemaVersion: 1, items: [] });
|
|
110
|
+
const result = await callback(state.items);
|
|
111
|
+
await writeJson(filePath, { schemaVersion: 1, items: state.items });
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const actions = {
|
|
116
|
+
todo_list: async ({ status = "all" }) => {
|
|
117
|
+
const state = await readJson(files.todos, { schemaVersion: 1, items: [] });
|
|
118
|
+
const items = state.items
|
|
119
|
+
.filter((item) => status === "all" || (status === "completed") === item.completed)
|
|
120
|
+
.sort((left, right) => Number(left.completed) - Number(right.completed) || optionalText(left.dueDate).localeCompare(optionalText(right.dueDate)) || right.createdAt.localeCompare(left.createdAt));
|
|
121
|
+
return { items };
|
|
122
|
+
},
|
|
123
|
+
todo_create: async (input) => await mutateCollection(files.todos, (items) => {
|
|
124
|
+
const timestamp = now();
|
|
125
|
+
const item = { id: randomUUID(), title: requireText(input.title, "title"), notes: optionalText(input.notes), dueDate: optionalText(input.dueDate), priority: ["low", "high"].includes(input.priority) ? input.priority : "normal", completed: false, createdAt: timestamp, updatedAt: timestamp };
|
|
126
|
+
items.push(item);
|
|
127
|
+
return { item };
|
|
128
|
+
}),
|
|
129
|
+
todo_update: async (input) => await mutateCollection(files.todos, (items) => {
|
|
130
|
+
const item = items.find((entry) => entry.id === requireId(input.id));
|
|
131
|
+
if (!item) throw new Error("todo not found");
|
|
132
|
+
for (const field of ["title", "notes", "dueDate"]) if (typeof input[field] === "string") item[field] = field === "title" ? requireText(input[field], field) : input[field].trim();
|
|
133
|
+
if (typeof input.completed === "boolean") item.completed = input.completed;
|
|
134
|
+
if (["low", "normal", "high"].includes(input.priority)) item.priority = input.priority;
|
|
135
|
+
item.updatedAt = now();
|
|
136
|
+
return { item };
|
|
137
|
+
}),
|
|
138
|
+
todo_delete: async ({ id }) => await mutateCollection(files.todos, (items) => {
|
|
139
|
+
const index = items.findIndex((item) => item.id === requireId(id));
|
|
140
|
+
if (index < 0) throw new Error("todo not found");
|
|
141
|
+
items.splice(index, 1);
|
|
142
|
+
return { deleted: true, id };
|
|
143
|
+
}),
|
|
144
|
+
note_list: async ({ query = "" }) => {
|
|
145
|
+
const state = await readJson(files.notesIndex, { schemaVersion: 1, items: [] });
|
|
146
|
+
const normalizedQuery = optionalText(query).toLowerCase();
|
|
147
|
+
return { items: state.items.filter((item) => !normalizedQuery || item.title.toLowerCase().includes(normalizedQuery)).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)) };
|
|
148
|
+
},
|
|
149
|
+
note_read: async ({ id }) => {
|
|
150
|
+
const noteId = requireNoteId(id);
|
|
151
|
+
const state = await readJson(files.notesIndex, { schemaVersion: 1, items: [] });
|
|
152
|
+
const item = state.items.find((entry) => entry.id === noteId);
|
|
153
|
+
if (!item) throw new Error("note not found");
|
|
154
|
+
return { item: { ...item, content: await readFile(path.join(files.notesDirectory, `${noteId}.md`), "utf8") } };
|
|
155
|
+
},
|
|
156
|
+
note_save: async (input) => {
|
|
157
|
+
const state = await readJson(files.notesIndex, { schemaVersion: 1, items: [] });
|
|
158
|
+
const timestamp = now();
|
|
159
|
+
const noteId = requireNoteId(optionalText(input.id) || randomUUID());
|
|
160
|
+
const content = String(input.content ?? "");
|
|
161
|
+
if (Buffer.byteLength(content, "utf8") > MAX_NOTE_BYTES) {
|
|
162
|
+
throw new Error(`note content exceeds ${MAX_NOTE_BYTES} bytes`);
|
|
163
|
+
}
|
|
164
|
+
let item = state.items.find((entry) => entry.id === noteId);
|
|
165
|
+
if (!item) {
|
|
166
|
+
item = { id: noteId, title: requireText(input.title, "title"), createdAt: timestamp, updatedAt: timestamp };
|
|
167
|
+
state.items.push(item);
|
|
168
|
+
} else {
|
|
169
|
+
item.title = requireText(input.title, "title");
|
|
170
|
+
item.updatedAt = timestamp;
|
|
171
|
+
}
|
|
172
|
+
const notePath = path.join(files.notesDirectory, `${noteId}.md`);
|
|
173
|
+
let previousContent;
|
|
174
|
+
try {
|
|
175
|
+
previousContent = await readFile(notePath, "utf8");
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (error?.code !== "ENOENT") throw error;
|
|
178
|
+
}
|
|
179
|
+
await writeTextAtomic(notePath, content);
|
|
180
|
+
try {
|
|
181
|
+
await writeJson(files.notesIndex, state);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
try {
|
|
184
|
+
if (previousContent === undefined) await rm(notePath, { force: true });
|
|
185
|
+
else await writeTextAtomic(notePath, previousContent);
|
|
186
|
+
} catch (restoreError) {
|
|
187
|
+
throw new AggregateError([error, restoreError], "note save failed and content could not be restored");
|
|
188
|
+
}
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
return { item: { ...item, content } };
|
|
192
|
+
},
|
|
193
|
+
note_delete: async ({ id }) => {
|
|
194
|
+
const noteId = requireNoteId(id);
|
|
195
|
+
const state = await readJson(files.notesIndex, { schemaVersion: 1, items: [] });
|
|
196
|
+
const nextItems = state.items.filter((item) => item.id !== noteId);
|
|
197
|
+
if (nextItems.length === state.items.length) throw new Error("note not found");
|
|
198
|
+
await writeJson(files.notesIndex, { ...state, items: nextItems });
|
|
199
|
+
try {
|
|
200
|
+
await rm(path.join(files.notesDirectory, `${noteId}.md`), { force: true });
|
|
201
|
+
} catch (error) {
|
|
202
|
+
try {
|
|
203
|
+
await writeJson(files.notesIndex, state);
|
|
204
|
+
} catch (restoreError) {
|
|
205
|
+
throw new AggregateError([error, restoreError], "note delete failed and index could not be restored");
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
return { deleted: true, id: noteId };
|
|
210
|
+
},
|
|
211
|
+
favorite_list: async ({ query = "", tag = "" }) => {
|
|
212
|
+
const state = await readJson(files.favorites, { schemaVersion: 1, items: [] });
|
|
213
|
+
const normalizedQuery = optionalText(query).toLowerCase();
|
|
214
|
+
const normalizedTag = optionalText(tag).toLowerCase();
|
|
215
|
+
return { items: state.items.filter((item) => (!normalizedQuery || `${item.title} ${item.url} ${item.note}`.toLowerCase().includes(normalizedQuery)) && (!normalizedTag || item.tags.some((entry) => entry.toLowerCase() === normalizedTag))).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)) };
|
|
216
|
+
},
|
|
217
|
+
favorite_save: async (input) => await mutateCollection(files.favorites, (items) => {
|
|
218
|
+
const timestamp = now();
|
|
219
|
+
const item = { id: randomUUID(), url: assertHttpUrl(input.url), title: requireText(input.title, "title"), note: optionalText(input.note), tags: normalizeTags(input.tags), createdAt: timestamp, updatedAt: timestamp };
|
|
220
|
+
items.push(item);
|
|
221
|
+
return { item };
|
|
222
|
+
}),
|
|
223
|
+
favorite_update: async (input) => await mutateCollection(files.favorites, (items) => {
|
|
224
|
+
const item = items.find((entry) => entry.id === requireId(input.id));
|
|
225
|
+
if (!item) throw new Error("favorite not found");
|
|
226
|
+
if (typeof input.url === "string") item.url = assertHttpUrl(input.url);
|
|
227
|
+
if (typeof input.title === "string") item.title = requireText(input.title, "title");
|
|
228
|
+
if (typeof input.note === "string") item.note = input.note.trim();
|
|
229
|
+
if (Array.isArray(input.tags)) item.tags = normalizeTags(input.tags);
|
|
230
|
+
item.updatedAt = now();
|
|
231
|
+
return { item };
|
|
232
|
+
}),
|
|
233
|
+
favorite_delete: async ({ id }) => await mutateCollection(files.favorites, (items) => {
|
|
234
|
+
const index = items.findIndex((item) => item.id === requireId(id));
|
|
235
|
+
if (index < 0) throw new Error("favorite not found");
|
|
236
|
+
items.splice(index, 1);
|
|
237
|
+
return { deleted: true, id };
|
|
238
|
+
}),
|
|
239
|
+
event_list: async ({ start = "", end = "" }) => {
|
|
240
|
+
const state = await readJson(files.calendar, { schemaVersion: 1, items: [], subscriptions: [] });
|
|
241
|
+
const from = start ? new Date(start).getTime() : Number.NEGATIVE_INFINITY;
|
|
242
|
+
const to = end ? new Date(end).getTime() : Number.POSITIVE_INFINITY;
|
|
243
|
+
return { items: state.items.filter((item) => new Date(item.start).getTime() >= from && new Date(item.start).getTime() <= to).sort((left, right) => left.start.localeCompare(right.start)), subscriptions: state.subscriptions };
|
|
244
|
+
},
|
|
245
|
+
event_create: async (input) => await mutateCalendar((state) => {
|
|
246
|
+
const timestamp = now();
|
|
247
|
+
const start = toIso(input.start, "start");
|
|
248
|
+
const item = { id: randomUUID(), title: requireText(input.title, "title"), start, end: input.end ? toIso(input.end, "end") : start, allDay: input.allDay === true, location: optionalText(input.location), notes: optionalText(input.notes), source: "local", createdAt: timestamp, updatedAt: timestamp };
|
|
249
|
+
state.items.push(item);
|
|
250
|
+
return { item };
|
|
251
|
+
}),
|
|
252
|
+
event_update: async (input) => await mutateCalendar((state) => {
|
|
253
|
+
const item = state.items.find((entry) => entry.id === requireId(input.id) && entry.source === "local");
|
|
254
|
+
if (!item) throw new Error("editable event not found");
|
|
255
|
+
if (typeof input.title === "string") item.title = requireText(input.title, "title");
|
|
256
|
+
if (typeof input.start === "string") item.start = toIso(input.start, "start");
|
|
257
|
+
if (typeof input.end === "string") item.end = toIso(input.end, "end");
|
|
258
|
+
if (typeof input.allDay === "boolean") item.allDay = input.allDay;
|
|
259
|
+
if (typeof input.location === "string") item.location = input.location.trim();
|
|
260
|
+
if (typeof input.notes === "string") item.notes = input.notes.trim();
|
|
261
|
+
item.updatedAt = now();
|
|
262
|
+
return { item };
|
|
263
|
+
}),
|
|
264
|
+
event_delete: async ({ id }) => await mutateCalendar((state) => {
|
|
265
|
+
const index = state.items.findIndex((item) => item.id === requireId(id) && item.source === "local");
|
|
266
|
+
if (index < 0) throw new Error("editable event not found");
|
|
267
|
+
state.items.splice(index, 1);
|
|
268
|
+
return { deleted: true, id };
|
|
269
|
+
}),
|
|
270
|
+
calendar_subscribe: async ({ name, url }) => await mutateCalendar(async (state) => {
|
|
271
|
+
const subscription = { id: randomUUID(), name: requireText(name, "name"), url: assertHttpUrl(url), lastSyncedAt: "", lastError: "" };
|
|
272
|
+
state.subscriptions.push(subscription);
|
|
273
|
+
await calendarSubscriptionService.sync(state, subscription);
|
|
274
|
+
return { subscription, imported: state.items.filter((item) => item.subscriptionId === subscription.id).length };
|
|
275
|
+
}),
|
|
276
|
+
calendar_sync: async ({ id = "" }) => await mutateCalendar(async (state) => {
|
|
277
|
+
const subscriptions = id ? state.subscriptions.filter((entry) => entry.id === id) : state.subscriptions;
|
|
278
|
+
for (const subscription of subscriptions) {
|
|
279
|
+
await calendarSubscriptionService.sync(state, subscription);
|
|
280
|
+
}
|
|
281
|
+
return { subscriptions, imported: state.items.filter((item) => item.source === "ics").length };
|
|
282
|
+
}),
|
|
283
|
+
calendar_unsubscribe: async ({ id }) => await mutateCalendar((state) => {
|
|
284
|
+
const subscriptionId = requireId(id);
|
|
285
|
+
state.subscriptions = state.subscriptions.filter((entry) => entry.id !== subscriptionId);
|
|
286
|
+
state.items = state.items.filter((item) => item.subscriptionId !== subscriptionId);
|
|
287
|
+
return { deleted: true, id: subscriptionId };
|
|
288
|
+
}),
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
async function mutateCalendar(callback) {
|
|
292
|
+
const state = await readJson(files.calendar, { schemaVersion: 1, items: [], subscriptions: [] });
|
|
293
|
+
try {
|
|
294
|
+
const result = await callback(state);
|
|
295
|
+
await writeJson(files.calendar, state);
|
|
296
|
+
return result;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
try {
|
|
299
|
+
await writeJson(files.calendar, state);
|
|
300
|
+
} catch (persistError) {
|
|
301
|
+
throw new AggregateError([error, persistError], "calendar operation failed and state could not be persisted");
|
|
302
|
+
}
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function toIso(value, field) {
|
|
308
|
+
const date = new Date(requireText(value, field));
|
|
309
|
+
if (!Number.isFinite(date.getTime())) throw new Error(`${field} must be a valid date`);
|
|
310
|
+
return date.toISOString();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function send(message) {
|
|
314
|
+
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function handle(request) {
|
|
318
|
+
if (request.method === "initialize") return { protocolVersion: request.params?.protocolVersion ?? "2025-03-26", capabilities: { tools: {} }, serverInfo: { name: "nextclaw-personal-organizer-data", version: "0.1.1" } };
|
|
319
|
+
if (request.method === "ping") return {};
|
|
320
|
+
if (request.method === "tools/list") return { tools };
|
|
321
|
+
if (request.method === "tools/call") {
|
|
322
|
+
const action = actions[request.params?.name];
|
|
323
|
+
if (!action) throw new Error(`unknown tool: ${request.params?.name}`);
|
|
324
|
+
const payload = await action(request.params?.arguments ?? {});
|
|
325
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
326
|
+
}
|
|
327
|
+
throw new Error(`method not found: ${request.method}`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const input = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
331
|
+
for await (const line of input) {
|
|
332
|
+
if (!line.trim()) continue;
|
|
333
|
+
let request;
|
|
334
|
+
try {
|
|
335
|
+
request = JSON.parse(line);
|
|
336
|
+
if (request.id === undefined) continue;
|
|
337
|
+
send({ jsonrpc: "2.0", id: request.id, result: await handle(request) });
|
|
338
|
+
} catch (error) {
|
|
339
|
+
if (request?.id !== undefined) send({ jsonrpc: "2.0", id: request.id, error: { code: -32603, message: error instanceof Error ? error.message : String(error) } });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "nextclaw-personal-organizer-data",
|
|
3
|
+
"title": "个人空间数据服务",
|
|
4
|
+
"titleI18n": { "zh-CN": "个人空间数据服务", "en-US": "Personal Space Data" },
|
|
5
|
+
"description": "在本机稳定目录中管理待办、Markdown 笔记、收藏和日历。",
|
|
6
|
+
"descriptionI18n": {
|
|
7
|
+
"zh-CN": "在本机稳定目录中管理待办、Markdown 笔记、收藏和日历。",
|
|
8
|
+
"en-US": "Store todos, Markdown notes, favorites, and calendar data in a stable local directory."
|
|
9
|
+
},
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"protocol": "mcp",
|
|
12
|
+
"command": "node",
|
|
13
|
+
"args": ["index.mjs"],
|
|
14
|
+
"actions": {
|
|
15
|
+
"todo_list": { "risk": "read", "title": "读取待办" },
|
|
16
|
+
"todo_create": { "risk": "write", "title": "创建待办" },
|
|
17
|
+
"todo_update": { "risk": "write", "title": "修改待办" },
|
|
18
|
+
"todo_delete": { "risk": "write", "title": "删除待办" },
|
|
19
|
+
"note_list": { "risk": "read", "title": "读取笔记列表" },
|
|
20
|
+
"note_read": { "risk": "read", "title": "读取笔记" },
|
|
21
|
+
"note_save": { "risk": "write", "title": "保存 Markdown 笔记" },
|
|
22
|
+
"note_delete": { "risk": "write", "title": "删除笔记" },
|
|
23
|
+
"favorite_list": { "risk": "read", "title": "读取收藏" },
|
|
24
|
+
"favorite_save": { "risk": "write", "title": "保存收藏" },
|
|
25
|
+
"favorite_update": { "risk": "write", "title": "修改收藏" },
|
|
26
|
+
"favorite_delete": { "risk": "write", "title": "删除收藏" },
|
|
27
|
+
"event_list": { "risk": "read", "title": "读取日程" },
|
|
28
|
+
"event_create": { "risk": "write", "title": "创建日程" },
|
|
29
|
+
"event_update": { "risk": "write", "title": "修改日程" },
|
|
30
|
+
"event_delete": { "risk": "write", "title": "删除日程" },
|
|
31
|
+
"calendar_subscribe": { "risk": "external", "title": "连接 ICS 日历" },
|
|
32
|
+
"calendar_sync": { "risk": "external", "title": "同步已连接日历" },
|
|
33
|
+
"calendar_unsubscribe": { "risk": "write", "title": "断开日历连接" }
|
|
34
|
+
}
|
|
35
|
+
}
|
package/ui-dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-BcFJp_1X.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./chunk-5HE753X5-
|
|
1
|
+
import{n as e}from"./chunk-5HE753X5-C-w6CQZK.js";import{n as t}from"./chunk-Y2CYZVJY-D1mAU_Po.js";import{m as n}from"./src-Bw-mzbQb.js";import"./chunk-WYO6CB5R-Dn9To_OI.js";import"./chunk-VAUOI2AC-BGvh3yIx.js";import{n as r,r as i,t as a}from"./chunk-MOJQB5TN-Di52TorW.js";import{t as o}from"./chunk-JWPE2WC7-DawOjNE3.js";import{t as s}from"./mermaid-parser.core-XUNZhr2W.js";var c=e().RailroadAbnf.parser.LangiumParser,l=t(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=t(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=t(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=t(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=t(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=t(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=t(e=>{o(e,a),e.title&&a.setTitle(e.title),e.rules.map(e=>a.addRule(m(e)))},`populateDb`),g={parser:{parse:t(e=>{a.clear(),n.debug(`[ABNF Parser] Starting Langium parse`);let t=c.parse(e);if(t.lexerErrors.length>0||t.parserErrors.length>0)throw new s(t);let r=t.value;n.debug(`[ABNF Parser] Parsed rules:`,r.rules.length),h(r),n.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:a}},db:a,renderer:i,styles:r};export{g as diagram};
|