diff --git a/bun.lock b/bun.lock index eacd663d8..a0d5acf67 100644 --- a/bun.lock +++ b/bun.lock @@ -18,6 +18,7 @@ "file-type": "^22.0.0", "hast-util-to-jsx-runtime": "^2", "html-url-attributes": "^3", + "mermaid": "^12.0.0", "openai": "^6.34.0", "remark-parse": "^11", "remark-rehype": "^11", @@ -70,6 +71,8 @@ "packages": { "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@antfu/install-pkg": ["@antfu/install-pkg@2.0.1", "", { "dependencies": { "package-manager-detector": "^1.7.0", "tinyexec": "^1.2.4" } }, "sha512-iCKVQcIC0e3oDxEfs3SHQGW+ovhBMZmS1TE+bTk50rVyMCBmCfClv7Qi3HQKlumYwvjb/iIMeWCW2i67q6kFfQ=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.257", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.257", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.257", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.257", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.257", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.257", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.257", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.257", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.257" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-Se55zXv48IYLg/WzoXzpbPLcq86suwDSbRUoNb69l4dkovorqS/47Xuy7MUo/gPNwwcPB4a+aqbXbshU33dcdQ=="], "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.257", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ITjFPYB8riu9tbxbrWArokiZ/90w/NDrYbtEvyr3ScilVtu1iupkComxkhvbUxoyT4JRDpKsdw/ZOfwSl/pkpA=="], @@ -170,6 +173,18 @@ "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], + "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], + + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@11.1.2", "", { "dependencies": { "@chevrotain/gast": "11.1.2", "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q=="], + + "@chevrotain/gast": ["@chevrotain/gast@11.1.2", "", { "dependencies": { "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g=="], + + "@chevrotain/regexp-to-ast": ["@chevrotain/regexp-to-ast@11.1.2", "", {}, "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw=="], + + "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="], + + "@chevrotain/utils": ["@chevrotain/utils@11.1.2", "", {}, "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA=="], + "@dnd-kit/accessibility": ["@dnd-kit/accessibility@3.1.1", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw=="], "@dnd-kit/core": ["@dnd-kit/core@6.3.1", "", { "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ=="], @@ -244,6 +259,10 @@ "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + + "@iconify/utils": ["@iconify/utils@3.1.7", "", { "dependencies": { "@antfu/install-pkg": "^2.0.1", "@iconify/types": "^2.0.0", "import-meta-resolve": "^4.2.0" } }, "sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -284,6 +303,8 @@ "@mariozechner/pi-tui": ["@mariozechner/pi-tui@0.73.1", "", { "dependencies": { "@types/mime-types": "^2.1.4", "chalk": "^5.5.0", "get-east-asian-width": "^1.3.0", "marked": "^15.0.12", "mime-types": "^3.0.1" }, "optionalDependencies": { "koffi": "^2.9.0" } }, "sha512-ybVsRnUbzQRtbocltJ2OXb2QogrO67N2BlUyKjZz9BHcZYiDJtNkcKQockxDjsVvDc0uBCLDX6iZJoBElBd8fw=="], + "@mermaid-js/parser": ["@mermaid-js/parser@2.0.0", "", { "dependencies": { "@chevrotain/types": "~11.1.2" } }, "sha512-K8BeapFUfrfxbRAUQAG5oBOCwo1+bNWzaVnPxTCutkfrTBn6T/j91FIhqxWJ32SUeQ9T3iy1zcmPZ5ROZEvDrg=="], + "@mistralai/mistralai": ["@mistralai/mistralai@2.5.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.40.0", "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-S/r6tkiUHblaDJGsb84WS0ePTF2YHVta2EoTi1NJqHNt5mfRRS2uE4v7hCYV134+an+fk6WgG3+aFfinJbQBjQ=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "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.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "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.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], @@ -514,12 +535,76 @@ "@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="], + "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="], + + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-axis": ["@types/d3-axis@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw=="], + + "@types/d3-brush": ["@types/d3-brush@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A=="], + + "@types/d3-chord": ["@types/d3-chord@3.0.6", "", {}, "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-contour": ["@types/d3-contour@3.0.6", "", { "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg=="], + + "@types/d3-delaunay": ["@types/d3-delaunay@6.0.4", "", {}, "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="], + + "@types/d3-dispatch": ["@types/d3-dispatch@3.0.7", "", {}, "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="], + + "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], + + "@types/d3-dsv": ["@types/d3-dsv@3.0.7", "", {}, "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-fetch": ["@types/d3-fetch@3.0.7", "", { "dependencies": { "@types/d3-dsv": "*" } }, "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA=="], + + "@types/d3-force": ["@types/d3-force@3.0.10", "", {}, "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="], + + "@types/d3-format": ["@types/d3-format@3.0.4", "", {}, "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="], + + "@types/d3-geo": ["@types/d3-geo@3.1.1", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w=="], + + "@types/d3-hierarchy": ["@types/d3-hierarchy@3.1.7", "", {}, "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-polygon": ["@types/d3-polygon@3.0.2", "", {}, "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="], + + "@types/d3-quadtree": ["@types/d3-quadtree@3.0.6", "", {}, "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="], + + "@types/d3-random": ["@types/d3-random@3.0.4", "", {}, "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-scale-chromatic": ["@types/d3-scale-chromatic@3.1.0", "", {}, "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="], + + "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], + + "@types/d3-shape": ["@types/d3-shape@3.2.0", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-time-format": ["@types/d3-time-format@4.0.3", "", {}, "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + + "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], + + "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], @@ -536,12 +621,16 @@ "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.47", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA=="], "@xterm/addon-serialize": ["@xterm/addon-serialize@0.14.0", "", {}, "sha512-uteyTU1EkrQa2Ux6P/uFl2fzmXI46jy5uoQMKEOM0fKTyiW7cSn0WrFenHm5vO5uEXX/GpwW/FgILvv3r0WbkA=="], @@ -622,6 +711,8 @@ "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + "chevrotain": ["chevrotain@11.1.2", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.1.2", "@chevrotain/gast": "11.1.2", "@chevrotain/regexp-to-ast": "11.1.2", "@chevrotain/types": "11.1.2", "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], @@ -642,6 +733,8 @@ "command-score": ["command-score@0.1.2", "", {}, "sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w=="], + "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + "content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -654,14 +747,90 @@ "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "cytoscape": ["cytoscape@3.34.3", "", {}, "sha512-yfYGhRcGAntq6YBD583j4n0Eg3jIxvWmZtz/5uz9UYkeIStSlMxuUja+ec5j3iBD8nv1rwaOAYMW09tBdkSeaQ=="], + + "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.14", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg=="], + "data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="], + "dayjs": ["dayjs@1.11.23", "", {}, "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], @@ -670,6 +839,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.1.0", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], @@ -682,6 +853,8 @@ "diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], + "dompurify": ["dompurify@3.4.15", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], @@ -690,6 +863,8 @@ "electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="], + "elkjs": ["elkjs@0.9.3", "", {}, "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], @@ -704,6 +879,8 @@ "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "es-toolkit": ["es-toolkit@1.52.0", "", {}, "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -794,6 +971,8 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], @@ -828,10 +1007,14 @@ "ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="], + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -874,8 +1057,14 @@ "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="], + + "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], + "koffi": ["koffi@2.16.2", "", {}, "sha512-owU0MRwv6xkrVqCd+33uw6BaYppkTRXbO/rVdJNI2dvZG0gzyRhYwW25eWtc5pauwK8TGh3AbkFONSezdykfSA=="], + "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], + "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], @@ -900,6 +1089,8 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], + "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], @@ -952,6 +1143,8 @@ "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + "mermaid": ["mermaid@12.0.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.2", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^2.0.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "chevrotain": "~11.1.2", "cytoscape": "^3.34.0", "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.14", "dayjs": "^1.11.21", "dompurify": "^3.4.12", "elkjs": "^0.9.3", "es-toolkit": "^1.45.1", "katex": "^0.16.47", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "sha512-/wQXC9iBxoGV8p3erbvaXs9h77VyLDBH6GdayVjj3hEcSQhFU4N1WUhUppotCEqlIxI2pRMwjwBSwTB1MfZBgQ=="], + "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=="], "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], @@ -1052,6 +1245,8 @@ "pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="], + "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], @@ -1062,6 +1257,8 @@ "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], + "path-data-parser": ["path-data-parser@0.1.0", "", {}, "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], @@ -1076,6 +1273,10 @@ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "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=="], + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], "postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], @@ -1142,10 +1343,16 @@ "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], + "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=="], + "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], @@ -1206,6 +1413,8 @@ "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + "stylis": ["stylis@4.4.0", "", {}, "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="], @@ -1218,6 +1427,8 @@ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + "tinyexec": ["tinyexec@1.3.1", "", {}, "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], @@ -1230,6 +1441,8 @@ "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], + "ts-dedent": ["ts-dedent@2.3.0", "", {}, "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], @@ -1378,10 +1591,24 @@ "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "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=="], + + "dagre-d3-es/lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], + "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], "hosted-git-info/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], + "node-fetch/data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], @@ -1450,6 +1677,12 @@ "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], + + "d3-sankey/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], + + "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], diff --git a/package.json b/package.json index 7cd18fb2c..8057c5247 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "file-type": "^22.0.0", "hast-util-to-jsx-runtime": "^2", "html-url-attributes": "^3", + "mermaid": "^12.0.0", "openai": "^6.34.0", "remark-parse": "^11", "remark-rehype": "^11", diff --git a/src/client/app/ChatPage/ChatTranscriptViewport.tsx b/src/client/app/ChatPage/ChatTranscriptViewport.tsx index 4c1562cf6..7315a41db 100644 --- a/src/client/app/ChatPage/ChatTranscriptViewport.tsx +++ b/src/client/app/ChatPage/ChatTranscriptViewport.tsx @@ -10,6 +10,8 @@ import { import { ArrowDown, Flower, Upload } from "lucide-react" import { DrainingIndicator } from "../../components/messages/DrainingIndicator" import { QueuedUserMessage } from "../../components/messages/QueuedUserMessage" +import { AttachmentPreviewModal } from "../../components/messages/AttachmentPreviewModal" +import { classifyAttachmentPreview, inferAttachmentPreviewMimeType } from "../../components/messages/attachmentPreview" import { OpenLocalLinkProvider, type OpenLocalLinkTarget } from "../../components/messages/shared" import { ProcessingMessage } from "../../components/messages/ProcessingMessage" import { ContextMenu, ContextMenuTrigger } from "../../components/ui/context-menu" @@ -18,7 +20,7 @@ import { TRANSCRIPT_PADDING_BOTTOM_OFFSET } from "../kannaStateHelpers" import { useScrollbarGutterVar } from "../../hooks/useScrollbarGutterVar" import { cn } from "../../lib/utils" import type { ChatJumpRole } from "../../lib/chat-navigation" -import { formatPathWithTilde, shouldOpenLocalFileLinkInEditor } from "../../lib/pathUtils" +import { formatPathWithTilde, projectRelativeFilePath, shouldOpenLocalFileLinkInEditor } from "../../lib/pathUtils" import { buildResolvedTranscriptRows, KannaTranscriptRow, @@ -49,7 +51,8 @@ import { EMPTY_STATE_TEXT, } from "./utils" import type { EditorOpenSettings, EditorPreset, OpenExternalAction } from "../../../shared/protocol" -import type { TranscriptOutlineEntry } from "../../../shared/types" +import { browserOriginFromWindow, parseBrowserAccessContext } from "../../../shared/browser-context" +import type { ChatAttachment, TranscriptOutlineEntry } from "../../../shared/types" /** * How close to the bottom counts as "at the end", as a fraction of viewport * height. @@ -185,6 +188,7 @@ interface ChatTranscriptViewportProps { messages: KannaState["messages"] queuedMessages: KannaState["queuedMessages"] transcriptPaddingBottom: number + projectId: string | null localPath: string | null | undefined latestToolIds: KannaState["latestToolIds"] isProcessing: boolean @@ -391,6 +395,7 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ messages, queuedMessages, transcriptPaddingBottom, + projectId, localPath, latestToolIds, isProcessing, @@ -437,6 +442,8 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ const localLinkMenuTriggerRef = useRef(null) const [toolGroupExpanded, setToolGroupExpanded] = useState>({}) const [localLinkMenuTarget, setLocalLinkMenuTarget] = useState(null) + const [localFilePreview, setLocalFilePreview] = useState(null) + const [localLinkError, setLocalLinkError] = useState(null) const isMac = platform === "darwin" const rawRows = useMemo(() => buildResolvedTranscriptRows(messages, { @@ -916,6 +923,38 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ const handleOpenLocalLinkClick = useCallback((target: OpenLocalLinkTarget) => { if (target.trigger !== "contextmenu") { + const accessContext = parseBrowserAccessContext(browserOriginFromWindow()) + if (accessContext?.mode === "network") { + const relativePath = projectRelativeFilePath(target.path, localPath) + if (!projectId || !relativePath) { + setLocalLinkError( + "This file is outside the active project and can't be previewed over the network. Right-click it for actions on the Kanna machine." + ) + return + } + + const mimeType = inferAttachmentPreviewMimeType(relativePath) + const contentUrl = `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(relativePath)}/content` + const attachment: ChatAttachment = { + id: `workspace-file:${target.path}`, + kind: mimeType.startsWith("image/") ? "image" : "file", + displayName: relativePath.split("/").pop() ?? relativePath, + absolutePath: target.path, + relativePath, + contentUrl, + mimeType, + size: 0, + } + setLocalLinkError(null) + if (classifyAttachmentPreview(attachment).openInNewTab) { + window.open(contentUrl, "_blank", "noopener,noreferrer") + } else { + setLocalFilePreview(attachment) + } + return + } + + setLocalLinkError(null) const action = shouldOpenLocalFileLinkInEditor(target.path) ? "open_editor" : "open_default" void onOpenLocalLink(target, action) return @@ -935,7 +974,7 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ view: window, })) }) - }, [onOpenLocalLink]) + }, [localPath, onOpenLocalLink, projectId]) // Stable identity: the viewport commits a render on every scroll event (the // visible row range changes constantly), and a fresh style object hands the @@ -985,9 +1024,9 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ {!isProcessing && isDraining ? ( void onStopDraining()} /> ) : null} - {commandError ? ( + {commandError || localLinkError ? (
- {commandError} + {commandError ?? localLinkError}
) : null} @@ -1043,6 +1082,14 @@ const TranscriptScrollerBody = memo(function TranscriptScrollerBody({ + + { + if (!open) setLocalFilePreview(null) + }} + /> {showEmptyState ? null : ( diff --git a/src/client/app/ChatPage/index.tsx b/src/client/app/ChatPage/index.tsx index 4d8643d25..082073f5e 100644 --- a/src/client/app/ChatPage/index.tsx +++ b/src/client/app/ChatPage/index.tsx @@ -1024,6 +1024,7 @@ export function ChatPage() { messages={state.messages} queuedMessages={state.queuedMessages} transcriptPaddingBottom={transcriptPaddingBottom} + projectId={projectId} localPath={state.runtime?.localPath} latestToolIds={state.latestToolIds} isProcessing={state.isProcessing} diff --git a/src/client/app/snapshotEquality.ts b/src/client/app/snapshotEquality.ts index cfb780f6b..3ab6fe360 100644 --- a/src/client/app/snapshotEquality.ts +++ b/src/client/app/snapshotEquality.ts @@ -53,6 +53,7 @@ function sameQueuedMessage(left: QueuedChatMessage, right: QueuedChatMessage) { return left.id === right.id && left.content === right.content && left.createdAt === right.createdAt + && left.browserOrigin === right.browserOrigin && left.provider === right.provider && left.model === right.model && left.planMode === right.planMode diff --git a/src/client/app/useSendMessage.ts b/src/client/app/useSendMessage.ts index 27e65362a..af5dc4a20 100644 --- a/src/client/app/useSendMessage.ts +++ b/src/client/app/useSendMessage.ts @@ -15,6 +15,7 @@ import { type OptimisticUserPrompt, } from "./kannaStateHelpers" import type { KannaSocket } from "./socket" +import { browserOriginFromWindow } from "../../shared/browser-context" export interface SendContext { isProcessing: boolean @@ -65,6 +66,7 @@ export function useSendMessage(params: { ) => { const { isProcessing, optimisticUserPrompts, serverTranscriptEntries, selectedProjectId, fallbackLocalProjectPath } = sendContextRef.current const attachments = options?.attachments ?? [] + const browserOrigin = browserOriginFromWindow() if (activeChatId && isProcessing) { try { await socket.command<{ queuedMessageId: string }>({ @@ -72,6 +74,7 @@ export function useSendMessage(params: { chatId: activeChatId, content, attachments, + browserOrigin, provider: options?.provider, model: options?.model, modelOptions: options?.modelOptions, @@ -139,6 +142,7 @@ export function useSendMessage(params: { provider: options?.provider, content, attachments, + browserOrigin, model: options?.model, modelOptions: options?.modelOptions, planMode: options?.planMode, diff --git a/src/client/components/chat-ui/BrowserPanel.tsx b/src/client/components/chat-ui/BrowserPanel.tsx index 2a7a3d9a0..88ec34a75 100644 --- a/src/client/components/chat-ui/BrowserPanel.tsx +++ b/src/client/components/chat-ui/BrowserPanel.tsx @@ -1,6 +1,7 @@ import { Copy, CornerDownLeft, Ellipsis, ExternalLink, Globe, GlobeLock, Home, Loader2, Minus, Play, Plus, RefreshCw, SquareArrowOutUpRight, Trash2, Zap } from "lucide-react" import { memo, useCallback, useEffect, useRef, useState, type FocusEvent, type FormEvent, type ReactNode } from "react" import type { LocalHttpServerInfo, ProjectQuickAction } from "../../../shared/protocol" +import { browserOriginFromWindow, resolveUrlForBrowserHost } from "../../../shared/browser-context" import type { KannaSocket } from "../../app/socket" import { getCachedLocalHttpServers, @@ -139,7 +140,7 @@ function BrowserPanelImpl({ projectId, socket, onRunQuickAction }: BrowserPanelP const openServer = useCallback(async (server: LocalHttpServerInfo) => { if (!isCloud) { - navigateBrowser(projectId, server.address) + navigateBrowser(projectId, resolveUrlForBrowserHost(server.address, browserOriginFromWindow())) return } const publicUrl = await exposeServer(server) @@ -450,7 +451,8 @@ function BrowserPanelImpl({ projectId, socket, onRunQuickAction }: BrowserPanelP
{visibleServers.map((server) => { const isExposing = exposingPorts.has(server.port) - const openUrl = isCloud && server.publicUrl ? server.publicUrl : server.address + const reachableAddress = resolveUrlForBrowserHost(server.address, browserOriginFromWindow()) + const openUrl = isCloud && server.publicUrl ? server.publicUrl : reachableAddress return ( @@ -490,7 +492,7 @@ function BrowserPanelImpl({ projectId, socket, onRunQuickAction }: BrowserPanelP - {isExposing ? "Exposing…" : server.publicUrl ?? server.address} + {isExposing ? "Exposing…" : server.publicUrl ?? reachableAddress} {server.ownerPath ? ( {formatPathWithTilde(server.ownerPath)} diff --git a/src/client/components/messages/AttachmentPreviewModal.tsx b/src/client/components/messages/AttachmentPreviewModal.tsx index c74c8ee49..90cfb940c 100644 --- a/src/client/components/messages/AttachmentPreviewModal.tsx +++ b/src/client/components/messages/AttachmentPreviewModal.tsx @@ -41,10 +41,11 @@ type LoadablePreviewKind = Extract void } -export function AttachmentPreviewModal({ attachment, onOpenChange }: Props) { +export function AttachmentPreviewModal({ attachment, metadataLabel, onOpenChange }: Props) { const [previewCache, setPreviewCache] = useState>({}) const previewTarget = useMemo(() => { return attachment ? classifyAttachmentPreview(attachment) : null @@ -149,7 +150,7 @@ export function AttachmentPreviewModal({ attachment, onOpenChange }: Props) { - {attachment.mimeType} · {formatAttachmentSize(attachment.size)} + {metadataLabel ?? `${attachment.mimeType} · ${formatAttachmentSize(attachment.size)}`}
diff --git a/src/client/components/messages/MermaidDiagram.tsx b/src/client/components/messages/MermaidDiagram.tsx new file mode 100644 index 000000000..871f72779 --- /dev/null +++ b/src/client/components/messages/MermaidDiagram.tsx @@ -0,0 +1,101 @@ +import { useEffect, useId, useState } from "react" +import { CopyButton } from "../ui/copy-button" + +type MermaidTheme = "default" | "dark" + +type DiagramState = + | { status: "loading" } + | { status: "ready"; svg: string } + | { status: "error" } + +let renderSequence = 0 +let renderQueue = Promise.resolve() + +function currentTheme(): MermaidTheme { + if (typeof document === "undefined") return "default" + return document.documentElement.classList.contains("dark") ? "dark" : "default" +} + +function queueRender(source: string, id: string, theme: MermaidTheme) { + const render = renderQueue.then(async () => { + const { default: mermaid } = await import("mermaid") + mermaid.initialize({ + startOnLoad: false, + securityLevel: "strict", + suppressErrorRendering: true, + theme, + flowchart: { useMaxWidth: true }, + }) + return mermaid.render(id, source) + }) + + renderQueue = render.then(() => undefined, () => undefined) + return render +} + +export function MermaidDiagram({ source }: { source: string }) { + const reactId = useId().replace(/[^a-zA-Z0-9_-]/g, "") + const [theme, setTheme] = useState(currentTheme) + const [state, setState] = useState({ status: "loading" }) + + useEffect(() => { + const root = document.documentElement + const observer = new MutationObserver(() => setTheme(currentTheme())) + observer.observe(root, { attributes: true, attributeFilter: ["class"] }) + return () => observer.disconnect() + }, []) + + useEffect(() => { + let cancelled = false + setState({ status: "loading" }) + renderSequence += 1 + + void queueRender(source, `kanna-mermaid-${reactId}-${renderSequence}`, theme) + .then(({ svg }) => { + if (!cancelled) setState({ status: "ready", svg }) + }) + .catch(() => { + if (!cancelled) setState({ status: "error" }) + }) + + return () => { + cancelled = true + } + }, [reactId, source, theme]) + + if (state.status === "ready") { + return ( +
+ ) + } + + if (state.status === "error") { + return ( +
+
+ Unable to render Mermaid diagram. Showing source instead. +
+
{source}
+ +
+ ) + } + + return ( +
+ ) +} diff --git a/src/client/components/messages/attachmentPreview.test.ts b/src/client/components/messages/attachmentPreview.test.ts index 25a359844..647ee48ca 100644 --- a/src/client/components/messages/attachmentPreview.test.ts +++ b/src/client/components/messages/attachmentPreview.test.ts @@ -4,6 +4,7 @@ import { JSON_PREVIEW_LIMIT_BYTES, classifyAttachmentIcon, classifyAttachmentPreview, + inferAttachmentPreviewMimeType, parseDelimitedPreview, prettifyJson, } from "./attachmentPreview" @@ -55,6 +56,15 @@ describe("classifyAttachmentPreview", () => { }) }) +describe("inferAttachmentPreviewMimeType", () => { + test("recognizes files supported by the in-browser preview", () => { + expect(inferAttachmentPreviewMimeType("README.md")).toBe("text/markdown") + expect(inferAttachmentPreviewMimeType("diagram.svg")).toBe("image/svg+xml") + expect(inferAttachmentPreviewMimeType("app.tsx")).toBe("text/plain") + expect(inferAttachmentPreviewMimeType("archive.zip")).toBe("application/octet-stream") + }) +}) + describe("parseDelimitedPreview", () => { test("parses quoted csv cells correctly", () => { const result = parseDelimitedPreview("name,notes\njake,\"a,b,c\"", ",") diff --git a/src/client/components/messages/attachmentPreview.ts b/src/client/components/messages/attachmentPreview.ts index c49f1797b..5b36ad0b8 100644 --- a/src/client/components/messages/attachmentPreview.ts +++ b/src/client/components/messages/attachmentPreview.ts @@ -16,6 +16,22 @@ const ARCHIVE_EXTENSIONS = new Set([".7z", ".bz2", ".gz", ".rar", ".tar", ".tgz" const AUDIO_EXTENSIONS = new Set([".aac", ".flac", ".m4a", ".mp3", ".ogg", ".wav"]) const VIDEO_EXTENSIONS = new Set([".avi", ".m4v", ".mov", ".mp4", ".mkv", ".webm"]) +const PREVIEW_MIME_TYPE_BY_EXTENSION = new Map([ + [".avif", "image/avif"], + [".bmp", "image/bmp"], + [".csv", "text/csv"], + [".gif", "image/gif"], + [".jpeg", "image/jpeg"], + [".jpg", "image/jpeg"], + [".json", "application/json"], + [".md", "text/markdown"], + [".pdf", "application/pdf"], + [".png", "image/png"], + [".svg", "image/svg+xml"], + [".tsv", "text/tab-separated-values"], + [".webp", "image/webp"], +]) + export type AttachmentIconKind = | "image" | "pdf" @@ -56,6 +72,13 @@ export interface TablePreviewData { truncatedColumns: boolean } +/** Best-effort type for workspace files that were linked rather than uploaded. */ +export function inferAttachmentPreviewMimeType(fileName: string) { + const extension = getFileExtension(fileName) + return PREVIEW_MIME_TYPE_BY_EXTENSION.get(extension) + ?? (CODE_OR_CONFIG_EXTENSIONS.has(extension) ? "text/plain" : "application/octet-stream") +} + export function classifyAttachmentPreview(attachment: ChatAttachment): AttachmentPreviewTarget { const mimeType = attachment.mimeType.toLowerCase() const extension = getFileExtension(attachment.displayName) diff --git a/src/client/components/messages/shared.test.tsx b/src/client/components/messages/shared.test.tsx index c80af2348..7c5d1902f 100644 --- a/src/client/components/messages/shared.test.tsx +++ b/src/client/components/messages/shared.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test" import { renderToStaticMarkup } from "react-dom/server" import Markdown from "react-markdown" import remarkGfm from "remark-gfm" -import { createMarkdownComponents, markdownComponents, OpenLocalLinkProvider } from "./shared" +import { createMarkdownComponents, markdownComponents, OpenLocalLinkProvider, TranscriptMarkdown } from "./shared" describe("markdownComponents", () => { test("renders markdown headings with transcript-specific sizes and no bold weight", () => { @@ -76,4 +76,14 @@ describe("markdownComponents", () => { expect(html).toContain("/Users/jake/Projects/kanna/src/client/app/App.tsx#L1") expect(html).not.toContain('target="_blank"') }) + + test("routes fenced mermaid blocks to the diagram renderer", () => { + const html = renderToStaticMarkup( + B\n```"} /> + ) + + expect(html).toContain("data-mermaid-diagram") + expect(html).toContain("Rendering Mermaid diagram") + expect(html).not.toContain("language-mermaid") + }) }) diff --git a/src/client/components/messages/shared.tsx b/src/client/components/messages/shared.tsx index a852e6e9f..bdaf0bb79 100644 --- a/src/client/components/messages/shared.tsx +++ b/src/client/components/messages/shared.tsx @@ -36,6 +36,7 @@ import { CopyButton } from "../ui/copy-button" import { cn } from "../../lib/utils" import { parseLocalFileLink } from "../../lib/pathUtils" import { useTranscriptRenderOptions } from "./render-context" +import { MermaidDiagram } from "./MermaidDiagram" export type OpenLocalLinkTarget = { path: string @@ -251,6 +252,12 @@ export const markdownComponents = { ), pre: ({ children, ...props }: ComponentPropsWithoutRef<"pre">) => { + const childNodes = Children.toArray(children) + const onlyChild = childNodes.length === 1 ? childNodes[0] : null + if (isValidElement<{ className?: string }>(onlyChild) && isMermaidClassName(onlyChild.props.className)) { + return onlyChild + } + const textContent = extractText(children) return ( @@ -265,6 +272,10 @@ export const markdownComponents = { }, code: ({ children, className, ...props }: ComponentPropsWithoutRef<"code">) => { + if (isMermaidClassName(className)) { + return + } + const isInline = !className if (isInline) { return {children} @@ -335,6 +346,10 @@ export const markdownComponents = { ), } +function isMermaidClassName(className: string | undefined) { + return className?.split(/\s+/).includes("language-mermaid") ?? false +} + export function createMarkdownComponents(options?: { onOpenLocalLink?: OpenLocalLinkHandler }) { @@ -417,4 +432,3 @@ export const TranscriptMarkdown = memo(function TranscriptMarkdown({ text }: { t passNode: true, }) }) - diff --git a/src/client/lib/pathUtils.test.ts b/src/client/lib/pathUtils.test.ts index c070251e3..eb1d7f4cc 100644 --- a/src/client/lib/pathUtils.test.ts +++ b/src/client/lib/pathUtils.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { abbreviatePathHead, formatPathWithTilde, parseLocalFileLink, shouldOpenLocalFileLinkInEditor } from "./pathUtils" +import { abbreviatePathHead, formatPathWithTilde, parseLocalFileLink, projectRelativeFilePath, shouldOpenLocalFileLinkInEditor } from "./pathUtils" describe("abbreviatePathHead", () => { test("returns short paths unchanged", () => { @@ -46,6 +46,14 @@ describe("parseLocalFileLink", () => { }) }) + test("decodes browser-escaped paths", () => { + expect(parseLocalFileLink("/Users/jake/My%20Project/readme.md#L2")).toEqual({ + path: "/Users/jake/My Project/readme.md", + line: 2, + column: undefined, + }) + }) + test("parses an absolute file path with a line suffix", () => { expect(parseLocalFileLink("/Users/jake/Kanna/superwall-agent/scripts/e2b-proxy.mjs:1")).toEqual({ path: "/Users/jake/Kanna/superwall-agent/scripts/e2b-proxy.mjs", @@ -92,6 +100,14 @@ describe("parseLocalFileLink", () => { }) }) +describe("projectRelativeFilePath", () => { + test("returns only files inside the active project", () => { + expect(projectRelativeFilePath("/repo/docs/plan.md", "/repo")).toBe("docs/plan.md") + expect(projectRelativeFilePath("/repo-other/plan.md", "/repo")).toBeNull() + expect(projectRelativeFilePath("/repo", "/repo")).toBeNull() + }) +}) + describe("shouldOpenLocalFileLinkInEditor", () => { test("opens source, markdown, and text files in the editor", () => { expect(shouldOpenLocalFileLinkInEditor("/Users/jake/Projects/kanna/src/app.ts")).toBe(true) diff --git a/src/client/lib/pathUtils.ts b/src/client/lib/pathUtils.ts index 431588ed7..ac36c6542 100644 --- a/src/client/lib/pathUtils.ts +++ b/src/client/lib/pathUtils.ts @@ -67,6 +67,14 @@ function parseAbsoluteFileTarget(target: string): ParsedFileTarget | null { return null } +function decodeFileLinkPath(filePath: string) { + try { + return decodeURIComponent(filePath) + } catch { + return filePath + } +} + export function parseLocalFileLink(target: string | undefined | null): ParsedLocalFileLink | null { if (!target) return null const trimmed = target.trim() @@ -81,13 +89,24 @@ export function parseLocalFileLink(target: string | undefined | null): ParsedLoc if (url.origin !== window.location.origin || !url.pathname.startsWith("/")) { return null } - return parseAbsoluteFileTarget(`${url.pathname}${url.hash}`) + const parsed = parseAbsoluteFileTarget(`${url.pathname}${url.hash}`) + return parsed ? { ...parsed, path: decodeFileLinkPath(parsed.path) } : null } catch { return null } } - return parseAbsoluteFileTarget(trimmed) + const parsed = parseAbsoluteFileTarget(trimmed) + return parsed ? { ...parsed, path: decodeFileLinkPath(parsed.path) } : null +} + +/** Project-relative path accepted by the scoped project-file content API. */ +export function projectRelativeFilePath(filePath: string, projectPath: string | undefined | null) { + if (!projectPath) return null + const root = projectPath.replace(/[\\/]+$/, "") + if (filePath === root) return null + const prefix = `${root}/` + return filePath.startsWith(prefix) ? filePath.slice(prefix.length) : null } /** diff --git a/src/export-viewer/main.tsx b/src/export-viewer/main.tsx index af97917ee..3a11dd275 100644 --- a/src/export-viewer/main.tsx +++ b/src/export-viewer/main.tsx @@ -156,6 +156,7 @@ function StandaloneTranscriptApp() { messages={messages} queuedMessages={[]} transcriptPaddingBottom={120} + projectId={null} localPath={state.bundle.localPath} latestToolIds={latestToolIds} isProcessing={false} diff --git a/src/server/agent.ts b/src/server/agent.ts index 39c1f3594..8dfda8c8b 100644 --- a/src/server/agent.ts +++ b/src/server/agent.ts @@ -62,6 +62,8 @@ import { asNumber, asRecord } from "../shared/json" import { buildHandoffContext, buildHandoffMessageContent, type HandoffContext } from "./handoff" import { checkSessionArtifact, type SessionArtifactStatus } from "./session-artifacts" import { timestamped } from "./transcript" +import { buildBrowserAccessNotice } from "./browser-context" +import { normalizeBrowserOrigin } from "../shared/browser-context" /** * Tools every Claude session gets. `EnterPlanMode` is deliberately absent — it @@ -241,6 +243,7 @@ interface SendMessageOptions { effort?: string planMode?: boolean autoPlan?: boolean + browserOrigin?: string } function stringFromUnknown(value: unknown) { @@ -1116,6 +1119,7 @@ export class AgentCoordinator { modelOptions: options?.modelOptions, planMode: options?.planMode, autoPlan: options?.autoPlan, + browserOrigin: normalizeBrowserOrigin(options?.browserOrigin), }) this.emitStateChange(chatId) return queued @@ -1136,6 +1140,7 @@ export class AgentCoordinator { serviceTier: settings.serviceTier, planMode: settings.planMode, autoPlan: settings.autoPlan, + browserOrigin: queuedMessage.browserOrigin, appendUserPrompt: true, steered: options?.steered, }) @@ -1309,6 +1314,7 @@ export class AgentCoordinator { autoPlan: boolean appendUserPrompt: boolean steered?: boolean + browserOrigin?: string }) { // Close any lingering draining stream before starting a new turn. @@ -1424,6 +1430,10 @@ export class AgentCoordinator { if (concurrentAgentsNotice) { wireContent = appendSystemMessageBlock(wireContent, concurrentAgentsNotice) } + const browserAccessNotice = buildBrowserAccessNotice(args.browserOrigin) + if (browserAccessNotice) { + wireContent = appendSystemMessageBlock(wireContent, browserAccessNotice) + } // Harness switch or session restore: lead with the rebuilt transcript so // the user's actual prompt is the last thing in context (trails for slash @@ -1712,6 +1722,7 @@ export class AgentCoordinator { effort: command.effort, planMode: command.planMode, autoPlan: command.autoPlan, + browserOrigin: command.browserOrigin, }) return { chatId, queuedMessageId: queuedMessage.id, queued: true as const } } @@ -1729,6 +1740,7 @@ export class AgentCoordinator { serviceTier: settings.serviceTier, planMode: settings.planMode, autoPlan: settings.autoPlan, + browserOrigin: normalizeBrowserOrigin(command.browserOrigin), appendUserPrompt: true, }) @@ -1744,6 +1756,7 @@ export class AgentCoordinator { modelOptions: command.modelOptions, planMode: command.planMode, autoPlan: command.autoPlan, + browserOrigin: command.browserOrigin, }) return { queuedMessageId: queuedMessage.id } } diff --git a/src/server/browser-context.test.ts b/src/server/browser-context.test.ts new file mode 100644 index 000000000..5f3a74750 --- /dev/null +++ b/src/server/browser-context.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from "bun:test" +import { buildBrowserAccessNotice } from "./browser-context" + +describe("buildBrowserAccessNotice", () => { + test("describes same-machine browsing without changing the user's visible text", () => { + const notice = buildBrowserAccessNotice("http://localhost:5174") + expect(notice).toContain("same-machine access") + expect(notice).toContain("localhost URL is appropriate") + }) + + test("tells remote agents which hostname makes server links useful", () => { + const notice = buildBrowserAccessNotice("https://jane.tailnet.ts.net/chat/one?ignored=yes") + expect(notice).toContain("viewed over the network") + expect(notice).toContain("jane.tailnet.ts.net instead of localhost") + expect(notice).toContain("Preserve the started server's protocol and port") + }) + + test("rejects non-http context", () => { + expect(buildBrowserAccessNotice("file:///tmp/kanna")).toBeNull() + }) +}) diff --git a/src/server/browser-context.ts b/src/server/browser-context.ts new file mode 100644 index 000000000..5f0c0aeaf --- /dev/null +++ b/src/server/browser-context.ts @@ -0,0 +1,36 @@ +import { parseBrowserAccessContext } from "../shared/browser-context" + +/** + * Wire-only context for the harness. The visible transcript continues to hold + * exactly what the user typed; this only prevents an agent on another machine + * from handing the reader unusable localhost links or opening desktop apps on + * the wrong computer. + */ +export function buildBrowserAccessNotice(browserOrigin: string | undefined | null) { + const context = parseBrowserAccessContext(browserOrigin) + if (!context) return null + + if (context.mode === "local") { + return [ + "", + "Kanna browser access context:", + `- The web app is being viewed from ${context.origin}.`, + "- This is same-machine access through a loopback hostname.", + "- If you start an HTTP server for the user to open, a localhost URL is appropriate unless the user asks to expose it elsewhere.", + "- Desktop open actions and local file links target this same machine.", + "", + ].join("\n") + } + + return [ + "", + "Kanna browser access context:", + `- The web app is being viewed over the network from ${context.origin}.`, + `- The hostname visible to the browser is ${context.hostname}.`, + "- The agent and its files/processes are on the Kanna machine, while the browser may be on a different device. Desktop open actions run on the Kanna machine, not necessarily the reader's device.", + `- If you start an HTTP server that the user should open, make it listen on a network-accessible interface when safe and requested, and give the user a URL using ${context.hostname} instead of localhost. Preserve the started server's protocol and port.`, + "- Do not claim that a service is publicly reachable, weaken authentication, or broaden network exposure beyond what the user requested.", + "- Continue to format workspace file references as absolute-path Markdown links; Kanna can preview project files in the web app.", + "", + ].join("\n") +} diff --git a/src/server/event-store.ts b/src/server/event-store.ts index 823bd09c2..07edc437e 100644 --- a/src/server/event-store.ts +++ b/src/server/event-store.ts @@ -1687,6 +1687,7 @@ export class EventStore { content: message.content, attachments: [...(message.attachments ?? [])], createdAt: message.createdAt ?? Date.now(), + browserOrigin: message.browserOrigin, provider: message.provider, model: message.model, modelOptions: message.modelOptions, diff --git a/src/shared/browser-context.test.ts b/src/shared/browser-context.test.ts new file mode 100644 index 000000000..bc7ea077d --- /dev/null +++ b/src/shared/browser-context.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, test } from "bun:test" +import { isLoopbackHostname, parseBrowserAccessContext, resolveUrlForBrowserHost } from "./browser-context" + +describe("browser access context", () => { + test("recognizes loopback spellings", () => { + expect(isLoopbackHostname("localhost")).toBe(true) + expect(isLoopbackHostname("app.localhost")).toBe(true) + expect(isLoopbackHostname("127.23.4.5")).toBe(true) + expect(isLoopbackHostname("[::1]")).toBe(true) + expect(isLoopbackHostname("192.168.1.20")).toBe(false) + expect(isLoopbackHostname("jane.tailnet.ts.net")).toBe(false) + }) + + test("normalizes browser origins and drops untrusted URL parts", () => { + expect(parseBrowserAccessContext("https://Jane.Example:8443/some/path?secret=yes#x")).toEqual({ + origin: "https://jane.example:8443", + hostname: "jane.example", + mode: "network", + }) + expect(parseBrowserAccessContext("https://user:secret@example.com")).toBeNull() + expect(parseBrowserAccessContext("javascript:alert(1)")).toBeNull() + }) + + test("uses the browsing hostname for machine-local server addresses over the network", () => { + expect(resolveUrlForBrowserHost("http://localhost:3000", "https://jane.tailnet.ts.net")).toBe( + "http://jane.tailnet.ts.net:3000" + ) + expect(resolveUrlForBrowserHost("http://127.0.0.1:8080/path", "http://192.168.1.20:3210")).toBe( + "http://192.168.1.20:8080/path" + ) + expect(resolveUrlForBrowserHost("http://localhost:3000", "http://localhost:3210")).toBe( + "http://localhost:3000" + ) + expect(resolveUrlForBrowserHost("https://example.com/app", "http://192.168.1.20:3210")).toBe( + "https://example.com/app" + ) + }) +}) diff --git a/src/shared/browser-context.ts b/src/shared/browser-context.ts new file mode 100644 index 000000000..87d1d75b9 --- /dev/null +++ b/src/shared/browser-context.ts @@ -0,0 +1,77 @@ +export type BrowserAccessMode = "local" | "network" + +export interface BrowserAccessContext { + origin: string + hostname: string + mode: BrowserAccessMode +} +function normalizedHostname(hostname: string) { + return hostname.trim().toLowerCase().replace(/^\[|\]$/g, "") +} + +export function isLoopbackHostname(hostname: string) { + const normalized = normalizedHostname(hostname) + if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "::1") { + return true + } + + const ipv4 = normalized.split(".") + return ipv4.length === 4 + && ipv4.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255) + && Number(ipv4[0]) === 127 +} + +/** + * Browser-provided, informational context. Keep it deliberately narrow: it + * is copied into an agent prompt, so paths, credentials, query strings, and + * fragments never survive normalization. + */ +export function parseBrowserAccessContext(value: string | undefined | null): BrowserAccessContext | null { + if (!value || value.length > 2_048) return null + + try { + const url = new URL(value) + if ((url.protocol !== "http:" && url.protocol !== "https:") || url.username || url.password) { + return null + } + + return { + origin: url.origin, + hostname: url.hostname, + mode: isLoopbackHostname(url.hostname) ? "local" : "network", + } + } catch { + return null + } +} + +export function normalizeBrowserOrigin(value: string | undefined | null) { + return parseBrowserAccessContext(value)?.origin +} + +export function browserOriginFromWindow() { + if (typeof window === "undefined") return undefined + return normalizeBrowserOrigin(window.location.origin) +} + +/** + * Kanna discovers servers from its own machine as localhost URLs. When the UI + * is being used over the network, localhost means the reader's device, not + * the Kanna machine, so retain the server's protocol/port and swap only the + * loopback hostname for the hostname used to reach Kanna. + */ +export function resolveUrlForBrowserHost(address: string, browserOrigin: string | undefined | null) { + const context = parseBrowserAccessContext(browserOrigin) + if (!context || context.mode === "local") return address + + try { + const target = new URL(address) + if (!isLoopbackHostname(target.hostname) && normalizedHostname(target.hostname) !== "0.0.0.0") { + return address + } + target.hostname = context.hostname + return target.toString().replace(/\/$/, "") + } catch { + return address + } +} diff --git a/src/shared/protocol.ts b/src/shared/protocol.ts index 7bbf56b42..e2c7ef766 100644 --- a/src/shared/protocol.ts +++ b/src/shared/protocol.ts @@ -244,6 +244,8 @@ export type ClientCommand = provider?: AgentProvider content: string attachments?: ChatAttachment[] + /** Browser origin used only for wire-only machine/network context. */ + browserOrigin?: string model?: string modelOptions?: ModelOptions effort?: string @@ -297,6 +299,8 @@ export type ClientCommand = chatId: string content: string attachments?: ChatAttachment[] + /** Browser origin retained with a queued prompt until its turn starts. */ + browserOrigin?: string provider?: AgentProvider model?: string modelOptions?: ModelOptions diff --git a/src/shared/types.ts b/src/shared/types.ts index d3581cf32..4feaee44e 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -171,6 +171,8 @@ export interface QueuedChatMessage { content: string attachments: ChatAttachment[] createdAt: number + /** Informational web origin used for wire-only agent context. */ + browserOrigin?: string provider?: AgentProvider model?: string modelOptions?: ModelOptions