diff --git a/bun.lock b/bun.lock index cabd7313..d6974c45 100644 --- a/bun.lock +++ b/bun.lock @@ -121,11 +121,13 @@ "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "highlight.js": "^11.11.1", "lucide-react": "^0.544.0", "markdown-it": "^14.1.0", "markdown-it-html5-embed": "^1.0.0", "markdown-it-link-attributes": "^4.0.1", "markdown-it-task-lists": "^2.1.1", + "mermaid": "^11.12.2", "monaco-editor": "^0.55.1", "postcss": "^8.5.6", "posthog-js": "^1.288.0", @@ -317,6 +319,8 @@ "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], + "@asamuzakjp/css-color": ["@asamuzakjp/css-color@4.1.1", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "lru-cache": "^11.2.4" } }, "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ=="], "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.7.7", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.5" } }, "sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA=="], @@ -447,6 +451,18 @@ "@borewit/text-codec": ["@borewit/text-codec@0.2.1", "", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="], + "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], + + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@11.0.3", "", { "dependencies": { "@chevrotain/gast": "11.0.3", "@chevrotain/types": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ=="], + + "@chevrotain/gast": ["@chevrotain/gast@11.0.3", "", { "dependencies": { "@chevrotain/types": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q=="], + + "@chevrotain/regexp-to-ast": ["@chevrotain/regexp-to-ast@11.0.3", "", {}, "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA=="], + + "@chevrotain/types": ["@chevrotain/types@11.0.3", "", {}, "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="], + + "@chevrotain/utils": ["@chevrotain/utils@11.0.3", "", {}, "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="], + "@clerk/backend": ["@clerk/backend@2.29.7", "", { "dependencies": { "@clerk/shared": "^3.44.0", "@clerk/types": "^4.101.14", "standardwebhooks": "^1.0.0", "tslib": "2.8.1" } }, "sha512-OSfFQ85L0FV2wSzqlr0hRvluIu3Z5ClgLiBE6Qx7XjSGyJoqEvP5OP4fl5Nt5icgGvH0EwA1dljPGyQpaqbQEw=="], "@clerk/clerk-react": ["@clerk/clerk-react@5.60.0", "", { "dependencies": { "@clerk/shared": "^3.44.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0", "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0" } }, "sha512-P88FncsJpq/3WZJhhlj+md8mYb35BIXpr462C/figwsBGHsinr8VuBQUMcMZZ/6M34C8ABfLTPa6PHVp6+3D5Q=="], @@ -577,6 +593,10 @@ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + + "@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="], + "@ioredis/commands": ["@ioredis/commands@1.5.0", "", {}, "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -625,6 +645,8 @@ "@lukeed/csprng": ["@lukeed/csprng@1.1.0", "", {}, "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA=="], + "@mermaid-js/parser": ["@mermaid-js/parser@0.6.3", "", { "dependencies": { "langium": "3.3.1" } }, "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA=="], + "@microsoft/tsdoc": ["@microsoft/tsdoc@0.16.0", "", {}, "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.3", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ=="], @@ -1457,6 +1479,10 @@ "charm": ["charm@0.1.2", "", {}, "sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ=="], + "chevrotain": ["chevrotain@11.0.3", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/gast": "11.0.3", "@chevrotain/regexp-to-ast": "11.0.3", "@chevrotain/types": "11.0.3", "@chevrotain/utils": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw=="], + + "chevrotain-allstar": ["chevrotain-allstar@0.3.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^11.0.0" } }, "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw=="], + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="], @@ -1499,6 +1525,8 @@ "concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="], + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "consola": ["consola@2.15.3", "", {}, "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="], "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], @@ -1517,6 +1545,8 @@ "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], + "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], + "croner": ["croner@4.1.97", "", {}, "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -1535,24 +1565,78 @@ "culvert": ["culvert@0.1.2", "", {}, "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg=="], + "cytoscape": ["cytoscape@3.33.1", "", {}, "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ=="], + + "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], + + "cytoscape-fcose": ["cytoscape-fcose@2.2.0", "", { "dependencies": { "cose-base": "^2.2.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ=="], + + "d3": ["d3@7.9.0", "", { "dependencies": { "d3-array": "3", "d3-axis": "3", "d3-brush": "3", "d3-chord": "3", "d3-color": "3", "d3-contour": "4", "d3-delaunay": "6", "d3-dispatch": "3", "d3-drag": "3", "d3-dsv": "3", "d3-ease": "3", "d3-fetch": "3", "d3-force": "3", "d3-format": "3", "d3-geo": "3", "d3-hierarchy": "3", "d3-interpolate": "3", "d3-path": "3", "d3-polygon": "3", "d3-quadtree": "3", "d3-random": "3", "d3-scale": "4", "d3-scale-chromatic": "3", "d3-selection": "3", "d3-shape": "3", "d3-time": "3", "d3-time-format": "4", "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" } }, "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA=="], + + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-axis": ["d3-axis@3.0.0", "", {}, "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="], + + "d3-brush": ["d3-brush@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" } }, "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ=="], + + "d3-chord": ["d3-chord@3.0.1", "", { "dependencies": { "d3-path": "1 - 3" } }, "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g=="], + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + "d3-contour": ["d3-contour@4.0.2", "", { "dependencies": { "d3-array": "^3.2.0" } }, "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA=="], + + "d3-delaunay": ["d3-delaunay@6.0.4", "", { "dependencies": { "delaunator": "5" } }, "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A=="], + "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], + "d3-dsv": ["d3-dsv@3.0.1", "", { "dependencies": { "commander": "7", "iconv-lite": "0.6", "rw": "1" }, "bin": { "csv2json": "bin/dsv2json.js", "csv2tsv": "bin/dsv2dsv.js", "dsv2dsv": "bin/dsv2dsv.js", "dsv2json": "bin/dsv2json.js", "json2csv": "bin/json2dsv.js", "json2dsv": "bin/json2dsv.js", "json2tsv": "bin/json2dsv.js", "tsv2csv": "bin/dsv2dsv.js", "tsv2json": "bin/dsv2json.js" } }, "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q=="], + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + "d3-fetch": ["d3-fetch@3.0.1", "", { "dependencies": { "d3-dsv": "1 - 3" } }, "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw=="], + + "d3-force": ["d3-force@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="], + + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + + "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="], + + "d3-hierarchy": ["d3-hierarchy@3.1.2", "", {}, "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="], + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-polygon": ["d3-polygon@3.0.1", "", {}, "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="], + + "d3-quadtree": ["d3-quadtree@3.0.1", "", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="], + + "d3-random": ["d3-random@3.0.1", "", {}, "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="], + + "d3-sankey": ["d3-sankey@0.12.3", "", { "dependencies": { "d3-array": "1 - 2", "d3-shape": "^1.2.0" } }, "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-scale-chromatic": ["d3-scale-chromatic@3.1.0", "", { "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" } }, "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ=="], + "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], + "dagre-d3-es": ["dagre-d3-es@7.0.13", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q=="], + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], "data-urls": ["data-urls@6.0.1", "", { "dependencies": { "whatwg-mimetype": "^5.0.0", "whatwg-url": "^15.1.0" } }, "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ=="], @@ -1591,6 +1675,8 @@ "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="], + "delaunator": ["delaunator@5.0.1", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], @@ -1617,7 +1703,7 @@ "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], - "dompurify": ["dompurify@3.2.7", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw=="], + "dompurify": ["dompurify@3.3.1", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q=="], "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], @@ -1869,6 +1955,8 @@ "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], + "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], + "hard-rejection": ["hard-rejection@2.1.0", "", {}, "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="], "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], @@ -1913,6 +2001,8 @@ "heap-js": ["heap-js@2.7.1", "", {}, "sha512-EQfezRg0NCZGNlhlDR3Evrw1FVL2G3LhU7EgPoxufQKruNBSYA8MiRPHeWbU+36o+Fhel0wMwM+sLEiBAlNLJA=="], + "highlight.js": ["highlight.js@11.11.1", "", {}, "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w=="], + "hono": ["hono@4.11.7", "", {}, "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw=="], "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], @@ -1955,6 +2045,8 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], + "ioredis": ["ioredis@5.9.2", "", { "dependencies": { "@ioredis/commands": "1.5.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ=="], "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], @@ -2089,10 +2181,18 @@ "kafkajs": ["kafkajs@2.2.4", "", {}, "sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA=="], + "katex": ["katex@0.16.28", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg=="], + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + "langium": ["langium@3.3.1", "", { "dependencies": { "chevrotain": "~11.0.3", "chevrotain-allstar": "~0.3.0", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.0.8" } }, "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w=="], + + "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], "libphonenumber-js": ["libphonenumber-js@1.12.36", "", {}, "sha512-woWhKMAVx1fzzUnMCyOzglgSgf6/AFHLASdOBcchYCyvWSGWt12imw3iu2hdI5d4dGZRsNWAmWiz37sDKUPaRQ=="], @@ -2113,6 +2213,8 @@ "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], @@ -2147,7 +2249,7 @@ "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], - "marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="], + "marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], @@ -2197,6 +2299,8 @@ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "mermaid": ["mermaid@11.12.2", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", "@mermaid-js/parser": "^0.6.3", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.13", "dayjs": "^1.11.18", "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", "lodash-es": "^4.17.21", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w=="], + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], @@ -2283,6 +2387,8 @@ "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], + "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], "monaco-editor": ["monaco-editor@0.55.1", "", { "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A=="], @@ -2377,6 +2483,8 @@ "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + "pako": ["pako@2.1.0", "", {}, "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="], "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], @@ -2393,6 +2501,8 @@ "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + "path-data-parser": ["path-data-parser@0.1.0", "", {}, "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -2403,6 +2513,8 @@ "path-to-regexp": ["path-to-regexp@3.3.0", "", {}, "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw=="], + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "pg": ["pg@8.18.0", "", { "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.11.0", "pg-protocol": "^1.11.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ=="], "pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="], @@ -2433,6 +2545,8 @@ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], "pm2": ["pm2@6.0.14", "", { "dependencies": { "@pm2/agent": "~2.1.1", "@pm2/blessed": "0.1.81", "@pm2/io": "~6.1.0", "@pm2/js-api": "~0.8.0", "@pm2/pm2-version-check": "^1.0.4", "ansis": "4.0.0-node10", "async": "3.2.6", "chokidar": "3.6.0", "cli-tableau": "2.0.1", "commander": "2.15.1", "croner": "4.1.97", "dayjs": "1.11.15", "debug": "4.4.3", "enquirer": "2.3.6", "eventemitter2": "5.0.1", "fclone": "1.0.11", "js-yaml": "4.1.1", "mkdirp": "1.0.4", "needle": "2.4.0", "pidusage": "3.0.2", "pm2-axon": "~4.0.1", "pm2-axon-rpc": "~0.7.1", "pm2-deploy": "~1.0.2", "pm2-multimeter": "^0.1.2", "promptly": "2.2.0", "semver": "7.7.2", "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1" }, "optionalDependencies": { "pm2-sysmonit": "^1.2.8" }, "bin": { "pm2": "bin/pm2", "pm2-dev": "bin/pm2-dev", "pm2-docker": "bin/pm2-docker", "pm2-runtime": "bin/pm2-runtime" } }, "sha512-wX1FiFkzuT2H/UUEA8QNXDAA9MMHDsK/3UHj6Dkd5U7kxyigKDA5gyDw78ycTQZAuGCLWyUX5FiXEuVQWafukA=="], @@ -2447,6 +2561,10 @@ "pm2-sysmonit": ["pm2-sysmonit@1.2.8", "", { "dependencies": { "async": "^3.2.0", "debug": "^4.3.1", "pidusage": "^2.0.21", "systeminformation": "^5.7", "tx2": "~1.0.4" } }, "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA=="], + "points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="], + + "points-on-path": ["points-on-path@0.2.1", "", { "dependencies": { "path-data-parser": "0.1.0", "points-on-curve": "0.2.0" } }, "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], @@ -2623,14 +2741,20 @@ "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], + "robust-predicates": ["robust-predicates@3.0.2", "", {}, "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="], + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], + "roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="], + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "run-series": ["run-series@1.1.9", "", {}, "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g=="], + "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], @@ -2775,6 +2899,8 @@ "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + "stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="], + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], "superagent": ["superagent@10.3.0", "", { "dependencies": { "component-emitter": "^1.3.1", "cookiejar": "^2.1.4", "debug": "^4.3.7", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.5", "formidable": "^3.5.4", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.14.1" } }, "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ=="], @@ -2821,6 +2947,8 @@ "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "tinygradient": ["tinygradient@1.1.5", "", { "dependencies": { "@types/tinycolor2": "^1.4.0", "tinycolor2": "^1.0.0" } }, "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw=="], @@ -2849,6 +2977,8 @@ "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + "ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="], + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], "ts-loader": ["ts-loader@9.5.4", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", "semver": "^7.3.4", "source-map": "^0.7.4" }, "peerDependencies": { "typescript": "*", "webpack": "^5.0.0" } }, "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ=="], @@ -2883,6 +3013,8 @@ "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "uid": ["uid@2.0.2", "", { "dependencies": { "@lukeed/csprng": "^1.0.0" } }, "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], @@ -2949,6 +3081,18 @@ "vizion": ["vizion@2.2.1", "", { "dependencies": { "async": "^2.6.3", "git-node-fs": "^1.0.0", "ini": "^1.3.5", "js-git": "^0.7.8" } }, "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww=="], + "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + + "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], + + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], + + "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + + "vscode-uri": ["vscode-uri@3.0.8", "", {}, "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw=="], + "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="], "watchpack": ["watchpack@2.5.1", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg=="], @@ -3049,6 +3193,10 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@chevrotain/cst-dts-gen/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + + "@chevrotain/gast/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "@clerk/shared/csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "@clerk/shared/swr": ["swr@2.3.4", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg=="], @@ -3219,6 +3367,8 @@ "chalk-animation/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chevrotain/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "cli-tableau/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], @@ -3229,6 +3379,16 @@ "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], + + "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "d3-dsv/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "d3-sankey/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], + + "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="], + "data-urls/whatwg-mimetype": ["whatwg-mimetype@5.0.0", "", {}, "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw=="], "debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -3285,6 +3445,8 @@ "js-git/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], + "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + "markdown-it-html5-embed/markdown-it": ["markdown-it@8.4.2", "", { "dependencies": { "argparse": "^1.0.7", "entities": "~1.1.1", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, "bin": { "markdown-it": "bin/markdown-it.js" } }, "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ=="], "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], @@ -3295,12 +3457,18 @@ "meow/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "mermaid/dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "minio/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], "minio/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "monaco-editor/dompurify": ["dompurify@3.2.7", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw=="], + + "monaco-editor/marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="], + "multer/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], "multer/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], @@ -3335,8 +3503,6 @@ "postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - "posthog-js/dompurify": ["dompurify@3.3.1", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q=="], - "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], @@ -3559,6 +3725,10 @@ "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], + + "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], + "drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], "drizzle-kit/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], diff --git a/frontend/package.json b/frontend/package.json index 8e524811..015c6f92 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -73,11 +73,13 @@ "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "highlight.js": "^11.11.1", "lucide-react": "^0.544.0", "markdown-it": "^14.1.0", "markdown-it-html5-embed": "^1.0.0", "markdown-it-link-attributes": "^4.0.1", "markdown-it-task-lists": "^2.1.1", + "mermaid": "^11.12.2", "monaco-editor": "^0.55.1", "postcss": "^8.5.6", "posthog-js": "^1.288.0", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 26139b94..fea75a05 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { ChatInterface } from '@/pages/ChatInterface'; import { WorkflowList } from '@/pages/WorkflowList'; import { WorkflowBuilder } from '@/features/workflow-builder/WorkflowBuilder'; import { SecretsManager } from '@/pages/SecretsManager'; @@ -49,7 +50,8 @@ function App() { - } /> + } /> + } /> ; + category: 'chat' | 'workflow' | 'navigation' | 'actions'; + action: () => void; + keywords?: string[]; +} + +interface ChatCommandPaletteProps { + onSelectPrompt?: (prompt: string) => void; +} + +export function ChatCommandPalette({ onSelectPrompt }: ChatCommandPaletteProps) { + const navigate = useNavigate(); + const [query, setQuery] = useState(''); + const [selectedIndex, setSelectedIndex] = useState(0); + const inputRef = useRef(null); + const listRef = useRef(null); + + const { + isCommandPaletteOpen, + setCommandPaletteOpen, + createSession, + clearSession, + currentSessionId, + } = useChatStore(); + + // Define all commands + const commands: CommandItem[] = useMemo(() => { + const baseCommands: CommandItem[] = [ + // Chat commands + { + id: 'new-chat', + label: 'New Conversation', + description: 'Start a new conversation', + icon: Plus, + category: 'chat', + action: () => { + createSession(); + setCommandPaletteOpen(false); + }, + keywords: ['create', 'start', 'conversation'], + }, + { + id: 'clear-chat', + label: 'Clear Chat', + description: 'Clear current conversation', + icon: Trash2, + category: 'chat', + action: () => { + if (currentSessionId) { + clearSession(currentSessionId); + } + setCommandPaletteOpen(false); + }, + keywords: ['delete', 'remove', 'reset'], + }, + + // Workflow commands + { + id: 'create-workflow', + label: 'Create Workflow', + description: 'Build a new automation workflow', + icon: Workflow, + category: 'workflow', + action: () => { + navigate('/workflows/new'); + setCommandPaletteOpen(false); + }, + keywords: ['automation', 'build', 'new'], + }, + { + id: 'run-workflow', + label: 'Run Workflow', + description: 'Execute an existing workflow', + icon: Play, + category: 'workflow', + action: () => { + navigate('/workflows'); + setCommandPaletteOpen(false); + }, + keywords: ['execute', 'start', 'trigger'], + }, + { + id: 'view-history', + label: 'Run History', + description: 'View recent workflow executions', + icon: History, + category: 'workflow', + action: () => { + navigate('/runs'); + setCommandPaletteOpen(false); + }, + keywords: ['logs', 'executions', 'past'], + }, + + // Navigation commands + { + id: 'go-workflows', + label: 'Go to Workflows', + description: 'View all workflows', + icon: Workflow, + category: 'navigation', + action: () => { + navigate('/workflows'); + setCommandPaletteOpen(false); + }, + keywords: ['navigate', 'open'], + }, + { + id: 'go-components', + label: 'Go to Components', + description: 'Browse available components', + icon: Code, + category: 'navigation', + action: () => { + navigate('/components'); + setCommandPaletteOpen(false); + }, + keywords: ['navigate', 'open', 'nodes'], + }, + { + id: 'go-settings', + label: 'Settings', + description: 'Open application settings', + icon: Settings, + category: 'navigation', + action: () => { + navigate('/settings'); + setCommandPaletteOpen(false); + }, + keywords: ['preferences', 'config', 'configure'], + }, + + // Action commands (prompts) + { + id: 'prompt-analyze', + label: 'Analyze Code', + description: 'Get code analysis and suggestions', + icon: Code, + category: 'actions', + action: () => { + onSelectPrompt?.('Analyze this code and suggest improvements:'); + setCommandPaletteOpen(false); + }, + keywords: ['review', 'code', 'suggestions'], + }, + { + id: 'prompt-debug', + label: 'Debug Issue', + description: 'Get help debugging a problem', + icon: Bug, + category: 'actions', + action: () => { + onSelectPrompt?.('Help me debug this issue:'); + setCommandPaletteOpen(false); + }, + keywords: ['fix', 'error', 'problem'], + }, + { + id: 'prompt-explain', + label: 'Explain Concept', + description: 'Learn about a concept or feature', + icon: BookOpen, + category: 'actions', + action: () => { + onSelectPrompt?.('Explain to me how'); + setCommandPaletteOpen(false); + }, + keywords: ['learn', 'understand', 'teach'], + }, + { + id: 'help', + label: 'Help & Documentation', + description: 'Get help and view docs', + icon: HelpCircle, + category: 'navigation', + action: () => { + navigate('/docs'); + setCommandPaletteOpen(false); + }, + keywords: ['docs', 'documentation', 'support'], + }, + ]; + + return baseCommands; + }, [ + navigate, + createSession, + clearSession, + currentSessionId, + setCommandPaletteOpen, + onSelectPrompt, + ]); + + // Filter commands based on query + const filteredCommands = useMemo(() => { + if (!query.trim()) return commands; + + const lowerQuery = query.toLowerCase(); + return commands.filter( + (cmd) => + cmd.label.toLowerCase().includes(lowerQuery) || + cmd.description?.toLowerCase().includes(lowerQuery) || + cmd.keywords?.some((k) => k.toLowerCase().includes(lowerQuery)), + ); + }, [commands, query]); + + // Group filtered commands by category + const groupedCommands = useMemo(() => { + const groups: Record = {}; + filteredCommands.forEach((cmd) => { + if (!groups[cmd.category]) groups[cmd.category] = []; + groups[cmd.category].push(cmd); + }); + return groups; + }, [filteredCommands]); + + const categoryLabels: Record = { + chat: 'Chat', + workflow: 'Workflows', + navigation: 'Navigation', + actions: 'Quick Actions', + }; + + const categoryOrder = ['chat', 'workflow', 'actions', 'navigation']; + + // Flatten for keyboard navigation + const flatCommands = useMemo(() => { + return categoryOrder + .filter((cat) => groupedCommands[cat]) + .flatMap((cat) => groupedCommands[cat]); + }, [groupedCommands]); + + // Keyboard navigation + useEffect(() => { + if (selectedIndex >= flatCommands.length) { + setSelectedIndex(Math.max(0, flatCommands.length - 1)); + } + }, [flatCommands.length, selectedIndex]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setSelectedIndex((prev) => Math.min(prev + 1, flatCommands.length - 1)); + break; + case 'ArrowUp': + e.preventDefault(); + setSelectedIndex((prev) => Math.max(prev - 1, 0)); + break; + case 'Enter': + e.preventDefault(); + if (flatCommands[selectedIndex]) { + flatCommands[selectedIndex].action(); + } + break; + case 'Escape': + e.preventDefault(); + setCommandPaletteOpen(false); + break; + } + }, + [flatCommands, selectedIndex, setCommandPaletteOpen], + ); + + // Reset state when opened + useEffect(() => { + if (isCommandPaletteOpen) { + setQuery(''); + setSelectedIndex(0); + setTimeout(() => inputRef.current?.focus(), 50); + } + }, [isCommandPaletteOpen]); + + // Global keyboard shortcut + useEffect(() => { + const handleGlobalKeyDown = (e: KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault(); + setCommandPaletteOpen(!isCommandPaletteOpen); + } + if ( + e.key === '/' && + !isCommandPaletteOpen && + !(e.target instanceof HTMLInputElement) && + !(e.target instanceof HTMLTextAreaElement) + ) { + e.preventDefault(); + setCommandPaletteOpen(true); + } + }; + + window.addEventListener('keydown', handleGlobalKeyDown); + return () => window.removeEventListener('keydown', handleGlobalKeyDown); + }, [isCommandPaletteOpen, setCommandPaletteOpen]); + + return ( + + + {/* Search Input */} +
+ + { + setQuery(e.target.value); + setSelectedIndex(0); + }} + placeholder="Type a command or search..." + className="flex-1 bg-transparent text-foreground text-base placeholder:text-muted-foreground/60 outline-none" + /> + + ESC + +
+ + {/* Commands List */} +
+ {flatCommands.length === 0 ? ( +
+ +

No commands found

+

Try a different search term

+
+ ) : ( + categoryOrder + .filter((cat) => groupedCommands[cat]) + .map((category) => ( +
+
+ {categoryLabels[category]} +
+ {groupedCommands[category].map((cmd) => { + const Icon = cmd.icon; + const isSelected = flatCommands[selectedIndex]?.id === cmd.id; + + return ( + + ); + })} +
+ )) + )} +
+ + {/* Footer */} +
+
+ + + + Navigate + + + + Select + +
+ + + K + Toggle + +
+
+
+ ); +} diff --git a/frontend/src/components/chat/ChatSidebar.tsx b/frontend/src/components/chat/ChatSidebar.tsx new file mode 100644 index 00000000..d269dfd2 --- /dev/null +++ b/frontend/src/components/chat/ChatSidebar.tsx @@ -0,0 +1,293 @@ +import { useState } from 'react'; +import { Link, useNavigate, useLocation } from 'react-router-dom'; +import { + Plus, + MessageSquare, + Folder, + Box, + Code, + Workflow, + Search, + Trash2, + ChevronDown, + ChevronRight, + Settings, + HelpCircle, +} from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { useChatStore, type ChatSession } from '@/store/chatStore'; +import { UserButton } from '@/components/auth/UserButton'; + +interface NavItemProps { + icon: React.ComponentType<{ className?: string }>; + label: string; + to: string; + active?: boolean; + badge?: string | number; +} + +const NavItem = ({ icon: Icon, label, to, active, badge }: NavItemProps) => ( + +
+ + {label} +
+ {badge && ( + + {badge} + + )} + +); + +interface ChatHistoryItemProps { + session: ChatSession; + isActive: boolean; + onSelect: () => void; + onDelete: () => void; + onRename: (title: string) => void; +} + +const ChatHistoryItem = ({ + session, + isActive, + onSelect, + onDelete, + onRename, +}: ChatHistoryItemProps) => { + const [isEditing, setIsEditing] = useState(false); + const [editTitle, setEditTitle] = useState(session.title); + + const handleRename = () => { + if (editTitle.trim() && editTitle.trim() !== session.title) { + onRename(editTitle.trim()); + } + setIsEditing(false); + }; + + const handleDelete = (e: React.MouseEvent) => { + e.stopPropagation(); + onDelete(); + }; + + const handleDoubleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + setEditTitle(session.title); + setIsEditing(true); + }; + + return ( +
+ + + {isEditing ? ( + setEditTitle(e.target.value)} + onBlur={handleRename} + onKeyDown={(e) => { + if (e.key === 'Enter') handleRename(); + if (e.key === 'Escape') { + setEditTitle(session.title); + setIsEditing(false); + } + }} + className="flex-1 bg-white/10 px-2 py-0.5 rounded text-sm text-white outline-none border border-white/20 min-w-0" + autoFocus + onClick={(e) => e.stopPropagation()} + /> + ) : ( + <> + + {session.title} + + {/* Delete button - inline in the row, appears on hover */} + + + )} +
+ ); +}; + +interface ChatSidebarProps { + className?: string; +} + +export function ChatSidebar({ className }: ChatSidebarProps) { + const navigate = useNavigate(); + const location = useLocation(); + const [searchQuery, setSearchQuery] = useState(''); + const [isHistoryExpanded, setIsHistoryExpanded] = useState(true); + + const { + sessions, + currentSessionId, + createSession, + deleteSession, + setCurrentSession, + updateSessionTitle, + } = useChatStore(); + + const filteredSessions = sessions.filter( + (session) => + session.title.toLowerCase().includes(searchQuery.toLowerCase()) || + session.messages.some((msg) => msg.content.toLowerCase().includes(searchQuery.toLowerCase())), + ); + + // Group sessions by date + const groupedSessions = filteredSessions.reduce( + (groups, session) => { + const date = new Date(session.updatedAt); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + let groupKey: string; + if (days === 0) groupKey = 'Today'; + else if (days === 1) groupKey = 'Yesterday'; + else if (days < 7) groupKey = 'Previous 7 Days'; + else if (days < 30) groupKey = 'Previous 30 Days'; + else groupKey = 'Older'; + + if (!groups[groupKey]) groups[groupKey] = []; + groups[groupKey].push(session); + return groups; + }, + {} as Record, + ); + + const handleNewChat = () => { + createSession(); + navigate('/'); + }; + + return ( +
+ {/* Header with New Chat */} +
+ + + {/* Search */} +
+ + setSearchQuery(e.target.value)} + placeholder="Search chats..." + className="w-full pl-9 pr-3 py-2 text-sm bg-white/5 border border-white/5 rounded-lg text-white placeholder:text-[#666] focus:outline-none focus:border-primary/50 focus:ring-1 focus:ring-primary/20 transition-all" + /> +
+
+ + {/* Navigation */} +
+ + + + + +
+ + {/* Chat History */} +
+ + + {isHistoryExpanded && ( +
+ {Object.entries(groupedSessions).length === 0 ? ( +
+ +

No chats yet

+

Start a new conversation

+
+ ) : ( + Object.entries(groupedSessions).map(([group, groupSessions]) => ( +
+
+ {group} +
+
+ {groupSessions.map((session) => ( + setCurrentSession(session.id)} + onDelete={() => deleteSession(session.id)} + onRename={(title) => updateSessionTitle(session.id, title)} + /> + ))} +
+
+ )) + )} +
+ )} +
+ + {/* Bottom Actions */} +
+ + + +
+ +
+
+
+ ); +} diff --git a/frontend/src/components/chat/SuggestedPrompts.tsx b/frontend/src/components/chat/SuggestedPrompts.tsx new file mode 100644 index 00000000..74306b6a --- /dev/null +++ b/frontend/src/components/chat/SuggestedPrompts.tsx @@ -0,0 +1,152 @@ +import { Zap, GraduationCap, Code, Coffee, Sparkles, Workflow, Bug, FileText } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { type SuggestedPrompt } from '@/store/chatStore'; + +const iconMap: Record> = { + Zap, + GraduationCap, + Code, + Coffee, + Sparkles, + Workflow, + Bug, + FileText, +}; + +// Extended prompts with more specific suggestions +export const extendedPrompts: SuggestedPrompt[] = [ + { + id: 'create-workflow', + icon: 'Workflow', + label: 'Create workflow', + prompt: 'Help me create a new workflow that', + category: 'workflow', + }, + { + id: 'write-code', + icon: 'Zap', + label: 'Write code', + prompt: 'Write code that', + category: 'code', + }, + { + id: 'learn', + icon: 'GraduationCap', + label: 'Learn', + prompt: 'Teach me about', + category: 'learn', + }, + { + id: 'analyze', + icon: 'Code', + label: 'Analyze', + prompt: 'Analyze this and provide insights:', + category: 'code', + }, + { + id: 'life-stuff', + icon: 'Coffee', + label: 'Life stuff', + prompt: 'Help me with', + category: 'general', + }, + { + id: 'surprise-me', + icon: 'Sparkles', + label: 'Surprise me', + prompt: 'Show me something interesting I can build with ShipSec workflows', + category: 'general', + }, +]; + +interface SuggestedPromptsProps { + onSelectPrompt: (prompt: string) => void; + className?: string; + variant?: 'pills' | 'cards'; +} + +export function SuggestedPrompts({ + onSelectPrompt, + className, + variant = 'pills', +}: SuggestedPromptsProps) { + if (variant === 'cards') { + return ( +
+ {extendedPrompts.slice(0, 6).map((prompt) => { + const Icon = iconMap[prompt.icon] || Sparkles; + return ( + + ); + })} +
+ ); + } + + return ( +
+ {extendedPrompts.map((prompt) => { + const Icon = iconMap[prompt.icon] || Sparkles; + return ( + + ); + })} +
+ ); +} + +interface QuickActionsBarProps { + onAction: (action: string) => void; + className?: string; +} + +export function QuickActionsBar({ onAction, className }: QuickActionsBarProps) { + const actions = [ + { id: 'new-workflow', icon: Workflow, label: 'New Workflow', command: 'Create a new workflow' }, + { id: 'debug', icon: Bug, label: 'Debug', command: 'Help me debug:' }, + { + id: 'docs', + icon: FileText, + label: 'Documentation', + command: 'Show me the documentation for', + }, + ]; + + return ( +
+ {actions.map((action) => { + const Icon = action.icon; + return ( + + ); + })} +
+ ); +} diff --git a/frontend/src/components/chat/WorkflowPreviewPanel.tsx b/frontend/src/components/chat/WorkflowPreviewPanel.tsx new file mode 100644 index 00000000..77edb29f --- /dev/null +++ b/frontend/src/components/chat/WorkflowPreviewPanel.tsx @@ -0,0 +1,218 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { + X, + Play, + Edit, + ExternalLink, + Clock, + AlertCircle, + Workflow, + Loader2, + Calendar, + FileCode, +} from 'lucide-react'; +import { useChatStore } from '@/store/chatStore'; +import { api } from '@/services/api'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; + +interface WorkflowDetails { + id: string; + name: string; + description?: string; + status?: string; + lastRun?: Date; + createdAt?: Date; + updatedAt?: Date; + nodeCount?: number; + version?: number; +} + +export function WorkflowPreviewPanel() { + const navigate = useNavigate(); + const [workflow, setWorkflow] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isRunning, setIsRunning] = useState(false); + + const { isWorkflowPreviewOpen, selectedWorkflowId, setWorkflowPreviewOpen, setSelectedWorkflow } = + useChatStore(); + + useEffect(() => { + if (selectedWorkflowId && isWorkflowPreviewOpen) { + loadWorkflow(selectedWorkflowId); + } + }, [selectedWorkflowId, isWorkflowPreviewOpen]); + + const loadWorkflow = async (id: string) => { + setIsLoading(true); + try { + const data = await api.workflows.get(id); + setWorkflow({ + id: data.id, + name: data.name, + description: data.description ?? undefined, + createdAt: data.createdAt ? new Date(data.createdAt) : undefined, + updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined, + version: data.currentVersion ?? undefined, + }); + } catch (error) { + console.error('Failed to load workflow', error); + } finally { + setIsLoading(false); + } + }; + + const handleRunWorkflow = async () => { + if (!workflow) return; + setIsRunning(true); + try { + await api.workflows.run(workflow.id); + // Could add a toast notification here + } catch (error) { + console.error('Failed to run workflow', error); + } finally { + setIsRunning(false); + } + }; + + const handleClose = () => { + setWorkflowPreviewOpen(false); + setSelectedWorkflow(null); + }; + + const handleOpenWorkflow = () => { + if (workflow) { + navigate(`/workflows/${workflow.id}`); + handleClose(); + } + }; + + if (!isWorkflowPreviewOpen || !selectedWorkflowId) return null; + + return ( +
+ {/* Header */} +
+
+
+ +
+
+

Workflow Preview

+

Quick actions & details

+
+
+ +
+ + {/* Content */} +
+ {isLoading ? ( +
+ +

Loading workflow...

+
+ ) : workflow ? ( + <> + {/* Workflow Name */} +
+

{workflow.name}

+ {workflow.description && ( +

{workflow.description}

+ )} +
+ + {/* Quick Actions */} +
+ + +
+ + {/* Workflow Info */} +
+

Details

+ +
+ {workflow.version && ( +
+ + Version + + v{workflow.version} + +
+ )} + + {workflow.createdAt && ( +
+ + Created + + {workflow.createdAt.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + })} + +
+ )} + + {workflow.updatedAt && ( +
+ + Updated + + {workflow.updatedAt.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + })} + +
+ )} +
+
+ + {/* Open Full View */} + + + ) : ( +
+ +

Workflow not found

+
+ )} +
+
+ ); +} diff --git a/frontend/src/components/chat/index.ts b/frontend/src/components/chat/index.ts new file mode 100644 index 00000000..8730e3c6 --- /dev/null +++ b/frontend/src/components/chat/index.ts @@ -0,0 +1,4 @@ +export { ChatSidebar } from './ChatSidebar'; +export { ChatCommandPalette } from './ChatCommandPalette'; +export { WorkflowPreviewPanel } from './WorkflowPreviewPanel'; +export { SuggestedPrompts, QuickActionsBar, extendedPrompts } from './SuggestedPrompts'; diff --git a/frontend/src/components/layout/AppLayout.tsx b/frontend/src/components/layout/AppLayout.tsx index bd0bf44f..25d45a73 100644 --- a/frontend/src/components/layout/AppLayout.tsx +++ b/frontend/src/components/layout/AppLayout.tsx @@ -23,6 +23,10 @@ import { Command, Zap, Webhook, + MessageSquare, + ChevronDown, + ChevronRight, + Trash2, } from 'lucide-react'; import React, { useState, useEffect, useCallback } from 'react'; import { useAuthStore } from '@/store/authStore'; @@ -34,6 +38,7 @@ import { useThemeStore } from '@/store/themeStore'; import { cn } from '@/lib/utils'; import { setMobilePlacementSidebarClose } from '@/components/layout/sidebar-state'; import { useCommandPaletteStore } from '@/store/commandPaletteStore'; +import { useChatStore } from '@/store/chatStore'; interface AppLayoutProps { children: React.ReactNode; @@ -61,11 +66,14 @@ function useIsMobile(breakpoint = 768) { export function AppLayout({ children }: AppLayoutProps) { const isMobile = useIsMobile(); + const location = useLocation(); + const navigate = useNavigate(); + // Check if we are on the Chat Interface (root path) + const isChatInterface = location.pathname === '/'; + const [sidebarOpen, setSidebarOpen] = useState(!isMobile); const [, setIsHovered] = useState(false); const [wasExplicitlyOpened, setWasExplicitlyOpened] = useState(!isMobile); - const location = useLocation(); - const navigate = useNavigate(); const roles = useAuthStore((state) => state.roles); const canManageWorkflows = hasAdminRole(roles); const { isAuthenticated } = useAuth(); @@ -74,6 +82,11 @@ export function AppLayout({ children }: AppLayoutProps) { const { theme, startTransition } = useThemeStore(); const openCommandPalette = useCommandPaletteStore((state) => state.open); + // Chat store for history in sidebar + const { sessions, currentSessionId, setCurrentSession, createSession, deleteSession } = + useChatStore(); + const [isChatHistoryExpanded, setIsChatHistoryExpanded] = useState(true); + // Get git SHA for version display (monorepo - same for frontend and backend) const gitSha = env.VITE_GIT_SHA; // If it's a tag (starts with v), show full tag. Otherwise show first 7 chars of SHA @@ -92,11 +105,18 @@ export function AppLayout({ children }: AppLayoutProps) { setWasExplicitlyOpened(false); } else { const isWorkflowRoute = - (location.pathname.startsWith('/workflows') || + (location.pathname.startsWith('/workflows/') || location.pathname.startsWith('/webhooks/')) && location.pathname !== '/'; - setSidebarOpen(!isWorkflowRoute); - setWasExplicitlyOpened(!isWorkflowRoute); + // For chat interface, maintain sidebar state based on user preference + if (location.pathname === '/') { + // Keep sidebar open by default on chat interface + setSidebarOpen(true); + setWasExplicitlyOpened(true); + } else { + setSidebarOpen(!isWorkflowRoute); + setWasExplicitlyOpened(!isWorkflowRoute); + } } }, [location.pathname, isMobile]); @@ -256,8 +276,13 @@ export function AppLayout({ children }: AppLayoutProps) { const navigationItems = [ { - name: 'Workflow Builder', + name: 'ShipSec AI', href: '/', + icon: MessageSquare, + }, + { + name: 'Workflow Builder', + href: '/workflows', icon: Workflow, }, { @@ -303,7 +328,10 @@ export function AppLayout({ children }: AppLayoutProps) { const isActive = (path: string) => { if (path === '/') { - return location.pathname === '/' || location.pathname.startsWith('/workflows'); + return location.pathname === '/'; + } + if (path === '/workflows') { + return location.pathname.startsWith('/workflows'); } return location.pathname === path || location.pathname.startsWith(`${path}/`); }; @@ -311,6 +339,23 @@ export function AppLayout({ children }: AppLayoutProps) { // Get page-specific actions const getPageActions = () => { if (location.pathname === '/') { + return ( + + ); + } + + if (location.pathname === '/workflows' || location.pathname.startsWith('/workflows')) { return ( + + {/* Search Button */} + + + )} + + {/* Search icon only when collapsed */} + {!sidebarOpen && ( +
+ +
+ )} + + {/* Navigation Items - Fixed */} +
{navigationItems.map((item) => { const Icon = item.icon; const active = isActive(item.href); @@ -404,17 +502,13 @@ export function AppLayout({ children }: AppLayoutProps) { key={item.href} to={item.href} onClick={(e) => { - // If modifier key is held (CMD+click, Ctrl+click), link opens in new tab - // Don't update sidebar state in this case if (e.metaKey || e.ctrlKey || e.shiftKey) { return; } - // Close sidebar on mobile after navigation if (isMobile) { setSidebarOpen(false); return; } - // Keep sidebar open when navigating to non-workflow routes (desktop) if (!item.href.startsWith('/workflows')) { setSidebarOpen(true); setWasExplicitlyOpened(true); @@ -447,38 +541,67 @@ export function AppLayout({ children }: AppLayoutProps) { })}
- {/* Command Palette Button */} -
- + + {isChatHistoryExpanded && ( +
+ {sessions.slice(0, 20).map((session) => ( +
+ + +
+ ))} +
)} - -
+ + )} @@ -554,8 +677,11 @@ export function AppLayout({ children }: AppLayoutProps) { isMobile ? 'w-full' : '', )} > - {/* Only show AppTopBar for non-workflow-builder and non-webhook-editor pages */} - {!location.pathname.startsWith('/workflows') && + {/* Show AppTopBar for: + - Non-chat pages (except workflow editor and webhook editor which have their own headers) + - Workflow list page (/workflows) to have "New Workflow" button */} + {!isChatInterface && + !(location.pathname.startsWith('/workflows/') && location.pathname !== '/workflows') && !location.pathname.startsWith('/webhooks/') && ( { it('renders code blocks', () => { const markdown = '```js\nconst x = 1\n```'; - render(); - expect(screen.getByText(/const x = 1/)).toBeInTheDocument(); + const { container } = render(); + // With syntax highlighting, text is split across multiple span elements + const codeBlock = container.querySelector('pre.code-block'); + expect(codeBlock).not.toBeNull(); + expect(codeBlock).toHaveAttribute('data-language', 'js'); + // Check that the code content exists (may be split across spans for highlighting) + const codeElement = codeBlock?.querySelector('code'); + expect(codeElement?.textContent).toContain('const'); + expect(codeElement?.textContent).toContain('x = 1'); }); }); diff --git a/frontend/src/components/ui/markdown.tsx b/frontend/src/components/ui/markdown.tsx index a1bd0091..39bfa348 100644 --- a/frontend/src/components/ui/markdown.tsx +++ b/frontend/src/components/ui/markdown.tsx @@ -1,9 +1,11 @@ -import React, { memo, useMemo, useCallback, useRef } from 'react'; +import React, { memo, useMemo, useCallback, useRef, useEffect, useState } from 'react'; import MarkdownIt from 'markdown-it'; import markdownItLinkAttributes from 'markdown-it-link-attributes'; import markdownItTaskLists from 'markdown-it-task-lists'; import markdownItHTML5Embed from 'markdown-it-html5-embed'; import markdownItImsize from '@/lib/markdown-it-imsize'; +import hljs from 'highlight.js'; +import mermaid from 'mermaid'; import { cn } from '@/lib/utils'; interface MarkdownViewProps { @@ -15,11 +17,96 @@ interface MarkdownViewProps { onEdit?: (next: string) => void; } -// Initialize markdown-it with plugins (similar to n8n sticky notes) +// Initialize mermaid with theme detection +let mermaidInitialized = false; +const initMermaid = () => { + if (mermaidInitialized) return; + + const isDark = document.documentElement.classList.contains('dark'); + mermaid.initialize({ + startOnLoad: false, + theme: isDark ? 'dark' : 'default', + securityLevel: 'loose', + fontFamily: 'inherit', + flowchart: { + useMaxWidth: true, + htmlLabels: true, + curve: 'basis', + }, + themeVariables: isDark + ? { + primaryColor: '#f97316', + primaryTextColor: '#fff', + primaryBorderColor: '#f97316', + lineColor: '#666', + secondaryColor: '#374151', + tertiaryColor: '#1f2937', + background: '#171717', + mainBkg: '#1f2937', + nodeBorder: '#f97316', + textColor: '#e5e7eb', + } + : { + primaryColor: '#f97316', + primaryTextColor: '#000', + primaryBorderColor: '#f97316', + lineColor: '#374151', + secondaryColor: '#f3f4f6', + tertiaryColor: '#e5e7eb', + }, + }); + mermaidInitialized = true; +}; + +// Helper function to escape HTML - standalone to avoid circular reference +function escapeHtml(str: string): string { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +// Syntax highlighting function with explicit return type +function highlightCode(str: string, lang: string): string { + // Handle mermaid diagrams - return placeholder that will be processed + if (lang === 'mermaid') { + const id = `mermaid-${Math.random().toString(36).substring(2, 11)}`; + return `
${str.replace(//g, '>')}
`; + } + + // Syntax highlighting for code blocks + if (lang && hljs.getLanguage(lang)) { + try { + const highlighted = hljs.highlight(str, { + language: lang, + ignoreIllegals: true, + }).value; + return `
${lang}
${highlighted}
`; + } catch (e) { + console.error('Highlight error:', e); + } + } + + // Auto-detect language if not specified + try { + const detected = hljs.highlightAuto(str); + const language = detected.language || 'text'; + return `
${language}
${detected.value}
`; + } catch (e) { + console.error('Highlight auto error:', e); + } + + // Fallback to plain code block + return `
text
${escapeHtml(str)}
`; +} + +// Initialize markdown-it with plugins and syntax highlighting const md = new MarkdownIt({ html: true, // Enable HTML for embeds (iframes are sanitized by the plugin) breaks: true, // Convert line breaks to
linkify: true, // Auto-convert URLs to links + highlight: highlightCode, }) .use(markdownItTaskLists, { enabled: true, @@ -107,6 +194,8 @@ export const MarkdownView = memo(function MarkdownView({ // Store onEdit in a ref so we can use a stable callback without re-renders const onEditRef = useRef(onEdit); onEditRef.current = onEdit; + const containerRef = useRef(null); + const [copiedCode, setCopiedCode] = useState(null); // Normalize common markdown typos const normalized: string = useMemo( @@ -122,59 +211,111 @@ export const MarkdownView = memo(function MarkdownView({ return rendered.replace(/(]*type="checkbox"[^>]*)disabled([^>]*>)/g, '$1$2'); }, [normalized]); + // Initialize mermaid and render diagrams + useEffect(() => { + initMermaid(); + + const container = containerRef.current; + if (!container) return; + + // Find and render mermaid diagrams + const mermaidDiagrams = container.querySelectorAll('.mermaid-diagram'); + mermaidDiagrams.forEach(async (diagram) => { + const id = diagram.getAttribute('data-mermaid-id'); + const code = diagram.textContent; + + if (id && code && !diagram.querySelector('svg')) { + try { + const { svg } = await mermaid.render(id, code); + diagram.innerHTML = svg; + diagram.classList.add('mermaid-rendered'); + } catch (error) { + console.error('Mermaid render error:', error); + diagram.innerHTML = `
Failed to render diagram
${code}
`; + } + } + }); + }, [html]); + + // Handle copy button clicks + const handleCopyClick = useCallback(async (code: string) => { + try { + await navigator.clipboard.writeText(code); + setCopiedCode(code); + setTimeout(() => setCopiedCode(null), 2000); + } catch (error) { + console.error('Failed to copy:', error); + } + }, []); + // Handle clicks on interactive elements - use useCallback for stable reference - const handleClick = useCallback((e: React.MouseEvent) => { - const target = e.target as HTMLElement; + const handleClick = useCallback( + (e: React.MouseEvent) => { + const target = e.target as HTMLElement; - // Handle checkbox clicks for interactive task lists - if (target.tagName === 'INPUT' && target.getAttribute('type') === 'checkbox') { - if (!onEditRef.current) { - // Even if not editable, prevent checkbox toggle and stop propagation + // Handle copy button clicks + if (target.closest('.copy-button')) { e.preventDefault(); e.stopPropagation(); + const button = target.closest('.copy-button') as HTMLButtonElement; + const code = button.getAttribute('data-code'); + if (code) { + handleCopyClick(decodeURIComponent(code)); + } return; } - e.preventDefault(); - e.stopPropagation(); + // Handle checkbox clicks for interactive task lists + if (target.tagName === 'INPUT' && target.getAttribute('type') === 'checkbox') { + if (!onEditRef.current) { + // Even if not editable, prevent checkbox toggle and stop propagation + e.preventDefault(); + e.stopPropagation(); + return; + } - // Find which checkbox was clicked - const container = e.currentTarget as HTMLDivElement; - const checkboxes = container.querySelectorAll('input[type="checkbox"]'); - const index = Array.from(checkboxes).indexOf(target as HTMLInputElement); + e.preventDefault(); + e.stopPropagation(); - if (index !== -1) { - // Get current normalized content for toggling - const currentContent = (container as any).__markdownContent || ''; - const toggled = toggleNthTask(currentContent, index); + // Find which checkbox was clicked + const container = e.currentTarget as HTMLDivElement; + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + const index = Array.from(checkboxes).indexOf(target as HTMLInputElement); - // 1. Toggle the checkbox visually in the DOM (prevents flicker) - const checkbox = target as HTMLInputElement; - checkbox.checked = !checkbox.checked; + if (index !== -1) { + // Get current normalized content for toggling + const currentContent = (container as any).__markdownContent || ''; + const toggled = toggleNthTask(currentContent, index); - // 2. Update the stored content so future toggles work correctly - (container as any).__markdownContent = toggled; + // 1. Toggle the checkbox visually in the DOM (prevents flicker) + const checkbox = target as HTMLInputElement; + checkbox.checked = !checkbox.checked; - // 3. Register expected content to skip the re-render when parent updates - const key = (container as any).__dataTestId || '__default__'; - pendingCheckboxUpdates.set(key, toggled); + // 2. Update the stored content so future toggles work correctly + (container as any).__markdownContent = toggled; - // 4. Notify parent of the change (for persistence) - onEditRef.current(toggled); + // 3. Register expected content to skip the re-render when parent updates + const key = (container as any).__dataTestId || '__default__'; + pendingCheckboxUpdates.set(key, toggled); + + // 4. Notify parent of the change (for persistence) + onEditRef.current(toggled); + } + return; } - return; - } - // For links, allow default behavior (open in new tab) but stop propagation - // to prevent parent node from being selected - if (target.tagName === 'A' || target.closest('a')) { - e.stopPropagation(); - return; - } + // For links, allow default behavior (open in new tab) but stop propagation + // to prevent parent node from being selected + if (target.tagName === 'A' || target.closest('a')) { + e.stopPropagation(); + return; + } - // Stop all other clicks from bubbling to prevent triggering parent handlers - e.stopPropagation(); - }, []); + // Stop all other clicks from bubbling to prevent triggering parent handlers + e.stopPropagation(); + }, + [handleCopyClick], + ); // Use capture phase for mousedown to intercept before React Flow can handle it const handleMouseDown = useCallback((e: React.MouseEvent) => { @@ -190,10 +331,14 @@ export const MarkdownView = memo(function MarkdownView({ if (target.tagName === 'A' || target.closest('a')) { e.stopPropagation(); } + + // For copy buttons + if (target.closest('.copy-button')) { + e.stopPropagation(); + } }, []); // Store normalized content and dataTestId on the DOM element for the click handler - const containerRef = useRef(null); const setRef = (el: HTMLDivElement | null) => { containerRef.current = el; if (el) { @@ -208,10 +353,31 @@ export const MarkdownView = memo(function MarkdownView({ e.stopPropagation(); }, []); + // Update copy button states + useEffect(() => { + const container = containerRef.current; + if (!container || !copiedCode) return; + + const copyButtons = container.querySelectorAll('.copy-button'); + copyButtons.forEach((button) => { + const code = button.getAttribute('data-code'); + const textSpan = button.querySelector('.copy-text'); + if (code && textSpan) { + if (decodeURIComponent(code) === copiedCode) { + textSpan.textContent = 'Copied!'; + button.classList.add('copied'); + } else { + textSpan.textContent = 'Copy'; + button.classList.remove('copied'); + } + } + }); + }, [copiedCode]); + return (
div { +.config-panel > div { scroll-behavior: smooth; } @@ -200,7 +208,7 @@ textarea { } .dark .status-success { - color: #4ADE80; + color: #4ade80; /* Accent Success */ } @@ -210,7 +218,7 @@ textarea { } .dark .status-error { - color: #EF4444; + color: #ef4444; /* Accent Error */ } @@ -220,7 +228,7 @@ textarea { } .dark .status-info { - color: #3C82F6; + color: #3c82f6; /* Accent Blue */ } @@ -230,7 +238,7 @@ textarea { } .dark .status-warning { - color: #FACC15; + color: #facc15; /* Accent Warning */ } @@ -267,7 +275,9 @@ textarea { /* Enhanced table row hover effects */ table tbody tr { - transition: background-color 0.15s ease, box-shadow 0.15s ease; + transition: + background-color 0.15s ease, + box-shadow 0.15s ease; } table tbody tr:hover { @@ -284,7 +294,9 @@ table tbody tr:hover { background-color: hsl(var(--card)) !important; border: 1px solid hsl(var(--border)) !important; border-radius: 0.375rem !important; - box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3), 0 2px 4px -2px rgb(0 0 0 / 0.2) !important; + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 0.3), + 0 2px 4px -2px rgb(0 0 0 / 0.2) !important; } .dark .react-flow__controls-button { @@ -315,7 +327,9 @@ table tbody tr:hover { background-color: hsl(var(--card)) !important; border: 1px solid hsl(var(--border)) !important; border-radius: 0.375rem !important; - box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3), 0 2px 4px -2px rgb(0 0 0 / 0.2) !important; + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 0.3), + 0 2px 4px -2px rgb(0 0 0 / 0.2) !important; } .dark .react-flow__minimap svg { @@ -467,7 +481,9 @@ table tbody tr:hover { border-radius: 2px; background: hsl(var(--border)); opacity: 0.6; - transition: opacity 0.15s, background-color 0.15s; + transition: + opacity 0.15s, + background-color 0.15s; } .timeline-resize-handle:hover::after { @@ -480,7 +496,11 @@ table tbody tr:hover { --text-node-handle-size: 28px; --text-node-handle-radius: var(--radius, 0.5rem); --text-node-handle-offset: calc((var(--text-node-handle-size) / 2) - 1px); - --text-node-handle-color-default: color-mix(in srgb, hsl(var(--border)) 70%, hsl(var(--foreground)) 30%); + --text-node-handle-color-default: color-mix( + in srgb, + hsl(var(--border)) 70%, + hsl(var(--foreground)) 30% + ); --text-node-handle-color-active: hsl(var(--primary)); --text-node-handle-color: var(--text-node-handle-color-default); --text-node-handle-opacity: 0.85; @@ -508,7 +528,10 @@ table tbody tr:hover { border: 2px solid transparent; opacity: var(--text-node-handle-opacity); pointer-events: none; - transition: border-color 0.15s ease, opacity 0.15s ease, transform 0.15s ease; + transition: + border-color 0.15s ease, + opacity 0.15s ease, + transform 0.15s ease; transform: scale(var(--text-node-handle-scale)); } @@ -547,11 +570,558 @@ table tbody tr:hover { .text-node-resize-line.react-flow__resize-control.line { border-color: transparent; opacity: 0; - transition: border-color 0.15s ease, opacity 0.15s ease; + transition: + border-color 0.15s ease, + opacity 0.15s ease; } .text-node-resize-line.react-flow__resize-control.line:hover, .text-node-resize-line.react-flow__resize-control.line:active { border-color: hsl(var(--primary)); opacity: 1; -} \ No newline at end of file +} + +/* ===== Chat Interface Styles ===== */ + +/* Chat scrollbar styling */ +.chat-scrollbar::-webkit-scrollbar { + width: 6px; +} + +.chat-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.chat-scrollbar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 3px; +} + +.chat-scrollbar::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.2); +} + +/* Chat message animations */ +@keyframes messageSlideIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.chat-message-enter { + animation: messageSlideIn 0.3s ease-out forwards; +} + +/* Typing indicator animation */ +@keyframes typingPulse { + 0%, + 60%, + 100% { + opacity: 0.4; + } + 30% { + opacity: 1; + } +} + +.typing-dot { + animation: typingPulse 1.4s ease-in-out infinite; +} + +.typing-dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-dot:nth-child(3) { + animation-delay: 0.4s; +} + +/* Smooth sidebar transitions */ +.chat-sidebar { + transition: + transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), + width 0.3s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s ease; +} + +/* Chat input focus glow */ +.chat-input-container:focus-within { + box-shadow: + 0 0 0 2px rgba(251, 146, 60, 0.1), + 0 4px 20px rgba(0, 0, 0, 0.3); +} + +/* Suggested prompt hover effects */ +.suggestion-pill { + transition: all 0.2s ease; +} + +.suggestion-pill:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +/* Command palette backdrop blur */ +.command-palette-overlay { + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} + +/* Workflow preview panel slide animation */ +@keyframes slideInFromRight { + from { + opacity: 0; + transform: translateX(100%); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.workflow-preview-enter { + animation: slideInFromRight 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; +} + +/* Chat history item hover state */ +.chat-history-item { + transition: + background-color 0.15s ease, + transform 0.15s ease; +} + +.chat-history-item:hover { + transform: translateX(2px); +} + +/* Gradient text for headings */ +.gradient-text { + background: linear-gradient(135deg, #fff 0%, rgba(255, 255, 255, 0.7) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* Smooth focus transitions for inputs */ +.chat-input { + transition: + box-shadow 0.2s ease, + border-color 0.2s ease; +} + +/* Avatar glow effect */ +.avatar-glow { + box-shadow: 0 0 20px rgba(251, 146, 60, 0.2); +} + +/* Message code block styling */ +.chat-message pre { + background: rgba(255, 255, 255, 0.03) !important; + border: 1px solid rgba(255, 255, 255, 0.08) !important; + border-radius: 12px !important; +} + +.chat-message code { + font-family: 'IBM Plex Mono', monospace; +} + +/* ===== Enhanced Markdown Styles ===== */ + +/* Markdown content container */ +.markdown-content { + line-height: 1.7; + word-wrap: break-word; + overflow-wrap: break-word; +} + +.markdown-content > *:first-child { + margin-top: 0; +} + +.markdown-content > *:last-child { + margin-bottom: 0; +} + +/* Headings */ +.markdown-content h1, +.markdown-content h2, +.markdown-content h3, +.markdown-content h4, +.markdown-content h5, +.markdown-content h6 { + font-weight: 600; + line-height: 1.3; + margin-top: 1.5em; + margin-bottom: 0.75em; + color: hsl(var(--foreground)); +} + +.markdown-content h1 { font-size: 1.75em; } +.markdown-content h2 { font-size: 1.5em; } +.markdown-content h3 { font-size: 1.25em; } +.markdown-content h4 { font-size: 1.125em; } +.markdown-content h5 { font-size: 1em; } +.markdown-content h6 { font-size: 0.875em; } + +/* Paragraphs */ +.markdown-content p { + margin: 0.75em 0; +} + +/* Links */ +.markdown-content a { + color: hsl(var(--primary)); + text-decoration: none; + transition: color 0.2s ease; +} + +.markdown-content a:hover { + color: hsl(var(--primary) / 0.8); + text-decoration: underline; +} + +/* Lists */ +.markdown-content ul, +.markdown-content ol { + padding-left: 1.5em; + margin: 0.75em 0; +} + +.markdown-content li { + margin: 0.25em 0; +} + +.markdown-content ul { + list-style-type: disc; +} + +.markdown-content ol { + list-style-type: decimal; +} + +/* Blockquotes */ +.markdown-content blockquote { + border-left: 4px solid hsl(var(--primary) / 0.5); + padding-left: 1em; + margin: 1em 0; + color: hsl(var(--muted-foreground)); + font-style: italic; + background: hsl(var(--muted) / 0.3); + padding: 0.75em 1em; + border-radius: 0 0.5rem 0.5rem 0; +} + +/* Inline code */ +.markdown-content code:not(pre code) { + background: hsl(var(--muted)); + padding: 0.2em 0.4em; + border-radius: 0.25rem; + font-size: 0.875em; + font-family: 'IBM Plex Mono', monospace; + color: hsl(var(--primary)); + border: 1px solid hsl(var(--border)); +} + +/* Code blocks with syntax highlighting */ +.markdown-content pre.hljs.code-block { + position: relative; + background: hsl(var(--card)); + border: 1px solid hsl(var(--border)); + border-radius: 0.75rem; + margin: 1em 0; + overflow: hidden; +} + +.markdown-content pre.hljs.code-block .code-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.5rem 1rem; + background: hsl(var(--muted) / 0.5); + border-bottom: 1px solid hsl(var(--border) / 0.5); +} + +.markdown-content pre.hljs.code-block .code-language { + font-size: 0.75rem; + font-weight: 500; + text-transform: uppercase; + color: hsl(var(--muted-foreground)); + font-family: 'IBM Plex Mono', monospace; +} + +.markdown-content pre.hljs.code-block .copy-button { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: hsl(var(--muted-foreground)); + background: hsl(var(--background) / 0.5); + border: 1px solid hsl(var(--border)); + border-radius: 0.375rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.markdown-content pre.hljs.code-block .copy-button:hover { + color: hsl(var(--foreground)); + background: hsl(var(--accent)); + border-color: hsl(var(--border)); +} + +.markdown-content pre.hljs.code-block .copy-button.copied { + color: hsl(var(--color-success)); + border-color: hsl(var(--color-success) / 0.5); +} + +.markdown-content pre.hljs.code-block .copy-button .copy-icon { + flex-shrink: 0; +} + +.markdown-content pre.hljs.code-block code { + display: block; + padding: 1rem; + overflow-x: auto; + font-family: 'IBM Plex Mono', monospace; + font-size: 0.875rem; + line-height: 1.6; + color: hsl(var(--foreground)); +} + +/* Scrollbar for code blocks */ +.markdown-content pre.hljs.code-block code::-webkit-scrollbar { + height: 6px; +} + +.markdown-content pre.hljs.code-block code::-webkit-scrollbar-track { + background: transparent; +} + +.markdown-content pre.hljs.code-block code::-webkit-scrollbar-thumb { + background: hsl(var(--border)); + border-radius: 3px; +} + +/* ===== Syntax Highlighting Theme ===== */ + +/* Light theme colors */ +.markdown-content .hljs-comment, +.markdown-content .hljs-quote { + color: #6a737d; + font-style: italic; +} + +.markdown-content .hljs-keyword, +.markdown-content .hljs-selector-tag { + color: #d73a49; +} + +.markdown-content .hljs-string, +.markdown-content .hljs-template-literal, +.markdown-content .hljs-addition { + color: #22863a; +} + +.markdown-content .hljs-number, +.markdown-content .hljs-literal, +.markdown-content .hljs-variable, +.markdown-content .hljs-template-variable, +.markdown-content .hljs-tag .hljs-attr { + color: #005cc5; +} + +.markdown-content .hljs-function, +.markdown-content .hljs-title { + color: #6f42c1; +} + +.markdown-content .hljs-built_in, +.markdown-content .hljs-type { + color: #e36209; +} + +.markdown-content .hljs-class .hljs-title, +.markdown-content .hljs-title.class_ { + color: #6f42c1; +} + +.markdown-content .hljs-attribute, +.markdown-content .hljs-symbol { + color: #005cc5; +} + +.markdown-content .hljs-meta, +.markdown-content .hljs-selector-id, +.markdown-content .hljs-selector-class { + color: #e36209; +} + +.markdown-content .hljs-deletion { + color: #b31d28; + background: #ffeef0; +} + +/* Dark theme colors */ +.dark .markdown-content .hljs-comment, +.dark .markdown-content .hljs-quote { + color: #8b949e; + font-style: italic; +} + +.dark .markdown-content .hljs-keyword, +.dark .markdown-content .hljs-selector-tag { + color: #ff7b72; +} + +.dark .markdown-content .hljs-string, +.dark .markdown-content .hljs-template-literal, +.dark .markdown-content .hljs-addition { + color: #7ee787; +} + +.dark .markdown-content .hljs-number, +.dark .markdown-content .hljs-literal, +.dark .markdown-content .hljs-variable, +.dark .markdown-content .hljs-template-variable, +.dark .markdown-content .hljs-tag .hljs-attr { + color: #79c0ff; +} + +.dark .markdown-content .hljs-function, +.dark .markdown-content .hljs-title { + color: #d2a8ff; +} + +.dark .markdown-content .hljs-built_in, +.dark .markdown-content .hljs-type { + color: #ffa657; +} + +.dark .markdown-content .hljs-class .hljs-title, +.dark .markdown-content .hljs-title.class_ { + color: #d2a8ff; +} + +.dark .markdown-content .hljs-attribute, +.dark .markdown-content .hljs-symbol { + color: #79c0ff; +} + +.dark .markdown-content .hljs-meta, +.dark .markdown-content .hljs-selector-id, +.dark .markdown-content .hljs-selector-class { + color: #ffa657; +} + +.dark .markdown-content .hljs-deletion { + color: #ffa198; + background: rgba(248, 81, 73, 0.2); +} + +/* ===== Mermaid Diagram Styles ===== */ + +.markdown-content .mermaid-diagram { + background: hsl(var(--muted) / 0.3); + border: 1px solid hsl(var(--border)); + border-radius: 0.75rem; + padding: 1.5rem; + margin: 1em 0; + overflow-x: auto; + text-align: center; +} + +.markdown-content .mermaid-diagram.mermaid-rendered { + background: hsl(var(--card) / 0.5); +} + +.markdown-content .mermaid-diagram svg { + max-width: 100%; + height: auto; +} + +.markdown-content .mermaid-error { + color: hsl(var(--destructive)); + font-size: 0.875rem; + padding: 0.5rem; + margin-bottom: 0.5rem; + background: hsl(var(--destructive) / 0.1); + border-radius: 0.375rem; +} + +.markdown-content .mermaid-error + pre { + margin-top: 0.5rem; + padding: 0.75rem; + background: hsl(var(--muted)); + border-radius: 0.375rem; + font-size: 0.75rem; + color: hsl(var(--muted-foreground)); +} + +/* Table styles */ +.markdown-content table { + width: 100%; + border-collapse: collapse; + margin: 1em 0; + font-size: 0.875rem; +} + +.markdown-content th, +.markdown-content td { + padding: 0.625rem 0.75rem; + border: 1px solid hsl(var(--border)); + text-align: left; +} + +.markdown-content th { + background: hsl(var(--muted) / 0.5); + font-weight: 600; +} + +.markdown-content tr:nth-child(even) { + background: hsl(var(--muted) / 0.2); +} + +/* Horizontal rule */ +.markdown-content hr { + border: none; + height: 1px; + background: hsl(var(--border)); + margin: 2em 0; +} + +/* Images */ +.markdown-content img { + max-width: 100%; + height: auto; + border-radius: 0.5rem; + margin: 1em 0; +} + +/* Task lists */ +.markdown-content .task-list-item { + list-style: none; + margin-left: -1.5em; +} + +.markdown-content .task-list-item input[type="checkbox"] { + margin-right: 0.5em; + width: 1em; + height: 1em; + cursor: pointer; + accent-color: hsl(var(--primary)); +} + +/* Strong and emphasis */ +.markdown-content strong { + font-weight: 600; + color: hsl(var(--foreground)); +} + +.markdown-content em { + font-style: italic; +} diff --git a/frontend/src/pages/ChatInterface.tsx b/frontend/src/pages/ChatInterface.tsx new file mode 100644 index 00000000..1628a9eb --- /dev/null +++ b/frontend/src/pages/ChatInterface.tsx @@ -0,0 +1,543 @@ +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { + Plus, + Sparkles, + Paperclip, + ArrowUp, + Command, + Bot, + User, + ChevronDown, + Loader2, + PanelLeftClose, + PanelLeftOpen, +} from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Avatar, AvatarFallback } from '@/components/ui/avatar'; +import { cn } from '@/lib/utils'; +import { Link } from 'react-router-dom'; +import { MarkdownView as Markdown } from '@/components/ui/markdown'; +import { ChatCommandPalette, WorkflowPreviewPanel, SuggestedPrompts } from '@/components/chat'; +import { useChatStore, type ChatMessage } from '@/store/chatStore'; +import { useAuth } from '@/auth/auth-context'; +import { useSidebar } from '@/components/layout/sidebar-context'; + +// Get time-based greeting +function getGreeting(): string { + const hour = new Date().getHours(); + if (hour < 12) return 'Good morning'; + if (hour < 18) return 'Good afternoon'; + return 'Good evening'; +} + +// Get user's first name or fallback +function getUserName(user: { email?: string; firstName?: string | null } | null): string { + if (!user) return 'there'; + if (user.firstName) return user.firstName; + if (user.email) return user.email.split('@')[0]; + return 'there'; +} + +// Message component +interface ChatMessageProps { + message: ChatMessage; +} + +function ChatMessageItem({ message }: ChatMessageProps) { + const isAssistant = message.role === 'assistant'; + const isLoading = message.metadata?.isLoading; + + return ( +
+ {/* Avatar */} + + {isAssistant ? ( + + + + ) : ( + + + + )} + + + {/* Message Content */} +
+
+ + {isAssistant ? 'ShipSec AI' : 'You'} + + + {new Date(message.timestamp).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + })} + +
+ +
+ {isLoading ? ( +
+ + Thinking... +
+ ) : ( + + )} +
+ + {message.metadata?.error && ( +
+ {message.metadata.error} +
+ )} +
+
+ ); +} + +// Empty state component +interface EmptyStateProps { + userName: string; + onSelectPrompt: (prompt: string) => void; +} + +function EmptyState({ userName, onSelectPrompt }: EmptyStateProps) { + return ( +
+ {/* Plan Badge */} +
+ + Free plan ·{' '} + + Upgrade + + +
+ + {/* Greeting */} +

+ + + + {getGreeting()}, {userName} + + +

+ +

+ How can I help you today? +

+ + {/* Suggested Prompts */} +
+ +
+
+ ); +} + +// Main Chat Interface +export function ChatInterface() { + const [input, setInput] = useState(''); + const [isTyping, setIsTyping] = useState(false); + const messagesEndRef = useRef(null); + const inputRef = useRef(null); + + const { user } = useAuth(); + const { + sessions, + currentSessionId, + createSession, + addMessage, + updateMessage, + getCurrentSession, + setCommandPaletteOpen, + } = useChatStore(); + + const currentSession = getCurrentSession(); + const messages = currentSession?.messages ?? []; + + // Auto-create session if none exists + useEffect(() => { + if (sessions.length === 0) { + createSession(); + } + }, [sessions.length, createSession]); + + // Scroll to bottom on new messages + const scrollToBottom = useCallback(() => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, []); + + useEffect(() => { + scrollToBottom(); + }, [messages, scrollToBottom]); + + // Auto-resize textarea + const handleInputChange = (e: React.ChangeEvent) => { + setInput(e.target.value); + // Auto-resize + e.target.style.height = 'auto'; + e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px'; + }; + + // Handle prompt selection + const handleSelectPrompt = useCallback((prompt: string) => { + setInput(prompt + ' '); + inputRef.current?.focus(); + }, []); + + // Send message + const handleSendMessage = useCallback( + (e?: React.FormEvent) => { + e?.preventDefault(); + + const trimmedInput = input.trim(); + if (!trimmedInput || !currentSessionId) return; + + // Add user message + addMessage(currentSessionId, { + role: 'user', + content: trimmedInput, + }); + + setInput(''); + if (inputRef.current) { + inputRef.current.style.height = 'auto'; + } + + // Add loading assistant message + addMessage(currentSessionId, { + role: 'assistant', + content: '', + metadata: { isLoading: true }, + }); + + // Simulate AI response (replace with actual API call) + setIsTyping(true); + setTimeout(() => { + // Get the last message and update it + const session = useChatStore.getState().sessions.find((s) => s.id === currentSessionId); + const lastMessage = session?.messages[session.messages.length - 1]; + + if (lastMessage && lastMessage.role === 'assistant') { + updateMessage(currentSessionId, lastMessage.id, { + content: generateMockResponse(trimmedInput), + metadata: { isLoading: false }, + }); + } + setIsTyping(false); + }, 1500); + }, + [input, currentSessionId, addMessage, updateMessage], + ); + + // Handle keyboard shortcuts + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + // Send on Enter (without Shift) + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSendMessage(); + } + + // Open command palette on / + if (e.key === '/' && input === '') { + e.preventDefault(); + setCommandPaletteOpen(true); + } + }, + [handleSendMessage, input, setCommandPaletteOpen], + ); + + const { isOpen: sidebarOpen, toggle: toggleSidebar } = useSidebar(); + + return ( +
+ {/* Header with sidebar toggle */} +
+ +

ShipSec AI

+
+ + {/* Content Area */} +
+ {messages.length === 0 ? ( + + ) : ( +
+
+ {messages.map((msg) => ( + + ))} +
+
+
+ )} + + {/* Input Area */} +
+
+ {/* Input Container */} +
+
+