diff --git a/package-lock.json b/package-lock.json index cdf9a1f..f7b6414 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-cowork", - "version": "0.9.82", + "version": "0.9.85", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-cowork", - "version": "0.9.82", + "version": "0.9.85", "hasInstallScript": true, "dependencies": { "@base-ui/react": "^1.1.0", @@ -43,6 +43,7 @@ "immer": "^11.1.3", "lucide-react": "^0.563.0", "mammoth": "^1.11.0", + "markstream-react": "^0.0.45", "mermaid": "^11.12.3", "monaco-editor": "^0.55.1", "motion": "^12.34.0", @@ -132,7 +133,6 @@ "version": "7.29.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -845,6 +845,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -866,6 +867,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1473,18 +1475,22 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.4", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.5", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/react-dom": { @@ -1499,7 +1505,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.10", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, "node_modules/@hono/node-server": { @@ -5450,7 +5458,6 @@ "node_modules/@types/node": { "version": "22.19.10", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -5490,7 +5497,6 @@ "node_modules/@types/react": { "version": "19.2.13", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5499,7 +5505,6 @@ "version": "19.2.3", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5624,7 +5629,6 @@ "version": "8.54.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", @@ -5921,7 +5925,6 @@ "node_modules/acorn": { "version": "8.15.0", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5957,7 +5960,6 @@ "version": "6.12.6", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6454,7 +6456,6 @@ "node_modules/bare-events": { "version": "2.8.2", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -6694,7 +6695,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7074,7 +7074,6 @@ "node_modules/chevrotain": { "version": "11.1.1", "license": "Apache-2.0", - "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.1.1", "@chevrotain/gast": "11.1.1", @@ -7457,7 +7456,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -7505,7 +7505,6 @@ "node_modules/cytoscape": { "version": "3.33.1", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -7845,7 +7844,6 @@ "node_modules/d3-selection": { "version": "3.0.0", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -8195,7 +8193,6 @@ "integrity": "sha512-vDDKK9npsEruUc9LN4Q0KdYkwR4GsA4WR+jPjKyIhB9Dlo0Di1EkJv4CfqWIkr9PCOwEdvK+mG3SiDEnbl4FZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.3.3", "builder-util": "26.3.1", @@ -8360,7 +8357,6 @@ "version": "36.9.5", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", @@ -8493,6 +8489,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -8513,6 +8510,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -8528,6 +8526,7 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", + "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -8538,6 +8537,7 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -8582,6 +8582,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "license": "MIT", @@ -8835,7 +8847,6 @@ "version": "9.39.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8894,7 +8905,6 @@ "version": "10.1.8", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -9169,7 +9179,6 @@ "node_modules/express": { "version": "5.2.1", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -10089,7 +10098,6 @@ "node_modules/hono": { "version": "4.12.1", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -10203,7 +10211,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.4" }, @@ -11358,6 +11365,15 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -11541,6 +11557,64 @@ "node": ">=12.0.0" } }, + "node_modules/markdown-it-container": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-4.0.0.tgz", + "integrity": "sha512-HaNccxUH0l7BNGYbFbjmGpf5aLHAMTinqRZQAEQbMr2cdD3z91Q6kIo1oUn1CQndkT03jat6ckrdRYuwwqLlQw==", + "license": "MIT" + }, + "node_modules/markdown-it-footnote": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", + "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", + "license": "MIT" + }, + "node_modules/markdown-it-ins": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-4.0.0.tgz", + "integrity": "sha512-sWbjK2DprrkINE4oYDhHdCijGT+MIDhEupjSHLXe5UXeVr5qmVxs/nTUVtgi0Oh/qtF+QKV0tNWDhQBEPxiMew==", + "license": "MIT" + }, + "node_modules/markdown-it-mark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-4.0.0.tgz", + "integrity": "sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg==", + "license": "MIT" + }, + "node_modules/markdown-it-sub": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-2.0.0.tgz", + "integrity": "sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==", + "license": "MIT" + }, + "node_modules/markdown-it-sup": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-2.0.0.tgz", + "integrity": "sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==", + "license": "MIT" + }, + "node_modules/markdown-it-task-checkbox": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/markdown-it-task-checkbox/-/markdown-it-task-checkbox-1.0.6.tgz", + "integrity": "sha512-7pxkHuvqTOu3iwVGmDPeYjQg+AIS9VQxzyLP9JCg9lBjgPAJXGEkChK6A2iFuj3tS0GV3HG2u5AMNhcQqwxpJw==", + "license": "ISC" + }, + "node_modules/markdown-it-ts": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/markdown-it-ts/-/markdown-it-ts-0.0.9.tgz", + "integrity": "sha512-krzuXIaUUiXI8SLlyssp1q4FzDlnfP3wrJwb7ulzwa1DLTYnYDtVe9R5NLTi2FZTo59APCD6to5JnFFj5bs0nA==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "license": "MIT", @@ -11559,6 +11633,47 @@ "node": ">= 20" } }, + "node_modules/markstream-react": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/markstream-react/-/markstream-react-0.0.45.tgz", + "integrity": "sha512-4LokzzYkXLORlJ2WS5zgAGcsBe+lBZV3h6m+ZljnwkV2To8VB2UaYiQuWvBUD1Tju1jI9qzQxvchSBH4DxmLuw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "clsx": "^2.1.1", + "stream-markdown-parser": "0.0.90" + }, + "peerDependencies": { + "@antv/infographic": "^0.2.3", + "@terrastruct/d2": ">=0.1.33", + "katex": ">=0.16.22", + "mermaid": ">=11", + "react": ">=18", + "react-dom": ">=18", + "stream-markdown": ">=0.0.15", + "stream-monaco": ">=0.0.38" + }, + "peerDependenciesMeta": { + "@antv/infographic": { + "optional": true + }, + "@terrastruct/d2": { + "optional": true + }, + "katex": { + "optional": true + }, + "mermaid": { + "optional": true + }, + "stream-markdown": { + "optional": true + }, + "stream-monaco": { + "optional": true + } + } + }, "node_modules/matcher": { "version": "3.0.0", "license": "MIT", @@ -11827,6 +11942,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/media-typer": { "version": "1.1.0", "license": "MIT", @@ -12644,7 +12765,6 @@ "node_modules/monaco-editor": { "version": "0.55.1", "license": "MIT", - "peer": true, "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" @@ -13353,7 +13473,6 @@ "node_modules/picomatch": { "version": "4.0.3", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13482,6 +13601,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -13499,6 +13619,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -13559,7 +13680,6 @@ "version": "3.8.1", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -13708,6 +13828,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.15.0", "license": "BSD-3-Clause", @@ -13884,7 +14013,6 @@ "node_modules/react": { "version": "19.2.4", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13892,7 +14020,6 @@ "node_modules/react-dom": { "version": "19.2.4", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -13929,8 +14056,7 @@ "version": "19.2.4", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz", "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-markdown": { "version": "10.1.0", @@ -13989,7 +14115,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -14211,8 +14336,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -14478,6 +14602,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -14492,6 +14617,7 @@ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -14513,6 +14639,7 @@ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -15152,6 +15279,22 @@ "node": ">= 0.4" } }, + "node_modules/stream-markdown-parser": { + "version": "0.0.90", + "resolved": "https://registry.npmjs.org/stream-markdown-parser/-/stream-markdown-parser-0.0.90.tgz", + "integrity": "sha512-mTv8MlN593DVAjIPaSm/IZCQb3X3v7fwfT0P4a/7KMK5bTDK+8p6l/C1S7IRPYGwss9bpfpD6gMRZFSrFC7w8A==", + "license": "MIT", + "dependencies": { + "markdown-it-container": "^4.0.0", + "markdown-it-footnote": "^4.0.0", + "markdown-it-ins": "^4.0.0", + "markdown-it-mark": "^4.0.0", + "markdown-it-sub": "^2.0.0", + "markdown-it-sup": "^2.0.0", + "markdown-it-task-checkbox": "^1.0.6", + "markdown-it-ts": "^0.0.9" + } + }, "node_modules/streamx": { "version": "2.23.0", "license": "MIT", @@ -15403,8 +15546,7 @@ }, "node_modules/tailwindcss": { "version": "4.1.18", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", @@ -15562,6 +15704,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -15587,6 +15730,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -15854,7 +15998,6 @@ "version": "5.9.3", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15885,6 +16028,12 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/ufo": { "version": "1.6.3", "license": "MIT" @@ -16220,7 +16369,6 @@ "node_modules/vite": { "version": "7.3.1", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -17111,7 +17259,6 @@ "node_modules/zod": { "version": "4.3.6", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 1d34310..95b1a47 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "immer": "^11.1.3", "lucide-react": "^0.563.0", "mammoth": "^1.11.0", + "markstream-react": "^0.0.45", "mermaid": "^11.12.3", "monaco-editor": "^0.55.1", "motion": "^12.34.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39bf19a..8136e53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,9 +35,6 @@ importers: '@tailwindcss/vite': specifier: ^4.1.18 version: 4.2.2(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)) - '@tanstack/react-virtual': - specifier: ^3.13.23 - version: 3.13.23(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@toon-format/toon': specifier: ^2.1.0 version: 2.1.0 @@ -54,7 +51,7 @@ importers: specifier: ^0.16.0 version: 0.16.0 '@xterm/addon-unicode11': - specifier: ^0.9.0 + specifier: 0.9.0 version: 0.9.0 '@xterm/addon-web-links': specifier: ^0.12.0 @@ -113,6 +110,9 @@ importers: mammoth: specifier: ^1.11.0 version: 1.12.0 + markstream-react: + specifier: ^0.0.45 + version: 0.0.45(katex@0.16.45)(mermaid@11.14.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) mermaid: specifier: ^11.12.3 version: 11.14.0 @@ -182,9 +182,6 @@ importers: tw-animate-css: specifier: ^1.4.0 version: 1.4.0 - virtua: - specifier: ^0.48.3 - version: 0.48.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ws: specifier: ^8.19.0 version: 8.20.0 @@ -2031,15 +2028,6 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/react-virtual@3.13.23': - resolution: {integrity: sha512-XnMRnHQ23piOVj2bzJqHrRrLg4r+F86fuBcwteKfbIjJrtGxb4z7tIvPVAe4B+4UVwo9G4Giuz5fmapcrnZ0OQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - '@tanstack/virtual-core@3.13.23': - resolution: {integrity: sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==} - '@toon-format/toon@2.1.0': resolution: {integrity: sha512-JwWptdF5eOA0HaQxbKAzkpQtR4wSWTEfDlEy/y3/4okmOAX1qwnpLZMmtEWr+ncAhTTY1raCKH0kteHhSXnQqg==} @@ -3230,6 +3218,10 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -4188,6 +4180,9 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -4278,6 +4273,31 @@ packages: engines: {node: '>=12.0.0'} hasBin: true + markdown-it-container@4.0.0: + resolution: {integrity: sha512-HaNccxUH0l7BNGYbFbjmGpf5aLHAMTinqRZQAEQbMr2cdD3z91Q6kIo1oUn1CQndkT03jat6ckrdRYuwwqLlQw==} + + markdown-it-footnote@4.0.0: + resolution: {integrity: sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==} + + markdown-it-ins@4.0.0: + resolution: {integrity: sha512-sWbjK2DprrkINE4oYDhHdCijGT+MIDhEupjSHLXe5UXeVr5qmVxs/nTUVtgi0Oh/qtF+QKV0tNWDhQBEPxiMew==} + + markdown-it-mark@4.0.0: + resolution: {integrity: sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg==} + + markdown-it-sub@2.0.0: + resolution: {integrity: sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==} + + markdown-it-sup@2.0.0: + resolution: {integrity: sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==} + + markdown-it-task-checkbox@1.0.6: + resolution: {integrity: sha512-7pxkHuvqTOu3iwVGmDPeYjQg+AIS9VQxzyLP9JCg9lBjgPAJXGEkChK6A2iFuj3tS0GV3HG2u5AMNhcQqwxpJw==} + + markdown-it-ts@0.0.9: + resolution: {integrity: sha512-krzuXIaUUiXI8SLlyssp1q4FzDlnfP3wrJwb7ulzwa1DLTYnYDtVe9R5NLTi2FZTo59APCD6to5JnFFj5bs0nA==} + engines: {node: '>=18'} + markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} @@ -4291,6 +4311,31 @@ packages: engines: {node: '>= 20'} hasBin: true + markstream-react@0.0.45: + resolution: {integrity: sha512-4LokzzYkXLORlJ2WS5zgAGcsBe+lBZV3h6m+ZljnwkV2To8VB2UaYiQuWvBUD1Tju1jI9qzQxvchSBH4DxmLuw==} + peerDependencies: + '@antv/infographic': ^0.2.3 + '@terrastruct/d2': '>=0.1.33' + katex: '>=0.16.22' + mermaid: '>=11' + react: '>=18' + react-dom: '>=18' + stream-markdown: '>=0.0.15' + stream-monaco: '>=0.0.38' + peerDependenciesMeta: + '@antv/infographic': + optional: true + '@terrastruct/d2': + optional: true + katex: + optional: true + mermaid: + optional: true + stream-markdown: + optional: true + stream-monaco: + optional: true + matcher@3.0.0: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} @@ -4344,6 +4389,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -4904,6 +4952,10 @@ packages: pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -5352,6 +5404,9 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + stream-markdown-parser@0.0.90: + resolution: {integrity: sha512-mTv8MlN593DVAjIPaSm/IZCQb3X3v7fwfT0P4a/7KMK5bTDK+8p6l/C1S7IRPYGwss9bpfpD6gMRZFSrFC7w8A==} + streamx@2.25.0: resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} @@ -5571,6 +5626,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} @@ -5696,26 +5754,6 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - virtua@0.48.8: - resolution: {integrity: sha512-jpsxOw5V4B6hg44JePRLo9DL0TV7N1lBEVtPjKpAJebXyhI2s9lfiXJESaLapNtr3vtiSk/pWHiLf7B2a6UcgQ==} - peerDependencies: - react: '>=16.14.0' - react-dom: '>=16.14.0' - solid-js: '>=1.0' - svelte: '>=5.0' - vue: '>=3.2' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - solid-js: - optional: true - svelte: - optional: true - vue: - optional: true - vite@7.3.2: resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7609,14 +7647,6 @@ snapshots: tailwindcss: 4.2.2 vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0) - '@tanstack/react-virtual@3.13.23(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/virtual-core': 3.13.23 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - - '@tanstack/virtual-core@3.13.23': {} - '@toon-format/toon@2.1.0': {} '@types/archiver@7.0.0': @@ -9064,6 +9094,8 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.2 + entities@4.5.0: {} + env-paths@2.2.1: {} err-code@2.0.3: {} @@ -10190,6 +10222,10 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -10293,12 +10329,45 @@ snapshots: underscore: 1.13.8 xmlbuilder: 10.1.1 + markdown-it-container@4.0.0: {} + + markdown-it-footnote@4.0.0: {} + + markdown-it-ins@4.0.0: {} + + markdown-it-mark@4.0.0: {} + + markdown-it-sub@2.0.0: {} + + markdown-it-sup@2.0.0: {} + + markdown-it-task-checkbox@1.0.6: {} + + markdown-it-ts@0.0.9: + dependencies: + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + markdown-table@3.0.4: {} marked@14.0.0: {} marked@16.4.2: {} + markstream-react@0.0.45(katex@0.16.45)(mermaid@11.14.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@floating-ui/dom': 1.7.6 + clsx: 2.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + stream-markdown-parser: 0.0.90 + optionalDependencies: + katex: 0.16.45 + mermaid: 11.14.0 + matcher@3.0.0: dependencies: escape-string-regexp: 4.0.0 @@ -10459,6 +10528,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdurl@2.0.0: {} + media-typer@1.1.0: {} merge-descriptors@2.0.0: {} @@ -11140,6 +11211,8 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 + punycode.js@2.3.1: {} + punycode@2.3.1: {} qs@6.15.0: @@ -11777,6 +11850,17 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + stream-markdown-parser@0.0.90: + dependencies: + markdown-it-container: 4.0.0 + markdown-it-footnote: 4.0.0 + markdown-it-ins: 4.0.0 + markdown-it-mark: 4.0.0 + markdown-it-sub: 2.0.0 + markdown-it-sup: 2.0.0 + markdown-it-task-checkbox: 1.0.6 + markdown-it-ts: 0.0.9 + streamx@2.25.0: dependencies: events-universal: 1.0.1 @@ -12064,6 +12148,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + ufo@1.6.3: {} unbox-primitive@1.1.0: @@ -12206,11 +12292,6 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - virtua@0.48.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.27.7 diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css index 602dd85..e4b0a61 100644 --- a/src/renderer/src/assets/main.css +++ b/src/renderer/src/assets/main.css @@ -1,5 +1,6 @@ @import 'tailwindcss'; @import 'tw-animate-css'; +@import 'markstream-react/index.css'; @plugin "@tailwindcss/typography"; @custom-variant dark (&:is(.dark *)); diff --git a/src/renderer/src/components/chat/AssistantMessage.tsx b/src/renderer/src/components/chat/AssistantMessage.tsx index 97db7e7..380271a 100644 --- a/src/renderer/src/components/chat/AssistantMessage.tsx +++ b/src/renderer/src/components/chat/AssistantMessage.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { useState, useCallback, useMemo, useEffect, useId, type ReactNode } from 'react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' +import MarkstreamRenderer from 'markstream-react' import Markdown, { type Components } from 'react-markdown' import remarkGfm from 'remark-gfm' import mermaid from 'mermaid' @@ -134,6 +135,8 @@ interface AssistantMessageProps { } const MARKDOWN_WRAPPER_CLASS = 'text-sm leading-relaxed text-foreground break-words' +const MARKSTREAM_CLASS = + 'opencowork-markstream [&_.markdown-renderer]:contents [&_.node-slot]:contents [&_.node-content]:contents [&_.paragraph-node]:my-1 [&_.paragraph-node]:leading-snug [&_.paragraph-node]:whitespace-pre-wrap [&_.paragraph-node]:break-words [&_.heading-node]:mt-3 [&_.heading-node]:mb-1.5 [&_.heading-node]:text-foreground [&_.heading-1]:text-lg [&_.heading-1]:leading-snug [&_.heading-2]:text-base [&_.heading-2]:leading-snug [&_.heading-3]:text-sm [&_.heading-3]:leading-snug [&_.heading-4]:text-sm [&_.heading-4]:leading-snug [&_.heading-5]:text-sm [&_.heading-5]:leading-snug [&_.heading-6]:text-sm [&_.heading-6]:leading-snug [&_.list-node]:my-1 [&_.list-node]:pl-4 [&_.list-node]:space-y-0.5 [&_.list-item-node]:leading-snug [&_.list-item-node]:break-words [&_.list-item-node_.paragraph-node]:m-0 [&_.table-node-wrapper]:my-2 [&_.table-node]:text-sm [&_.table-node_th]:whitespace-pre-wrap [&_.table-node_th]:break-words [&_.table-node_td]:whitespace-pre-wrap [&_.table-node_td]:break-words [&_.link-node]:text-primary [&_.link-node]:underline [&_.link-node]:underline-offset-2 [&_.link-node]:break-all [&_.link-node:hover]:text-primary/80 [&_.inline-code]:rounded [&_.inline-code]:bg-muted [&_.inline-code]:px-1.5 [&_.inline-code]:py-0.5 [&_.inline-code]:text-xs [&_.inline-code]:font-mono [&_.code-block-node]:my-3 [&_.code-block-node]:whitespace-pre-wrap [&_.code-block-node]:break-all [&_.code-block-node]:text-xs [&_.code-block-node]:leading-6 [&_.code-block-node]:font-mono [&_.code-block-container]:my-3 [&_.code-block-container]:border-border/60 [&_.code-block-container]:shadow-sm [&_.code-block-container]:bg-[hsl(var(--muted))] [&_.code-block-container.is-dark]:bg-[hsl(var(--muted))] [&_.code-block-header]:bg-muted/40 [&_.code-block-header]:px-3 [&_.code-block-header]:py-1.5 [&_.code-block-header]:border-border/60 [&_.code-block-content]:max-h-[500px] [&_.code-fallback-plain]:whitespace-pre-wrap [&_.code-fallback-plain]:break-all [&_.code-fallback-plain]:text-xs [&_.code-fallback-plain]:leading-6 [&_.code-fallback-plain]:font-mono [&_.blockquote-node]:my-2 [&_.blockquote-node]:border-l-border [&_.blockquote-node]:pl-3 [&_.blockquote-node]:text-muted-foreground' const THINK_OPEN_TAG_RE = /<\s*think\s*>/i const SPECIAL_TOOLS = new Set([ 'TaskCreate', @@ -924,15 +927,42 @@ function StreamingMarkdownContent({ isStreaming: boolean }): React.JSX.Element { const liveOutputAnimationStyle = useSettingsStore((s) => s.liveOutputAnimationStyle) + const handleMarkstreamClick = useCallback((event: React.MouseEvent) => { + const link = (event.target as HTMLElement | null)?.closest('a[href]') + const href = link?.getAttribute('href') + if (!href) return + const handled = openMarkdownHref(href) + if (handled) event.preventDefault() + }, []) + + if (!text.trim()) { + return
{text}
+ } + // Fast path: during streaming we render plain text to avoid re-parsing the markdown - // AST on every delta. The full MarkdownContent kicks in after the stream ends, and - // since it's memoized on `text`, re-renders that don't change content are free. + // AST on every delta with react-markdown. Markstream is built for partial LLM output, + // so we can still show markdown structure before the stream is complete. if (isStreaming) { return ( -
- {text} +
+
) }