From bd9ba9b52651ddffc95a77e264b3bf0c261604d0 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 18:28:25 -0400 Subject: [PATCH 01/79] Fix scanner probes returning 200 via SPA catch-all The 404 handler was unconditionally serving index.html (200) for all non-API, non-static paths, including scanner probes for .php, .asp, .cgi etc. Added _SPA_EXTENSIONS set so paths with unknown extensions get a real 404 instead of a misleading 200. Co-Authored-By: Claude Sonnet 4.6 --- src/fabledassistant/app.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/fabledassistant/app.py b/src/fabledassistant/app.py index b823292..53d4585 100644 --- a/src/fabledassistant/app.py +++ b/src/fabledassistant/app.py @@ -238,17 +238,34 @@ def create_app() -> Quart: resp.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" return resp + # File extensions that belong to the SPA or its assets. + # Anything else with an extension is not a valid app path and gets a hard 404. + _SPA_EXTENSIONS = { + "", ".html", ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", + ".svg", ".webp", ".woff", ".woff2", ".ttf", ".otf", ".map", ".json", + } + @app.errorhandler(404) async def handle_404(error): # Return JSON 404 for API routes if request.path.startswith("/api/"): return jsonify({"error": "Not found"}), 404 - # Try to serve static file + + # Try to serve a real static file first path = request.path.lstrip("/") file_path = STATIC_DIR / path if path and file_path.is_file(): return await send_from_directory(STATIC_DIR, path) - # SPA fallback + + # Reject paths with file extensions the app doesn't serve. + # This turns scanner probes (.php, .asp, .cgi, etc.) into honest 404s + # instead of serving them the Vue SPA with a misleading 200. + from pathlib import PurePosixPath + suffix = PurePosixPath(request.path).suffix.lower() + if suffix not in _SPA_EXTENSIONS: + return "", 404 + + # SPA fallback for clean client-side routes (/notes/123, /chat, etc.) resp = await make_response( await send_from_directory(STATIC_DIR, "index.html") ) From 3d861d08eb9449e2ab4d1888608d96314bd0438a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 18:42:07 -0400 Subject: [PATCH 02/79] Skip semantic duplicate check for bare-title tasks/notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The semantic similarity check was flagging unrelated short-title tasks as duplicates (e.g. "Lore: Shell 0" matching "Lore: Reinitialization 0" at 91%) because with no body, the embedding is purely title-based and co-domain tasks in the same project share a tight embedding neighborhood. Only run the semantic check when the body is ≥ 80 chars — enough content to make a meaningful comparison. The fuzzy title check already covers exact/near-exact title duplicates. Co-Authored-By: Claude Sonnet 4.6 --- src/fabledassistant/services/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fabledassistant/services/tools.py b/src/fabledassistant/services/tools.py index 6b8378a..e8bccba 100644 --- a/src/fabledassistant/services/tools.py +++ b/src/fabledassistant/services/tools.py @@ -825,7 +825,7 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict: item_type = "task" if near.status is not None else "note" return {"success": False, "error": f"A {item_type} with a very similar title '{near.title}' already exists (id: {near.id}, similarity: {ratio:.0%}). Use update_note to modify it instead of creating a duplicate."} - if not arguments.get("confirmed"): + if not arguments.get("confirmed") and len(task_body.strip()) >= 80: from fabledassistant.services.embeddings import semantic_search_notes as _ssn sem_query = f"{task_title}\n{task_body}".strip() sem_hits = await _ssn(user_id, sem_query, limit=3, threshold=0.87) @@ -903,7 +903,7 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict: item_type = "task" if near.status is not None else "note" return {"success": False, "error": f"A {item_type} with a very similar title '{near.title}' already exists (id: {near.id}, similarity: {ratio:.0%}). Use update_note to modify it instead of creating a duplicate."} - if not arguments.get("confirmed"): + if not arguments.get("confirmed") and len(note_body.strip()) >= 80: from fabledassistant.services.embeddings import semantic_search_notes as _ssn sem_query = f"{note_title}\n{note_body}".strip() sem_hits = await _ssn(user_id, sem_query, limit=3, threshold=0.87) From c6211e52391e71724ef3a6de7f2e275172bda10f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 18:53:58 -0400 Subject: [PATCH 03/79] Gate Docker build on CI passing Merged ci.yml and build.yml into a single workflow. The build job now declares needs: [typecheck, lint, test] so images are only pushed when all checks are green. PRs run CI only; branch/tag pushes run CI then build if successful. Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/build.yml | 67 ------------------------------------ .forgejo/workflows/ci.yml | 65 ++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 70 deletions(-) delete mode 100644 .forgejo/workflows/build.yml diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml deleted file mode 100644 index ec62ff4..0000000 --- a/.forgejo/workflows/build.yml +++ /dev/null @@ -1,67 +0,0 @@ -# Branch push (dev): builds and pushes :dev + : -# Branch push (main): builds and pushes :latest + : -# Tag push (v1.2.0): builds and pushes :latest + : + :v1.2.0 -# -# To cut a versioned release: -# git tag v1.2.0 && git push origin v1.2.0 -# -# Required secrets (repo → Settings → Secrets → Actions): -# REGISTRY_USER — your Forgejo username -# REGISTRY_TOKEN — Forgejo PAT with write:packages scope -name: Build & push image - -on: - push: - branches: [main, dev] - tags: ["v*"] - paths: - - "src/**" - - "frontend/**" - - "Dockerfile" - - "pyproject.toml" - - "alembic/**" - - "alembic.ini" - - ".forgejo/workflows/build.yml" - -env: - REGISTRY: git.fabledsword.com - IMAGE: git.fabledsword.com/bvandeusen/fabledassistant - -jobs: - build: - name: Build & push - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Generate image tags - id: tags - run: | - TAGS="${{ env.IMAGE }}:${{ github.sha }}" - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - TAGS="$TAGS,${{ env.IMAGE }}:latest" - elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then - TAGS="$TAGS,${{ env.IMAGE }}:dev" - elif [[ "${{ github.ref }}" == refs/tags/* ]]; then - TAGS="$TAGS,${{ env.IMAGE }}:latest,${{ env.IMAGE }}:${{ github.ref_name }}" - fi - echo "value=$TAGS" >> $GITHUB_OUTPUT - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Forgejo registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.REGISTRY_USER }} - password: ${{ secrets.REGISTRY_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ${{ steps.tags.outputs.value }} - cache-from: type=registry,ref=${{ env.IMAGE }}:cache - cache-to: type=registry,ref=${{ env.IMAGE }}:cache,mode=max diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9a30c52..7568908 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -1,14 +1,28 @@ -# Runs on every push and pull request. -# Fast checks only — no Docker build. Second runs take ~30s due to caching. -name: CI +# CI runs first; build only proceeds if all checks pass. +# +# Push to dev: typecheck + lint + test → build :dev + : +# Push to main: typecheck + lint + test → build :latest + : +# Tag v*: typecheck + lint + test → build :latest + : + : +# Pull request: typecheck + lint + test only (no build) +# +# Required secrets (repo → Settings → Secrets → Actions): +# REGISTRY_USER — your Forgejo username +# REGISTRY_TOKEN — Forgejo PAT with write:packages scope +name: CI & Build on: push: + branches: [main, dev] + tags: ["v*"] paths: - "src/**" - "frontend/**" - "tests/**" - "pyproject.toml" + - "alembic/**" + - "alembic.ini" + - "Dockerfile" + - "assets/**" - ".forgejo/workflows/ci.yml" pull_request: paths: @@ -18,6 +32,10 @@ on: - "pyproject.toml" - ".forgejo/workflows/ci.yml" +env: + REGISTRY: git.fabledsword.com + IMAGE: git.fabledsword.com/bvandeusen/fabledassistant + jobs: typecheck: name: TypeScript typecheck @@ -70,3 +88,44 @@ jobs: - name: Run tests run: pytest tests/ -v + + build: + name: Build & push image + needs: [typecheck, lint, test] + # Only build on branch/tag pushes — not on pull requests + if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate image tags + id: tags + run: | + TAGS="${{ env.IMAGE }}:${{ github.sha }}" + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + TAGS="$TAGS,${{ env.IMAGE }}:latest" + elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then + TAGS="$TAGS,${{ env.IMAGE }}:dev" + elif [[ "${{ github.ref }}" == refs/tags/* ]]; then + TAGS="$TAGS,${{ env.IMAGE }}:latest,${{ env.IMAGE }}:${{ github.ref_name }}" + fi + echo "value=$TAGS" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Forgejo registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.tags.outputs.value }} + cache-from: type=registry,ref=${{ env.IMAGE }}:cache + cache-to: type=registry,ref=${{ env.IMAGE }}:cache,mode=max From 8b96115bb2d30915bd6bd0d41639835adb78e905 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 19:57:33 -0400 Subject: [PATCH 04/79] Bump vue to 3.5.30 (patch) Co-Authored-By: Claude Sonnet 4.6 --- frontend/package-lock.json | 122 ++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 026ec3f..9e53adc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,7 +20,7 @@ "dompurify": "^3.1.0", "marked": "^15.0.0", "pinia": "^2.2.0", - "vue": "^3.5.0", + "vue": "3.5.30", "vue-router": "^4.4.0" }, "devDependencies": { @@ -1765,53 +1765,53 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", - "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.27", - "entities": "^7.0.0", + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", - "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", - "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.27", - "@vue/compiler-dom": "3.5.27", - "@vue/compiler-ssr": "3.5.27", - "@vue/shared": "3.5.27", + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.6", + "postcss": "^8.5.8", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", - "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/compiler-vue2": { @@ -1857,53 +1857,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz", - "integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.27" + "@vue/shared": "3.5.30" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz", - "integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz", - "integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.27", - "@vue/runtime-core": "3.5.27", - "@vue/shared": "3.5.27", + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz", - "integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" }, "peerDependencies": { - "vue": "3.5.27" + "vue": "3.5.30" } }, "node_modules/@vue/shared": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", - "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", "license": "MIT" }, "node_modules/alien-signals": { @@ -2689,9 +2689,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "funding": [ { "type": "opencollective", @@ -3127,16 +3127,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", - "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.27", - "@vue/compiler-sfc": "3.5.27", - "@vue/runtime-dom": "3.5.27", - "@vue/server-renderer": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" }, "peerDependencies": { "typescript": "*" diff --git a/frontend/package.json b/frontend/package.json index edfbf05..c3ee76c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,7 @@ "dompurify": "^3.1.0", "marked": "^15.0.0", "pinia": "^2.2.0", - "vue": "^3.5.0", + "vue": "3.5.30", "vue-router": "^4.4.0" }, "devDependencies": { From c65aad6639b3afe63286c8cbd905c62003b17097 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 21:30:55 -0400 Subject: [PATCH 05/79] Upgrade all major frontend dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TipTap 2 → 3: Extension from @tiptap/core, Placeholder from @tiptap/extensions, TaskList/TaskItem from @tiptap/extension-list, link: false in StarterKit (now bundles Link), @tiptap/core added - marked 15 → 17: heading renderer updated to tokens/parseInline API - Pinia 2 → 3, Vue Router 4 → 5 (no code changes required) - Vite 6 → 7, @vitejs/plugin-vue 5 → 6, vue-tsc 2 → 3 - TypeScript 5.6 → 5.9: fixed Uint8Array strictness in push.ts, removed unused bodyEl ref in NoteViewerView.vue - .npmrc: legacy-peer-deps=true for TipTap v3 peer dep resolution TipTap 3 new capabilities now available: static renderer (createStaticRenderer), MarkViews, @tiptap/extensions package. Co-Authored-By: Claude Sonnet 4.6 --- frontend/.npmrc | 1 + frontend/package-lock.json | 1416 +++++++++++------ frontend/package.json | 30 +- frontend/src/components/TiptapEditor.vue | 6 +- frontend/src/extensions/SlashCommands.ts | 2 +- frontend/src/extensions/TagDecoration.ts | 2 +- frontend/src/extensions/TagSuggestion.ts | 2 +- frontend/src/extensions/WikilinkDecoration.ts | 2 +- frontend/src/extensions/WikilinkSuggestion.ts | 2 +- frontend/src/stores/push.ts | 5 +- frontend/src/utils/markdown.ts | 5 +- frontend/src/views/NoteViewerView.vue | 2 - 12 files changed, 950 insertions(+), 525 deletions(-) create mode 100644 frontend/.npmrc diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9e53adc..8fb6d7d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,28 +8,44 @@ "name": "fabledassistant-frontend", "version": "0.1.0", "dependencies": { - "@tiptap/extension-link": "^2.11.0", - "@tiptap/extension-placeholder": "^2.11.0", - "@tiptap/extension-task-item": "^2.27.2", - "@tiptap/extension-task-list": "^2.27.2", - "@tiptap/pm": "^2.11.0", - "@tiptap/starter-kit": "^2.11.0", - "@tiptap/suggestion": "^2.11.0", - "@tiptap/vue-3": "^2.11.0", + "@tiptap/core": "^3.0.0", + "@tiptap/extension-link": "^3.0.0", + "@tiptap/extension-list": "^3.0.0", + "@tiptap/extensions": "^3.0.0", + "@tiptap/pm": "^3.0.0", + "@tiptap/starter-kit": "^3.0.0", + "@tiptap/suggestion": "^3.0.0", + "@tiptap/vue-3": "^3.0.0", "d3": "^7", "dompurify": "^3.1.0", - "marked": "^15.0.0", - "pinia": "^2.2.0", + "marked": "^17.0.0", + "pinia": "^3.0.0", "vue": "3.5.30", - "vue-router": "^4.4.0" + "vue-router": "^5.0.0" }, "devDependencies": { "@types/d3": "^7", "@types/dompurify": "^3.0.0", - "@vitejs/plugin-vue": "^5.1.0", - "typescript": "~5.6.0", - "vite": "^6.0.0", - "vue-tsc": "^2.1.0" + "@vitejs/plugin-vue": "^6.0.0", + "typescript": "~5.9.0", + "vite": "^7.0.0", + "vue-tsc": "^3.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { @@ -79,9 +95,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -96,9 +112,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -113,9 +129,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -130,9 +146,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -147,9 +163,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -164,9 +180,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -181,9 +197,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -198,9 +214,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -215,9 +231,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -232,9 +248,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -249,9 +265,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -266,9 +282,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -283,9 +299,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -300,9 +316,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -317,9 +333,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -334,9 +350,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -351,9 +367,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -368,9 +384,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], @@ -385,9 +401,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -402,9 +418,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ "arm64" ], @@ -419,9 +435,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -436,9 +452,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", "cpu": [ "arm64" ], @@ -453,9 +469,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -470,9 +486,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -487,9 +503,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -504,9 +520,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -520,20 +536,77 @@ "node": ">=18" } }, + "node_modules/@floating-ui/core": { + "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", + "optional": true, + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT", + "optional": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@remirror/core-constants": { @@ -542,6 +615,13 @@ "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", "license": "MIT" }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", @@ -932,230 +1012,214 @@ ] }, "node_modules/@tiptap/core": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.27.2.tgz", - "integrity": "sha512-ABL1N6eoxzDzC1bYvkMbvyexHacszsKdVPYqhl5GwHLOvpZcv9VE9QaKwDILTyz5voCA0lGcAAXZp+qnXOk5lQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.1.tgz", + "integrity": "sha512-SwkPEWIfaDEZjC8SEIi4kZjqIYUbRgLUHUuQezo5GbphUNC8kM1pi3C3EtoOPtxXrEbY6e4pWEzW54Pcrd+rVA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^2.7.0" + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-blockquote": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.27.2.tgz", - "integrity": "sha512-oIGZgiAeA4tG3YxbTDfrmENL4/CIwGuP3THtHsNhwRqwsl9SfMk58Ucopi2GXTQSdYXpRJ0ahE6nPqB5D6j/Zw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.1.tgz", + "integrity": "sha512-WzNXk/63PQI2fav4Ta6P0GmYRyu8Gap1pV3VUqaVK829iJ6Zt1T21xayATHEHWMK27VT1GLPJkx9Ycr2jfDyQw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-bold": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.27.2.tgz", - "integrity": "sha512-bR7J5IwjCGQ0s3CIxyMvOCnMFMzIvsc5OVZKscTN5UkXzFsaY6muUAIqtKxayBUucjtUskm5qZowJITCeCb1/A==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.1.tgz", + "integrity": "sha512-fz++Qv6Rk/Hov0IYG/r7TJ1Y4zWkuGONe0UN5g0KY32NIMg3HeOHicbi4xsNWTm9uAOl3eawWDkezEMrleObMw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.27.2.tgz", - "integrity": "sha512-VkwlCOcr0abTBGzjPXklJ92FCowG7InU8+Od9FyApdLNmn0utRYGRhw0Zno6VgE9EYr1JY4BRnuSa5f9wlR72w==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.20.1.tgz", + "integrity": "sha512-XaPvO6aCoWdFnCBus0s88lnj17NR/OopV79i8Qhgz3WMR0vrsL5zsd45l0lZuu9pSvm5VW47SoxakkJiZC1suw==", "license": "MIT", + "optional": true, "dependencies": { - "tippy.js": "^6.3.7" + "@floating-ui/dom": "^1.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-bullet-list": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.27.2.tgz", - "integrity": "sha512-gmFuKi97u5f8uFc/GQs+zmezjiulZmFiDYTh3trVoLRoc2SAHOjGEB7qxdx7dsqmMN7gwiAWAEVurLKIi1lnnw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.20.1.tgz", + "integrity": "sha512-mbrlvOZo5OF3vLhp+3fk9KuL/6J/wsN0QxF6ZFRAHzQ9NkJdtdfARcBeBnkWXGN8inB6YxbTGY1/E4lmBkOpOw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/extension-list": "^3.20.1" } }, "node_modules/@tiptap/extension-code": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.27.2.tgz", - "integrity": "sha512-7X9AgwqiIGXoZX7uvdHQsGsjILnN/JaEVtqfXZnPECzKGaWHeK/Ao4sYvIIIffsyZJA8k5DC7ny2/0sAgr2TuA==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.1.tgz", + "integrity": "sha512-509DHINIA/Gg+eTG7TEkfsS8RUiPLH5xZNyLRT0A1oaoaJmECKfrV6aAm05IdfTyqDqz6LW5pbnX6DdUC4keug==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-code-block": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.27.2.tgz", - "integrity": "sha512-KgvdQHS4jXr79aU3wZOGBIZYYl9vCB7uDEuRFV4so2rYrfmiYMw3T8bTnlNEEGe4RUeAms1i4fdwwvQp9nR1Dw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.20.1.tgz", + "integrity": "sha512-vKejwBq+Nlj4Ybd3qOyDxIQKzYymdNH+8eXkKwGShk2nfLJIxq69DCyGvmuHgipIO1qcYPJ149UNpGN+YGcdmA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-document": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.27.2.tgz", - "integrity": "sha512-CFhAYsPnyYnosDC4639sCJnBUnYH4Cat9qH5NZWHVvdgtDwu8GZgZn2eSzaKSYXWH1vJ9DSlCK+7UyC3SNXIBA==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.1.tgz", + "integrity": "sha512-9vrqdGmRV7bQCSY3NLgu7UhIwgOCDp4sKqMNsoNRX0aZ021QQMTvBQDPkiRkCf7MNsnWrNNnr52PVnULEn3vFQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-dropcursor": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.27.2.tgz", - "integrity": "sha512-oEu/OrktNoQXq1x29NnH/GOIzQZm8ieTQl3FK27nxfBPA89cNoH4mFEUmBL5/OFIENIjiYG3qWpg6voIqzswNw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.20.1.tgz", + "integrity": "sha512-K18L9FX4znn+ViPSIbTLOGcIaXMx/gLNwAPE8wPLwswbHhQqdiY1zzdBw6drgOc1Hicvebo2dIoUlSXOZsOEcw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/extensions": "^3.20.1" } }, "node_modules/@tiptap/extension-floating-menu": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.27.2.tgz", - "integrity": "sha512-GUN6gPIGXS7ngRJOwdSmtBRBDt9Kt9CM/9pSwKebhLJ+honFoNA+Y6IpVyDvvDMdVNgBchiJLs6qA5H97gAePQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.20.1.tgz", + "integrity": "sha512-BeDC6nfOesIMn5pFuUnkEjOxGv80sOJ8uk1mdt9/3Fkvra8cB9NIYYCVtd6PU8oQFmJ8vFqPrRkUWrG5tbqnOg==", "license": "MIT", - "dependencies": { - "tippy.js": "^6.3.7" - }, + "optional": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.27.2.tgz", - "integrity": "sha512-/c9VF1HBxj+AP54XGVgCmD9bEGYc5w5OofYCFQgM7l7PB1J00A4vOke0oPkHJnqnOOyPlFaxO/7N6l3XwFcnKA==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.20.1.tgz", + "integrity": "sha512-kZOtttV6Ai8VUAgEng3h4WKFbtdSNJ6ps7r0cRPY+FctWhVmgNb/JJwwyC+vSilR7nRENAhrA/Cv/RxVlvLw+g==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/extensions": "^3.20.1" } }, "node_modules/@tiptap/extension-hard-break": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.27.2.tgz", - "integrity": "sha512-kSRVGKlCYK6AGR0h8xRkk0WOFGXHIIndod3GKgWU49APuIGDiXd8sziXsSlniUsWmqgDmDXcNnSzPcV7AQ8YNg==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.20.1.tgz", + "integrity": "sha512-9sKpmg/IIdlLXimYWUZ3PplIRcehv4Oc7V1miTqlnAthMzjMqigDkjjgte4JZV67RdnDJTQkRw8TklCAU28Emg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-heading": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.27.2.tgz", - "integrity": "sha512-iM3yeRWuuQR/IRQ1djwNooJGfn9Jts9zF43qZIUf+U2NY8IlvdNsk2wTOdBgh6E0CamrStPxYGuln3ZS4fuglw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.1.tgz", + "integrity": "sha512-unudyfQP6FxnyWinxvPqe/51DG91J6AaJm666RnAubgYMCgym+33kBftx4j4A6qf+ddWYbD00thMNKOnVLjAEQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" - } - }, - "node_modules/@tiptap/extension-history": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.27.2.tgz", - "integrity": "sha512-+hSyqERoFNTWPiZx4/FCyZ/0eFqB9fuMdTB4AC/q9iwu3RNWAQtlsJg5230bf/qmyO6bZxRUc0k8p4hrV6ybAw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-horizontal-rule": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.27.2.tgz", - "integrity": "sha512-WGWUSgX+jCsbtf9Y9OCUUgRZYuwjVoieW5n6mAUohJ9/6gc6sGIOrUpBShf+HHo6WD+gtQjRd+PssmX3NPWMpg==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.20.1.tgz", + "integrity": "sha512-rjFKFXNntdl0jay8oIGFvvykHlpyQTLmrH3Ag2fj3i8yh6MVvqhtaDomYQbw5sxECd5hBkL+T4n2d2DRuVw/QQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-italic": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.27.2.tgz", - "integrity": "sha512-1OFsw2SZqfaqx5Fa5v90iNlPRcqyt+lVSjBwTDzuPxTPFY4Q0mL89mKgkq2gVHYNCiaRkXvFLDxaSvBWbmthgg==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.1.tgz", + "integrity": "sha512-ZYRX13Kt8tR8JOzSXirH3pRpi8x30o7LHxZY58uXBdUvr3tFzOkh03qbN523+diidSVeHP/aMd/+IrplHRkQug==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-link": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.27.2.tgz", - "integrity": "sha512-bnP61qkr0Kj9Cgnop1hxn2zbOCBzNtmawxr92bVTOE31fJv6FhtCnQiD6tuPQVGMYhcmAj7eihtvuEMFfqEPcQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.1.tgz", + "integrity": "sha512-oYTTIgsQMqpkSnJAuAc+UtIKMuI4lv9e1y4LfI1iYm6NkEUHhONppU59smhxHLzb3Ww7YpDffbp5IgDTAiJztA==", "license": "MIT", "dependencies": { "linkifyjs": "^4.3.2" @@ -1165,133 +1229,133 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.1.tgz", + "integrity": "sha512-euBRAn0mkV7R2VEE+AuOt3R0j9RHEMFXamPFmtvTo8IInxDClusrm6mJoDjS8gCGAXsQCRiAe1SCQBPgGbOOwg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/extension-list-item": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.27.2.tgz", - "integrity": "sha512-eJNee7IEGXMnmygM5SdMGDC8m/lMWmwNGf9fPCK6xk0NxuQRgmZHL6uApKcdH6gyNcRPHCqvTTkhEP7pbny/fg==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.20.1.tgz", + "integrity": "sha512-tzgnyTW82lYJkUnadYbatwkI9dLz/OWRSWuFpQPRje/ItmFMWuQ9c9NDD8qLbXPdEYnvrgSAA+ipCD/1G0qA0Q==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/extension-list": "^3.20.1" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.20.1.tgz", + "integrity": "sha512-Dr0xsQKx0XPOgDg7xqoWwfv7FFwZ3WeF3eOjqh3rDXlNHMj1v+UW5cj1HLphrsAZHTrVTn2C+VWPJkMZrSbpvQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.20.1" } }, "node_modules/@tiptap/extension-ordered-list": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.27.2.tgz", - "integrity": "sha512-M7A4tLGJcLPYdLC4CI2Gwl8LOrENQW59u3cMVa+KkwG1hzSJyPsbDpa1DI6oXPC2WtYiTf22zrbq3gVvH+KA2w==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.20.1.tgz", + "integrity": "sha512-Y+3Ad7OwAdagqdYwCnbqf7/to5ypD4NnUNHA0TXRCs7cAHRA8AdgPoIcGFpaaSpV86oosNU3yfeJouYeroffog==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/extension-list": "^3.20.1" } }, "node_modules/@tiptap/extension-paragraph": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.27.2.tgz", - "integrity": "sha512-elYVn2wHJJ+zB9LESENWOAfI4TNT0jqEN34sMA/hCtA4im1ZG2DdLHwkHIshj/c4H0dzQhmsS/YmNC5Vbqab/A==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.1.tgz", + "integrity": "sha512-QFrAtXNyv7JSnomMQc1nx5AnG9mMznfbYJAbdOQYVdbLtAzTfiTuNPNbQrufy5ZGtGaHxDCoaygu2QEfzaKG+Q==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" - } - }, - "node_modules/@tiptap/extension-placeholder": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.27.2.tgz", - "integrity": "sha512-IjsgSVYJRjpAKmIoapU0E2R4E2FPY3kpvU7/1i7PUYisylqejSJxmtJPGYw0FOMQY9oxnEEvfZHMBA610tqKpg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-strike": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.27.2.tgz", - "integrity": "sha512-HHIjhafLhS2lHgfAsCwC1okqMsQzR4/mkGDm4M583Yftyjri1TNA7lzhzXWRFWiiMfJxKtdjHjUAQaHuteRTZw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.1.tgz", + "integrity": "sha512-EYgyma10lpsY+rwbVQL9u+gA7hBlKLSMFH7Zgd37FSxukOjr+HE8iKPQQ+SwbGejyDsPlLT8Z5Jnuxo5Ng90Pg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" - } - }, - "node_modules/@tiptap/extension-task-item": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-task-item/-/extension-task-item-2.27.2.tgz", - "integrity": "sha512-ZBSqj/dygB/Rp5K9qOxRVwASTZCmKVoTq8C59KvMgD/aFjJxhq/w2dZaWkCUEXEep+NmvJqo0kfeAEMY5UDnGg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" - } - }, - "node_modules/@tiptap/extension-task-list": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-task-list/-/extension-task-list-2.27.2.tgz", - "integrity": "sha512-5nupAewdzZ9F3599oAcaK0WkDH04wdACAVBPM4zG7InlIpkbho3txB7zWmm64OxfhCMIMGKiXY1q0bw9i0QBGQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, "node_modules/@tiptap/extension-text": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.27.2.tgz", - "integrity": "sha512-Xk7nYcigljAY0GO9hAQpZ65ZCxqOqaAlTPDFcKerXmlkQZP/8ndx95OgUb1Xf63kmPOh3xypurGS2is3v0MXSA==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.1.tgz", + "integrity": "sha512-7PlIbYW8UenV6NPOXHmv8IcmPGlGx6HFq66RmkJAOJRPXPkTLAiX0N8rQtzUJ6jDEHqoJpaHFEHJw0xzW1yF+A==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" } }, - "node_modules/@tiptap/extension-text-style": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.27.2.tgz", - "integrity": "sha512-Omk+uxjJLyEY69KStpCw5fA9asvV+MGcAX2HOxyISDFoLaL49TMrNjhGAuz09P1L1b0KGXo4ml7Q3v/Lfy4WPA==", + "node_modules/@tiptap/extension-underline": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.1.tgz", + "integrity": "sha512-fmHvDKzwCgnZUwRreq8tYkb1YyEwgzZ6QQkAQ0CsCRtvRMqzerr3Duz0Als4i8voZTuGDEL3VR6nAJbLAb/wPg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0" + "@tiptap/core": "^3.20.1" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.1.tgz", + "integrity": "sha512-JRc/v+OBH0qLTdvQ7HvHWTxGJH73QOf1MC0R8NhOX2QnAbg2mPFv1h+FjGa2gfLGuCXBdWQomjekWkUKbC4e5A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/pm": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.27.2.tgz", - "integrity": "sha512-kaEg7BfiJPDQMKbjVIzEPO3wlcA+pZb2tlcK9gPrdDnEFaec2QTF1sXz2ak2IIb2curvnIrQ4yrfHgLlVA72wA==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.1.tgz", + "integrity": "sha512-6kCiGLvpES4AxcEuOhb7HR7/xIeJWMjZlb6J7e8zpiIh5BoQc7NoRdctsnmFEjZvC19bIasccshHQ7H2zchWqw==", "license": "MIT", "dependencies": { "prosemirror-changeset": "^2.3.0", @@ -1304,14 +1368,14 @@ "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", - "prosemirror-model": "^1.23.0", + "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", - "prosemirror-schema-list": "^1.4.1", + "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", - "prosemirror-view": "^1.37.0" + "prosemirror-view": "^1.38.1" }, "funding": { "type": "github", @@ -1319,32 +1383,35 @@ } }, "node_modules/@tiptap/starter-kit": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.27.2.tgz", - "integrity": "sha512-bb0gJvPoDuyRUQ/iuN52j1//EtWWttw+RXAv1uJxfR0uKf8X7uAqzaOOgwjknoCIDC97+1YHwpGdnRjpDkOBxw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.20.1.tgz", + "integrity": "sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw==", "license": "MIT", "dependencies": { - "@tiptap/core": "^2.27.2", - "@tiptap/extension-blockquote": "^2.27.2", - "@tiptap/extension-bold": "^2.27.2", - "@tiptap/extension-bullet-list": "^2.27.2", - "@tiptap/extension-code": "^2.27.2", - "@tiptap/extension-code-block": "^2.27.2", - "@tiptap/extension-document": "^2.27.2", - "@tiptap/extension-dropcursor": "^2.27.2", - "@tiptap/extension-gapcursor": "^2.27.2", - "@tiptap/extension-hard-break": "^2.27.2", - "@tiptap/extension-heading": "^2.27.2", - "@tiptap/extension-history": "^2.27.2", - "@tiptap/extension-horizontal-rule": "^2.27.2", - "@tiptap/extension-italic": "^2.27.2", - "@tiptap/extension-list-item": "^2.27.2", - "@tiptap/extension-ordered-list": "^2.27.2", - "@tiptap/extension-paragraph": "^2.27.2", - "@tiptap/extension-strike": "^2.27.2", - "@tiptap/extension-text": "^2.27.2", - "@tiptap/extension-text-style": "^2.27.2", - "@tiptap/pm": "^2.27.2" + "@tiptap/core": "^3.20.1", + "@tiptap/extension-blockquote": "^3.20.1", + "@tiptap/extension-bold": "^3.20.1", + "@tiptap/extension-bullet-list": "^3.20.1", + "@tiptap/extension-code": "^3.20.1", + "@tiptap/extension-code-block": "^3.20.1", + "@tiptap/extension-document": "^3.20.1", + "@tiptap/extension-dropcursor": "^3.20.1", + "@tiptap/extension-gapcursor": "^3.20.1", + "@tiptap/extension-hard-break": "^3.20.1", + "@tiptap/extension-heading": "^3.20.1", + "@tiptap/extension-horizontal-rule": "^3.20.1", + "@tiptap/extension-italic": "^3.20.1", + "@tiptap/extension-link": "^3.20.1", + "@tiptap/extension-list": "^3.20.1", + "@tiptap/extension-list-item": "^3.20.1", + "@tiptap/extension-list-keymap": "^3.20.1", + "@tiptap/extension-ordered-list": "^3.20.1", + "@tiptap/extension-paragraph": "^3.20.1", + "@tiptap/extension-strike": "^3.20.1", + "@tiptap/extension-text": "^3.20.1", + "@tiptap/extension-underline": "^3.20.1", + "@tiptap/extensions": "^3.20.1", + "@tiptap/pm": "^3.20.1" }, "funding": { "type": "github", @@ -1352,35 +1419,36 @@ } }, "node_modules/@tiptap/suggestion": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.27.2.tgz", - "integrity": "sha512-dQyvCIg0hcAVeh4fCIVCxogvbp+bF+GpbUb8sNlgnGrmHXnapGxzkvrlHnvneXZxLk/j7CxmBPKJNnm4Pbx4zw==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.20.1.tgz", + "integrity": "sha512-ng7olbzgZhWvPJVJygNQK5153CjquR2eJXpkLq7bRjHlahvt4TH4tGFYvGdYZcXuzbe2g9RoqT7NaPGL9CUq9w==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0" + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1" } }, "node_modules/@tiptap/vue-3": { - "version": "2.27.2", - "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-2.27.2.tgz", - "integrity": "sha512-NahnVLTAQsbLaNU9nGLdGCr88nAeQZJTejjBVQc3EzMdijmE46R44Rosj6O/pj3e7eLj1/gYvc+U/hIVbxMpoQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.20.1.tgz", + "integrity": "sha512-06IsNzIkAC0HPHNSdXf4AgtExnr02BHBLXmUiNrjjhgHdxXDKIB0Yq3hEWEfbWNPr3lr7jK6EaFu2IKFMhoUtQ==", "license": "MIT", - "dependencies": { - "@tiptap/extension-bubble-menu": "^2.27.2", - "@tiptap/extension-floating-menu": "^2.27.2" - }, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.20.1", + "@tiptap/extension-floating-menu": "^3.20.1" + }, "peerDependencies": { - "@tiptap/core": "^2.7.0", - "@tiptap/pm": "^2.7.0", + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "^3.20.1", + "@tiptap/pm": "^3.20.1", "vue": "^3.0.0" } }, @@ -1722,48 +1790,78 @@ "license": "MIT" }, "node_modules/@vitejs/plugin-vue": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", - "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", + "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", "dev": true, "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "vue": "^3.2.25" } }, "node_modules/@volar/language-core": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", - "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", "dev": true, "license": "MIT", "dependencies": { - "@volar/source-map": "2.4.15" + "@volar/source-map": "2.4.28" } }, "node_modules/@volar/source-map": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", - "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", "dev": true, "license": "MIT" }, "node_modules/@volar/typescript": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", - "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.15", + "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, + "node_modules/@vue-macros/common": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", @@ -1814,46 +1912,53 @@ "@vue/shared": "3.5.30" } }, - "node_modules/@vue/compiler-vue2": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", - "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", - "dev": true, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", "license": "MIT", "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" + "@vue/devtools-kit": "^7.7.9" } }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } }, "node_modules/@vue/language-core": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", - "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.5.tgz", + "integrity": "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.15", + "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", - "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", - "alien-signals": "^1.0.3", - "minimatch": "^9.0.3", + "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" } }, "node_modules/@vue/reactivity": { @@ -1906,10 +2011,22 @@ "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", "license": "MIT" }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/alien-signals": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", - "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", + "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", "dev": true, "license": "MIT" }, @@ -1919,21 +2036,60 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", + "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "ast-kit": "^2.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/commander": { @@ -1945,6 +2101,27 @@ "node": ">= 10" } }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -2358,13 +2535,6 @@ "node": ">=12" } }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" - }, "node_modules/delaunator": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", @@ -2399,9 +2569,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2412,32 +2582,32 @@ "node": ">=18" }, "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" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/escape-string-regexp": { @@ -2458,11 +2628,16 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -2491,15 +2666,11 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" }, "node_modules/iconv-lite": { "version": "0.6.3", @@ -2522,6 +2693,42 @@ "node": ">=12" } }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -2537,6 +2744,23 @@ "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", "license": "MIT" }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2546,6 +2770,21 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/markdown-it": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", @@ -2576,15 +2815,15 @@ } }, "node_modules/marked": { - "version": "15.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", - "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz", + "integrity": "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==", "license": "MIT", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/mdurl": { @@ -2593,27 +2832,45 @@ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "license": "MIT" }, - "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mlly": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -2647,6 +2904,18 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2657,7 +2926,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -2667,20 +2935,19 @@ } }, "node_modules/pinia": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", - "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" + "@vue/devtools-api": "^7.7.7" }, "funding": { "url": "https://github.com/sponsors/posva" }, "peerDependencies": { - "typescript": ">=4.4.4", - "vue": "^2.7.0 || ^3.5.11" + "typescript": ">=4.5.0", + "vue": "^3.5.11" }, "peerDependenciesMeta": { "typescript": { @@ -2688,6 +2955,17 @@ } } }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", @@ -2920,6 +3198,41 @@ "node": ">=6" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -2989,6 +3302,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2998,11 +3317,31 @@ "node": ">=0.10.0" } }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -3015,20 +3354,11 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tippy.js": { - "version": "6.3.7", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", - "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", - "license": "MIT", - "dependencies": { - "@popperjs/core": "^2.9.0" - } - }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "devOptional": true, + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -3044,25 +3374,61 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -3071,14 +3437,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -3147,56 +3513,93 @@ } } }, - "node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, "node_modules/vue-router": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", - "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.3.tgz", + "integrity": "sha512-nG1c7aAFac7NYj8Hluo68WyWfc41xkEjaR0ViLHCa3oDvTQ/nIuLJlXJX1NUPw/DXzx/8+OKMng045HHQKQKWw==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.4" + "@babel/generator": "^7.28.6", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.0.6", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" }, "funding": { "url": "https://github.com/sponsors/posva" }, "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.17", + "pinia": "^3.0.4", "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + } } }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.7.tgz", + "integrity": "sha512-tc1TXAxclsn55JblLkFVcIRG7MeSJC4fWsPjfM7qu/IcmPUYnQ5Q8vzWwBpyDY24ZjmZTUCCwjRSNbx58IhlAA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.0.7" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-kit": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.7.tgz", + "integrity": "sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.0.7", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-shared": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.7.tgz", + "integrity": "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==", + "license": "MIT" + }, + "node_modules/vue-router/node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, "node_modules/vue-tsc": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz", - "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.5.tgz", + "integrity": "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==", "dev": true, "license": "MIT", "dependencies": { - "@volar/typescript": "2.4.15", - "@vue/language-core": "2.2.12" + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.2.5" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -3210,6 +3613,27 @@ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", "license": "MIT" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } } } } diff --git a/frontend/package.json b/frontend/package.json index c3ee76c..6dd33ae 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,27 +9,27 @@ "preview": "vite preview" }, "dependencies": { - "@tiptap/extension-link": "^2.11.0", - "@tiptap/extension-placeholder": "^2.11.0", - "@tiptap/extension-task-item": "^2.27.2", - "@tiptap/extension-task-list": "^2.27.2", - "@tiptap/pm": "^2.11.0", - "@tiptap/starter-kit": "^2.11.0", - "@tiptap/suggestion": "^2.11.0", - "@tiptap/vue-3": "^2.11.0", + "@tiptap/core": "^3.0.0", + "@tiptap/extension-link": "^3.0.0", + "@tiptap/extension-list": "^3.0.0", + "@tiptap/extensions": "^3.0.0", + "@tiptap/pm": "^3.0.0", + "@tiptap/starter-kit": "^3.0.0", + "@tiptap/suggestion": "^3.0.0", + "@tiptap/vue-3": "^3.0.0", "d3": "^7", "dompurify": "^3.1.0", - "marked": "^15.0.0", - "pinia": "^2.2.0", + "marked": "^17.0.0", + "pinia": "^3.0.0", "vue": "3.5.30", - "vue-router": "^4.4.0" + "vue-router": "^5.0.0" }, "devDependencies": { "@types/d3": "^7", "@types/dompurify": "^3.0.0", - "@vitejs/plugin-vue": "^5.1.0", - "typescript": "~5.6.0", - "vite": "^6.0.0", - "vue-tsc": "^2.1.0" + "@vitejs/plugin-vue": "^6.0.0", + "typescript": "~5.9.0", + "vite": "^7.0.0", + "vue-tsc": "^3.0.0" } } diff --git a/frontend/src/components/TiptapEditor.vue b/frontend/src/components/TiptapEditor.vue index 455dbab..47f8300 100644 --- a/frontend/src/components/TiptapEditor.vue +++ b/frontend/src/components/TiptapEditor.vue @@ -3,12 +3,11 @@ import { watch, onBeforeUnmount } from "vue"; import { Editor, EditorContent } from "@tiptap/vue-3"; import StarterKit from "@tiptap/starter-kit"; import Link from "@tiptap/extension-link"; -import Placeholder from "@tiptap/extension-placeholder"; +import { Placeholder } from "@tiptap/extensions"; import { marked } from "marked"; import DOMPurify from "dompurify"; import { serializeToMarkdown } from "@/utils/markdownSerializer"; -import TaskList from "@tiptap/extension-task-list"; -import TaskItem from "@tiptap/extension-task-item"; +import { TaskList, TaskItem } from "@tiptap/extension-list"; import { TagDecoration } from "@/extensions/TagDecoration"; import { WikilinkDecoration } from "@/extensions/WikilinkDecoration"; import { WikilinkSuggestion } from "@/extensions/WikilinkSuggestion"; @@ -71,6 +70,7 @@ try { extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3, 4, 5, 6] }, + link: false, }), Link.configure({ openOnClick: false, diff --git a/frontend/src/extensions/SlashCommands.ts b/frontend/src/extensions/SlashCommands.ts index 579deb7..aee1768 100644 --- a/frontend/src/extensions/SlashCommands.ts +++ b/frontend/src/extensions/SlashCommands.ts @@ -1,4 +1,4 @@ -import { Extension } from "@tiptap/vue-3"; +import { Extension } from "@tiptap/core"; import { PluginKey } from "@tiptap/pm/state"; import Suggestion from "@tiptap/suggestion"; import { createSuggestionRenderer } from "./suggestionRenderer"; diff --git a/frontend/src/extensions/TagDecoration.ts b/frontend/src/extensions/TagDecoration.ts index 7512a95..c35d099 100644 --- a/frontend/src/extensions/TagDecoration.ts +++ b/frontend/src/extensions/TagDecoration.ts @@ -1,4 +1,4 @@ -import { Extension } from "@tiptap/vue-3"; +import { Extension } from "@tiptap/core"; import { Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet } from "@tiptap/pm/view"; diff --git a/frontend/src/extensions/TagSuggestion.ts b/frontend/src/extensions/TagSuggestion.ts index eed4664..6b240c1 100644 --- a/frontend/src/extensions/TagSuggestion.ts +++ b/frontend/src/extensions/TagSuggestion.ts @@ -1,4 +1,4 @@ -import { Extension } from "@tiptap/vue-3"; +import { Extension } from "@tiptap/core"; import { PluginKey } from "@tiptap/pm/state"; import Suggestion from "@tiptap/suggestion"; import { createSuggestionRenderer } from "./suggestionRenderer"; diff --git a/frontend/src/extensions/WikilinkDecoration.ts b/frontend/src/extensions/WikilinkDecoration.ts index c2096b3..71805bb 100644 --- a/frontend/src/extensions/WikilinkDecoration.ts +++ b/frontend/src/extensions/WikilinkDecoration.ts @@ -1,4 +1,4 @@ -import { Extension } from "@tiptap/vue-3"; +import { Extension } from "@tiptap/core"; import { Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet } from "@tiptap/pm/view"; diff --git a/frontend/src/extensions/WikilinkSuggestion.ts b/frontend/src/extensions/WikilinkSuggestion.ts index 7b53bd0..a761106 100644 --- a/frontend/src/extensions/WikilinkSuggestion.ts +++ b/frontend/src/extensions/WikilinkSuggestion.ts @@ -1,4 +1,4 @@ -import { Extension } from "@tiptap/vue-3"; +import { Extension } from "@tiptap/core"; import { PluginKey } from "@tiptap/pm/state"; import Suggestion from "@tiptap/suggestion"; import { createSuggestionRenderer } from "./suggestionRenderer"; diff --git a/frontend/src/stores/push.ts b/frontend/src/stores/push.ts index 61d9990..d6e90fa 100644 --- a/frontend/src/stores/push.ts +++ b/frontend/src/stores/push.ts @@ -1,11 +1,12 @@ import { defineStore } from 'pinia' import { ref } from 'vue' -function urlBase64ToUint8Array(base64String: string): Uint8Array { +function urlBase64ToUint8Array(base64String: string): Uint8Array { const padding = '='.repeat((4 - (base64String.length % 4)) % 4) const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/') const rawData = window.atob(base64) - const outputArray = new Uint8Array(rawData.length) + const buf = new ArrayBuffer(rawData.length) + const outputArray = new Uint8Array(buf) for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } diff --git a/frontend/src/utils/markdown.ts b/frontend/src/utils/markdown.ts index 925d626..44672d9 100644 --- a/frontend/src/utils/markdown.ts +++ b/frontend/src/utils/markdown.ts @@ -1,4 +1,4 @@ -import { marked } from "marked"; +import { marked, type RendererThis, type Tokens } from "marked"; import DOMPurify from "dompurify"; import { linkifyTags, linkifyWikilinks } from "@/utils/tags"; @@ -28,7 +28,8 @@ export function stripFirstLineTags(text: string): string { } const headingRenderer = { - heading({ text, depth }: { text: string; depth: number }): string { + heading(this: RendererThis, { tokens, depth }: Tokens.Heading): string { + const text = this.parser.parseInline(tokens); const id = slugify(text); return `${text}`; }, diff --git a/frontend/src/views/NoteViewerView.vue b/frontend/src/views/NoteViewerView.vue index a7b0119..142dcbf 100644 --- a/frontend/src/views/NoteViewerView.vue +++ b/frontend/src/views/NoteViewerView.vue @@ -12,7 +12,6 @@ import TableOfContents from "@/components/TableOfContents.vue"; const route = useRoute(); const router = useRouter(); const store = useNotesStore(); -const bodyEl = ref(null); const backlinks = ref<{ type: string; id: number; title: string }[]>([]); const converting = ref(false); @@ -198,7 +197,6 @@ async function convertToTask() { />
Date: Mon, 9 Mar 2026 21:33:11 -0400 Subject: [PATCH 06/79] Fix Python CI jobs: drop container, install Python 3.12 directly python:3.12-slim has no Node, causing actions/checkout@v4's post-step to fail with 'exec: node not found'. Drop the container: declaration so jobs run on the ubuntu-latest runner (which has Node). Install Python 3.12 via deadsnakes PPA for the test job since the runner base image (Ubuntu 22.04) ships with Python 3.10. Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/ci.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 7568908..9ea3b89 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -60,8 +60,6 @@ jobs: lint: name: Python lint runs-on: ubuntu-latest - container: - image: python:3.12-slim steps: - uses: actions/checkout@v4 @@ -74,20 +72,25 @@ jobs: test: name: Python tests runs-on: ubuntu-latest - container: - image: python:3.12-slim steps: - uses: actions/checkout@v4 - # git is required by setuptools-scm during package build - - name: Install git - run: apt-get update -qq && apt-get install -y -qq git + # The act runner base image ships Ubuntu 22.04 with Python 3.10. + # Our package requires 3.12, so install it from the deadsnakes PPA. + - name: Install Python 3.12 + run: | + apt-get update -qq + apt-get install -y -qq software-properties-common + add-apt-repository -y ppa:deadsnakes/ppa + apt-get update -qq + apt-get install -y -qq python3.12 python3.12-dev python3.12-venv python3-pip git + python3.12 -m ensurepip --upgrade - name: Install package with dev deps - run: pip install -e ".[dev]" + run: python3.12 -m pip install -e ".[dev]" - name: Run tests - run: pytest tests/ -v + run: python3.12 -m pytest tests/ -v build: name: Build & push image From e34f6d6e546194dd4c3aa2961dd1f78877eba52d Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 21:41:14 -0400 Subject: [PATCH 07/79] Bump all GitHub Actions to latest major versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit actions/checkout v4 → v6 actions/setup-node v4 → v6 (Node 24 runtime, fixes punycode warning) docker/setup-buildx-action v3 → v4 (Node 24 + ESM) docker/login-action v3 → v4 (Node 24 + ESM) docker/build-push-action v6 → v7 (Node 24 + ESM) Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9ea3b89..8cf7fed 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -41,9 +41,9 @@ jobs: name: TypeScript typecheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: "20" cache: "npm" @@ -61,7 +61,7 @@ jobs: name: Python lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install ruff run: pip install ruff @@ -73,7 +73,7 @@ jobs: name: Python tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 # The act runner base image ships Ubuntu 22.04 with Python 3.10. # Our package requires 3.12, so install it from the deadsnakes PPA. @@ -99,7 +99,7 @@ jobs: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Generate image tags id: tags @@ -115,17 +115,17 @@ jobs: echo "value=$TAGS" >> $GITHUB_OUTPUT - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Log in to Forgejo registry - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . push: true From 059a2e06d5c6352e7b211c23936406f02828f3b5 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:05:49 -0400 Subject: [PATCH 08/79] Queue concurrent prompts instead of dropping or conflicting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chat store: when sendMessage() is called while streaming, push to a per-conversation queue and return. When the stream ends the next queued message fires automatically via setTimeout(0) to keep the call stack clean. clearQueue() and queuedCount exposed for UI consumption. Queue is cleaned up on conversation delete. ChatView/WorkspaceView: remove the streaming guard from the local sendMessage() functions and the :disabled on the textarea so users can type and submit freely while streaming. Input placeholder changes to "Type to queue next message…" during streaming. A small "⏳ N queued ×" chip appears below the streaming bubble showing queue depth with a cancel button. DashboardChatInput: disable input, attach button, and send button during streaming. The dashboard creates a fresh conversation per message so in-conversation queuing doesn't apply — locking the input is the correct UX here. Placeholder updates to "Generating response…" during streaming. Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/DashboardChatInput.vue | 12 ++-- frontend/src/stores/chat.ts | 58 ++++++++++++++++++- frontend/src/views/ChatView.vue | 40 ++++++++++++- frontend/src/views/WorkspaceView.vue | 33 ++++++++++- 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/DashboardChatInput.vue b/frontend/src/components/DashboardChatInput.vue index 4780f15..cf5fea9 100644 --- a/frontend/src/components/DashboardChatInput.vue +++ b/frontend/src/components/DashboardChatInput.vue @@ -126,7 +126,7 @@ defineExpose({ focus });
+ +
+ + {{ store.queuedCount }} message{{ store.queuedCount > 1 ? 's' : '' }} queued + +
+

{ @keydown="onInputKeydown" @input="autoResize" :placeholder="inputPlaceholder" - :disabled="store.streaming || !store.chatReady" + :disabled="!store.chatReady" rows="1" > + +

{ ref="inputEl" v-model="messageInput" class="chat-input" - placeholder="Message the agent... (Enter to send)" + :placeholder="chatStore.streaming ? 'Type to queue next message… (Enter to queue)' : 'Message the agent… (Enter to send)'" rows="1" - :disabled="chatStore.streaming" @keydown="onInputKeydown" @input="autoResize" > @@ -625,4 +631,25 @@ details[open] .thinking-summary::before { max-height: 300px; overflow-y: auto; } +.queued-indicator { + display: flex; + align-items: center; + gap: 0.4rem; + font-size: 0.8rem; + color: var(--color-text-muted); + padding: 0.3rem 0.75rem; + margin: 0.25rem 0; +} +.queued-cancel { + background: none; + border: none; + cursor: pointer; + color: var(--color-text-muted); + font-size: 1rem; + line-height: 1; + padding: 0 0.2rem; +} +.queued-cancel:hover { + color: var(--color-text); +} From 690270519f65c9c358042be1abac9ab7c708660f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:12:20 -0400 Subject: [PATCH 09/79] Fix push notifications: focus suppression, empty body, error visibility - sw.js: suppress notification when the target chat tab is already focused (clients.matchAll visibility check before showNotification) - generation_task.py: provide meaningful body for tool-only responses (lists tool names instead of sending an empty string that browsers discard); promote scheduling failure from debug to warning - push.py: promote send errors from warning to error with exc_info; log successful sends at INFO so they're visible in normal operation Co-Authored-By: Claude Sonnet 4.6 --- frontend/public/sw.js | 20 ++++++++++++++----- .../services/generation_task.py | 17 ++++++++++++---- src/fabledassistant/services/push.py | 11 ++++++---- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/frontend/public/sw.js b/frontend/public/sw.js index cd54d9c..246a13b 100644 --- a/frontend/public/sw.js +++ b/frontend/public/sw.js @@ -2,12 +2,22 @@ self.addEventListener('push', event => { if (!event.data) return; const data = event.data.json(); + const notifUrl = data.url || '/'; + event.waitUntil( - self.registration.showNotification(data.title || 'Fabled Assistant', { - body: data.body || '', - icon: '/favicon.ico', - badge: '/favicon.ico', - data: { url: data.url || '/' }, + clients.matchAll({ type: 'window', includeUncontrolled: true }).then(clientList => { + // Suppress notification if the user already has the relevant page focused + for (const client of clientList) { + if (client.visibilityState === 'visible' && client.url.includes(notifUrl)) { + return; + } + } + return self.registration.showNotification(data.title || 'Fabled Assistant', { + body: data.body || '', + icon: '/favicon.ico', + badge: '/favicon.ico', + data: { url: notifUrl }, + }); }) ); }); diff --git a/src/fabledassistant/services/generation_task.py b/src/fabledassistant/services/generation_task.py index 7a16c29..5d22ee6 100644 --- a/src/fabledassistant/services/generation_task.py +++ b/src/fabledassistant/services/generation_task.py @@ -358,9 +358,18 @@ async def run_generation( try: from fabledassistant.services.push import send_push_notification, vapid_enabled if vapid_enabled(): - preview = buf.content_so_far[:120].rstrip() - if len(buf.content_so_far) > 120: - preview += "…" + text = buf.content_so_far.strip() + if text: + preview = text[:120].rstrip() + if len(text) > 120: + preview += "…" + else: + # Tool-only response — summarise what was done + tool_names = [tc.get("function") for tc in all_tool_calls if tc.get("function")] + if tool_names: + preview = f"Completed: {', '.join(tool_names[:3])}" + else: + preview = "Action completed" asyncio.create_task(send_push_notification( user_id, title="Response ready", @@ -368,7 +377,7 @@ async def run_generation( url=f"/chat/{conv_id}", )) except Exception: - logger.debug("Failed to schedule push notification", exc_info=True) + logger.warning("Failed to schedule push notification", exc_info=True) # Title generation is non-critical — fire-and-forget so done fires immediately non_system = [m for m in messages if m["role"] != "system"] diff --git a/src/fabledassistant/services/push.py b/src/fabledassistant/services/push.py index c67f3bb..87256ad 100644 --- a/src/fabledassistant/services/push.py +++ b/src/fabledassistant/services/push.py @@ -190,7 +190,7 @@ async def send_push_notification( ) return response.status_code, sub.endpoint except Exception as e: - logger.warning("Push send failed for sub %d: %s", sub.id, e) + logger.error("Push send failed for sub %d: %s", sub.id, e, exc_info=True) return 0, sub.endpoint loop = asyncio.get_event_loop() @@ -199,9 +199,12 @@ async def send_push_notification( for sub, result in zip(subscriptions, results): if isinstance(result, Exception): + logger.error("Push gather exception for user %d: %s", user_id, result, exc_info=result) continue status_code, endpoint = result - if status_code == 410: + if status_code in (200, 201): + logger.info("Push notification sent to sub %d (status %d)", sub.id, status_code) + elif status_code == 410: asyncio.create_task(_remove_expired_subscription(user_id, endpoint)) - elif status_code and status_code not in (200, 201): - logger.warning("Push returned status %d for user %d", status_code, user_id) + elif status_code: + logger.error("Push returned unexpected status %d for user %d sub %d", status_code, user_id, sub.id) From 090df1633a4018ee02b761e0af738fa2efac1a25 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:28:34 -0400 Subject: [PATCH 10/79] =?UTF-8?q?Fix=20ruff=20E741:=20rename=20ambiguous?= =?UTF-8?q?=20variable=20l=20=E2=86=92=20log=20in=20task=5Flogs=20route?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/fabledassistant/routes/task_logs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fabledassistant/routes/task_logs.py b/src/fabledassistant/routes/task_logs.py index c1d3dfb..a442947 100644 --- a/src/fabledassistant/routes/task_logs.py +++ b/src/fabledassistant/routes/task_logs.py @@ -16,7 +16,7 @@ task_logs_bp = Blueprint("task_logs", __name__, url_prefix="/api/tasks") async def list_logs_route(task_id: int): uid = get_current_user_id() logs = await list_logs(uid, task_id) - return jsonify({"logs": [l.to_dict() for l in logs]}) + return jsonify({"logs": [log.to_dict() for log in logs]}) @task_logs_bp.route("//logs", methods=["POST"]) From 52d14672e5626157260930814b3fcd360ff9ef1c Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:29:05 -0400 Subject: [PATCH 11/79] CI: install setuptools before dev deps to support legacy http-ece build http-ece (pulled in by pywebpush) uses setup.py and requires setuptools, which is not included in the deadsnakes Python 3.12 install. Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 8cf7fed..fe265ea 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -86,6 +86,9 @@ jobs: apt-get install -y -qq python3.12 python3.12-dev python3.12-venv python3-pip git python3.12 -m ensurepip --upgrade + - name: Install setuptools (required by legacy deps) + run: python3.12 -m pip install setuptools + - name: Install package with dev deps run: python3.12 -m pip install -e ".[dev]" From 2b4163523ba971262b8c2a95cc24f3b4c34ed0e4 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:34:12 -0400 Subject: [PATCH 12/79] CI: pre-install http-ece with --no-build-isolation to fix PEP 517 isolation pip builds legacy setup.py packages in an isolated environment that doesn't inherit the globally installed setuptools. Pre-building http-ece with --no-build-isolation bypasses that isolation so setuptools is available. Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index fe265ea..9f31e0e 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -86,8 +86,10 @@ jobs: apt-get install -y -qq python3.12 python3.12-dev python3.12-venv python3-pip git python3.12 -m ensurepip --upgrade - - name: Install setuptools (required by legacy deps) - run: python3.12 -m pip install setuptools + - name: Install setuptools and pre-build legacy deps + run: | + python3.12 -m pip install setuptools wheel + python3.12 -m pip install --no-build-isolation http-ece - name: Install package with dev deps run: python3.12 -m pip install -e ".[dev]" From 4327b9f858e41b8ba6a59ff12fd149a894957474 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 22:47:08 -0400 Subject: [PATCH 13/79] CI: use venv for Python tests to isolate setuptools from system Python deadsnakes python3.12 sees system python3.10's setuptools at /usr/lib/python3/dist-packages and skips installation, leaving python3.12 without setuptools. A venv gets its own site-packages so pip/setuptools are properly present for http-ece's legacy setup.py build. Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/ci.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9f31e0e..752dd8e 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -86,16 +86,17 @@ jobs: apt-get install -y -qq python3.12 python3.12-dev python3.12-venv python3-pip git python3.12 -m ensurepip --upgrade - - name: Install setuptools and pre-build legacy deps - run: | - python3.12 -m pip install setuptools wheel - python3.12 -m pip install --no-build-isolation http-ece + - name: Create virtual environment + run: python3.12 -m venv /opt/venv - name: Install package with dev deps - run: python3.12 -m pip install -e ".[dev]" + run: | + /opt/venv/bin/pip install --upgrade pip setuptools wheel + /opt/venv/bin/pip install --no-build-isolation http-ece + /opt/venv/bin/pip install -e ".[dev]" - name: Run tests - run: python3.12 -m pytest tests/ -v + run: /opt/venv/bin/python -m pytest tests/ -v build: name: Build & push image From 12644999c17cc2e0f5240ed225c91b70da3a0b7f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 9 Mar 2026 23:20:33 -0400 Subject: [PATCH 14/79] Settings: reorganise into tabs (General, Account, Notifications, Integrations, Data, Admin) Replaces the single long scrolling page with a tab bar. Active tab persists to localStorage across navigation. Admin tab only visible to admins. Push notifications description clarified to mention HTTPS requirement. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/views/SettingsView.vue | 420 +++++++++++++++++----------- 1 file changed, 249 insertions(+), 171 deletions(-) diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 4cc114a..2393883 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -1,5 +1,5 @@ From 474ed1fe055b21a3d99277250fdae4cade9cadbd Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 10 Mar 2026 18:34:52 -0400 Subject: [PATCH 37/79] UI polish: hover lift, skeleton loaders, empty states, badge contrast, transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Card & row interactions: - NoteCard, TaskCard, ProjectCard: translateY(-2px) lift on hover + extended transitions - Kanban task cards (ProjectView), note rows: same lift treatment - Task rows in flat/grouped list: soft indigo bg tint on hover - Chat conversation items: left-border accent + bg tint on hover (was border-only) - HomeView project mini-cards: translateY(-2px) lift on hover Global feedback: - Buttons: scale(0.97) on :active press (theme.css, :not(:disabled) scoped) - TagPill: color → primary + indigo bg tint on hover - StatusBadge: increased opacity 15% → 22% + stronger text color for readability Loading & empty states: - TasksListView: shimmer skeleton loader (6 rows) + rich empty state with CTA - ProjectListView: shimmer skeleton cards (4) + rich empty state with CTA - HomeView: section-empty messages for overdue/high-priority/notes sections - ProjectView kanban columns: dashed-border styled empty state Transitions & graph: - WorkspaceView panels: panel-fade opacity transition on show/hide (v-if inner wrap) - GraphView D3 nodes: grow to r*1.3 + bold label on mouseover (150ms transition) - Milestone action buttons: base opacity 0 → 0.35 for discoverability Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/assets/theme.css | 7 +++ frontend/src/components/NoteCard.vue | 3 +- frontend/src/components/StatusBadge.vue | 12 ++--- frontend/src/components/TagPill.vue | 4 +- frontend/src/components/TaskCard.vue | 3 +- frontend/src/views/ChatView.vue | 6 ++- frontend/src/views/GraphView.vue | 18 ++++++- frontend/src/views/HomeView.vue | 16 +++++- frontend/src/views/ProjectListView.vue | 58 ++++++++++---------- frontend/src/views/ProjectView.vue | 18 ++++--- frontend/src/views/TasksListView.vue | 71 +++++++++++++++++++++++-- frontend/src/views/WorkspaceView.vue | 43 +++++++++++---- 12 files changed, 195 insertions(+), 64 deletions(-) diff --git a/frontend/src/assets/theme.css b/frontend/src/assets/theme.css index b7d068b..7c34a2e 100644 --- a/frontend/src/assets/theme.css +++ b/frontend/src/assets/theme.css @@ -128,6 +128,13 @@ a:focus-visible { border-radius: var(--radius-sm); } +button:not(:disabled):active, +.btn:not(:disabled):active, +[role="button"]:not(:disabled):active { + transform: scale(0.97); + transition: transform 0.08s ease; +} + /* Responsive breakpoints: 480px (phone), 768px (tablet), 1024px (desktop) */ @media (max-width: 768px) { .hide-mobile { diff --git a/frontend/src/components/NoteCard.vue b/frontend/src/components/NoteCard.vue index d3461f0..cefdc8c 100644 --- a/frontend/src/components/NoteCard.vue +++ b/frontend/src/components/NoteCard.vue @@ -65,10 +65,11 @@ function goEdit() { color: inherit; background: var(--color-bg-card); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(99, 102, 241, 0.06); - transition: box-shadow 0.2s; + transition: box-shadow 0.2s, transform 0.18s ease; } .note-card:hover { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px rgba(99, 102, 241, 0.14); + transform: translateY(-2px); } /* Compact single-row layout */ diff --git a/frontend/src/components/StatusBadge.vue b/frontend/src/components/StatusBadge.vue index fae4892..1167cbd 100644 --- a/frontend/src/components/StatusBadge.vue +++ b/frontend/src/components/StatusBadge.vue @@ -37,16 +37,16 @@ const labels: Record = { letter-spacing: 0.025em; } .status-todo { - background: var(--color-status-todo-bg); - color: var(--color-status-todo); + background: color-mix(in srgb, var(--color-status-todo-bg) 78%, var(--color-status-todo) 22%); + color: color-mix(in srgb, var(--color-status-todo) 85%, #000 15%); } .status-in_progress { - background: var(--color-status-in-progress-bg); - color: var(--color-status-in-progress); + background: color-mix(in srgb, var(--color-status-in-progress-bg) 78%, var(--color-status-in-progress) 22%); + color: color-mix(in srgb, var(--color-status-in-progress) 85%, #000 15%); } .status-done { - background: var(--color-status-done-bg); - color: var(--color-status-done); + background: color-mix(in srgb, var(--color-status-done-bg) 78%, var(--color-status-done) 22%); + color: color-mix(in srgb, var(--color-status-done) 85%, #000 15%); } .clickable { cursor: pointer; diff --git a/frontend/src/components/TagPill.vue b/frontend/src/components/TagPill.vue index f2ecaa1..687ee9b 100644 --- a/frontend/src/components/TagPill.vue +++ b/frontend/src/components/TagPill.vue @@ -36,9 +36,11 @@ defineEmits<{ font-size: 0.8rem; cursor: pointer; white-space: nowrap; + transition: color 0.15s, background 0.15s; } .tag-pill:hover { - filter: brightness(0.95); + color: var(--color-primary); + background: rgba(99, 102, 241, 0.08); } .dismiss { background: none; diff --git a/frontend/src/components/TaskCard.vue b/frontend/src/components/TaskCard.vue index dd6d436..9a97798 100644 --- a/frontend/src/components/TaskCard.vue +++ b/frontend/src/components/TaskCard.vue @@ -102,10 +102,11 @@ function isOverdue(): boolean { color: inherit; background: var(--color-bg-card); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(99, 102, 241, 0.06); - transition: box-shadow 0.2s; + transition: box-shadow 0.2s, transform 0.18s ease; } .task-card:hover { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px rgba(99, 102, 241, 0.14); + transform: translateY(-2px); } /* Compact single-row layout */ diff --git a/frontend/src/views/ChatView.vue b/frontend/src/views/ChatView.vue index 011a181..8318baf 100644 --- a/frontend/src/views/ChatView.vue +++ b/frontend/src/views/ChatView.vue @@ -999,13 +999,17 @@ onUnmounted(() => { border-radius: var(--radius-sm); cursor: pointer; margin-bottom: 0.25rem; + border-left: 3px solid transparent; + transition: background 0.15s, border-color 0.15s; } .conv-item:hover { - background: var(--color-bg-card); + background: rgba(99,102,241,0.05); + border-left: 3px solid var(--color-primary); } .conv-item.active { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); + border-left: 3px solid var(--color-primary); } .conv-info { flex: 1; diff --git a/frontend/src/views/GraphView.vue b/frontend/src/views/GraphView.vue index dd05858..b4f2e47 100644 --- a/frontend/src/views/GraphView.vue +++ b/frontend/src/views/GraphView.vue @@ -258,7 +258,7 @@ function initGraph() { openPeek(d); } }) - .on("mouseover", (event: MouseEvent, d: GraphNode) => { + .on("mouseover", function(event: MouseEvent, d: GraphNode) { const rect = containerRef.value!.getBoundingClientRect(); tooltip.value = { visible: true, @@ -266,14 +266,28 @@ function initGraph() { y: event.clientY - rect.top - 8, node: d, }; + select(this as SVGGElement).select("circle") + .transition().duration(150) + .attr("r", (d.radius ?? 8) * 1.3); + select(this as SVGGElement).select("text") + .transition().duration(150) + .style("font-weight", "600") + .style("font-size", "11px"); }) .on("mousemove", (event: MouseEvent) => { const rect = containerRef.value!.getBoundingClientRect(); tooltip.value.x = event.clientX - rect.left + 12; tooltip.value.y = event.clientY - rect.top - 8; }) - .on("mouseout", () => { + .on("mouseout", function(_event: MouseEvent, d: GraphNode) { tooltip.value.visible = false; + select(this as SVGGElement).select("circle") + .transition().duration(150) + .attr("r", d.radius ?? 8); + select(this as SVGGElement).select("text") + .transition().duration(150) + .style("font-weight", null) + .style("font-size", null); }); nodeSel diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 5650e3b..305d434 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -397,6 +397,7 @@ function clearDashboardResponse() { /> +

All clear

Due Today

@@ -439,6 +440,7 @@ function clearDashboardResponse() { />
+

All clear

In Progress

@@ -484,7 +486,7 @@ function clearDashboardResponse() { />
-

No notes yet.

+

No recent notes

+ New Note
@@ -691,10 +693,11 @@ function clearDashboardResponse() { text-decoration: none; color: inherit; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(99, 102, 241, 0.06); - transition: box-shadow 0.15s; + transition: box-shadow 0.18s ease, transform 0.18s ease; } .project-mini-card:hover { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10), 0 0 0 1px rgba(99, 102, 241, 0.14); + transform: translateY(-2px); } .project-mini-title { font-size: 0.9rem; @@ -748,6 +751,15 @@ function clearDashboardResponse() { } .muted { color: var(--color-text-muted); } +.section-empty { + text-align: center; + padding: 1rem 0.5rem; + color: var(--color-text-muted); + font-size: 0.82rem; + font-style: italic; + margin: 0; +} + .loading { color: var(--color-text-secondary); } .empty-state { text-align: center; padding: 1.5rem 0; } .empty-state::before { diff --git a/frontend/src/views/ProjectListView.vue b/frontend/src/views/ProjectListView.vue index f1171bb..639cfc0 100644 --- a/frontend/src/views/ProjectListView.vue +++ b/frontend/src/views/ProjectListView.vue @@ -150,13 +150,16 @@ function truncate(text: string | null, max = 120): string { -

Loading...

+
+
+

{{ error }}

-
+
+

No projects yet

-

Create your first project to organize tasks and notes.

- +

Organise your notes and tasks into a project

+
@@ -327,32 +330,28 @@ function truncate(text: string | null, max = 120): string { color: var(--color-danger); } -.empty-state { - text-align: center; - margin-top: 3rem; +.empty-state-rich { text-align: center; padding: 3rem 1rem; color: var(--color-text-muted); } +.empty-icon { font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.3; } +.empty-title { font-size: 1rem; font-weight: 600; color: var(--color-text-secondary); margin: 0 0 0.35rem; } +.empty-sub { font-size: 0.85rem; margin: 0 0 1rem; } +.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--color-primary); border-radius: var(--radius-sm); color: var(--color-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; } +.empty-action:hover { background: var(--color-primary); color: #fff; } + +.skeleton-card { + height: 140px; + border-radius: var(--radius-md); + background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%); + background-size: 200% 100%; + animation: skeleton-shimmer 1.4s ease infinite; } -.empty-title { - font-size: 1.1rem; - font-weight: 600; - margin: 0 0 0.25rem; - color: var(--color-text); +@keyframes skeleton-shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } } -.empty-subtitle { - color: var(--color-text-muted); - margin: 0 0 1rem; - font-size: 0.95rem; -} -.btn-cta { - display: inline-block; - padding: 0.45rem 1rem; - background: var(--color-primary); - color: #fff; - border: none; - border-radius: var(--radius-sm); - text-decoration: none; - font-size: 0.9rem; - cursor: pointer; - font-family: inherit; +.skeleton-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 1rem; } .projects-grid { @@ -367,7 +366,7 @@ function truncate(text: string | null, max = 120): string { border-radius: var(--radius-md); padding: 1rem 1.1rem; cursor: pointer; - transition: border-color 0.15s, box-shadow 0.15s; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.18s ease; display: flex; flex-direction: column; gap: 0.5rem; @@ -375,6 +374,7 @@ function truncate(text: string | null, max = 120): string { .project-card:hover { border-color: var(--color-primary); box-shadow: 0 2px 8px var(--color-shadow); + transform: translateY(-2px); } .card-header { diff --git a/frontend/src/views/ProjectView.vue b/frontend/src/views/ProjectView.vue index 73d866b..fccea9d 100644 --- a/frontend/src/views/ProjectView.vue +++ b/frontend/src/views/ProjectView.vue @@ -1031,10 +1031,11 @@ function formatDate(dateStr?: string | null): string { text-decoration: none; color: var(--color-text); font-size: 0.875rem; - transition: border-color 0.15s; + transition: border-color 0.15s, transform 0.18s ease; } .task-card:hover { border-color: var(--color-primary); + transform: translateY(-2px); } .task-card-done .task-title { text-decoration: line-through; @@ -1069,11 +1070,13 @@ function formatDate(dateStr?: string | null): string { color: var(--color-text-muted); } .col-empty { - font-size: 0.8rem; - color: var(--color-text-muted); text-align: center; - padding: 0.5rem 0; - margin: 0; + padding: 1.5rem 0.5rem; + color: var(--color-text-muted); + font-size: 0.82rem; + border: 1px dashed var(--color-border); + border-radius: var(--radius-sm); + margin-top: 0.5rem; } /* Notes list */ @@ -1093,10 +1096,11 @@ function formatDate(dateStr?: string | null): string { text-decoration: none; color: var(--color-text); font-size: 0.9rem; - transition: border-color 0.15s; + transition: border-color 0.15s, transform 0.15s ease; } .note-row:hover { border-color: var(--color-primary); + transform: translateY(-1px); } .note-title { font-weight: 500; @@ -1193,7 +1197,7 @@ function formatDate(dateStr?: string | null): string { display: flex; gap: 0.15rem; margin-left: 0.25rem; - opacity: 0; + opacity: 0.35; transition: opacity 0.15s; } .milestone-header:hover .ms-actions { diff --git a/frontend/src/views/TasksListView.vue b/frontend/src/views/TasksListView.vue index 041a74b..0f4a1b8 100644 --- a/frontend/src/views/TasksListView.vue +++ b/frontend/src/views/TasksListView.vue @@ -247,7 +247,9 @@ function toggleGroup(key: string) {
-

Loading...

+
+
+
@@ -426,6 +431,23 @@ function toggleGroup(key: string) { padding: 0; } +/* Skeleton loading */ +.task-list-skeleton { + margin-top: 1rem; +} +.skeleton-row { + height: 44px; + border-radius: var(--radius-sm); + background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%); + background-size: 200% 100%; + animation: skeleton-shimmer 1.4s ease infinite; + margin-bottom: 0.3rem; +} +@keyframes skeleton-shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + /* Flat compact list */ .cards-list { display: flex; @@ -433,6 +455,13 @@ function toggleGroup(key: string) { gap: 0.3rem; margin-top: 1rem; } +.cards-list > div { + border-radius: var(--radius-sm, 6px); + transition: background 0.15s; +} +.cards-list > div:hover { + background: rgba(99,102,241,0.05); +} /* Grouped view */ .task-group { @@ -513,6 +542,40 @@ function toggleGroup(key: string) { text-decoration: none; font-size: 0.9rem; } +.empty-state-rich { + text-align: center; + padding: 3rem 1rem; + color: var(--color-text-muted); +} +.empty-icon { + font-size: 2.5rem; + margin-bottom: 0.75rem; + opacity: 0.3; +} +.empty-state-rich .empty-title { + font-size: 1rem; + font-weight: 600; + color: var(--color-text-secondary); + margin: 0 0 0.35rem; +} +.empty-sub { + font-size: 0.85rem; + margin: 0 0 1rem; +} +.empty-action { + display: inline-block; + padding: 0.4rem 1rem; + border: 1px solid var(--color-primary); + border-radius: var(--radius-sm); + color: var(--color-primary); + text-decoration: none; + font-size: 0.85rem; + transition: background 0.15s, color 0.15s; +} +.empty-action:hover { + background: var(--color-primary); + color: #fff; +} .kb-active-item { outline: 2px solid var(--color-primary); diff --git a/frontend/src/views/WorkspaceView.vue b/frontend/src/views/WorkspaceView.vue index 59d90a4..de73437 100644 --- a/frontend/src/views/WorkspaceView.vue +++ b/frontend/src/views/WorkspaceView.vue @@ -261,11 +261,15 @@ onUnmounted(async () => {
- + +
+ +
+
@@ -376,11 +380,15 @@ onUnmounted(async () => {
- + +
+ +
+
@@ -461,6 +469,21 @@ onUnmounted(async () => { min-width: 0; } +.panel-inner { + height: 100%; + display: flex; + flex-direction: column; +} + +.panel-fade-enter-active, +.panel-fade-leave-active { + transition: opacity 0.18s ease; +} +.panel-fade-enter-from, +.panel-fade-leave-to { + opacity: 0; +} + /* Chat panel */ .ws-chat-panel { display: flex; From bb1f29c8e2b677e23f43aa56c3d721c474c43aea Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 10 Mar 2026 18:36:10 -0400 Subject: [PATCH 38/79] Header: increase height and logo size for better visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Nav padding: 0.5rem → 0.75rem vertical, 1.25rem → 1.5rem horizontal - AppLogo size: 24px → 34px so the book detail is legible Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/AppHeader.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue index d32c212..5c74f4a 100644 --- a/frontend/src/components/AppHeader.vue +++ b/frontend/src/components/AppHeader.vue @@ -81,7 +81,7 @@ onUnmounted(() => document.removeEventListener("click", handleClickOutside));
+ +
+

Invite User

+
+ + +
+

Send an invitation link to allow someone to register, even when public registration is closed.

+
+

Pending Invitations

+ + + + + + + + + + + + + + + + + +
EmailSentExpiresActions
{{ formatUserDate(inv.created_at) }}{{ formatUserDate(inv.expires_at) }} + +
+
+
+ +
+

Users

+
Loading users...
+
No users found.
+ + + + + + + + + + + + + + + + + + + +
UsernameEmailRoleJoinedActions
{{ u.username }} + + {{ u.role }} + + {{ formatUserDate(u.created_at) }} + + + +
+
+ + +``` + +- [ ] **Step 3: Add Users panel CSS to SettingsView** + +Copy the following CSS from `UserManagementView.vue` into `SettingsView.vue`'s ` From c2565fb81807938ba2241b3032fb799d798f6d4a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 10 Mar 2026 22:22:18 -0400 Subject: [PATCH 46/79] feat: inline Users panel into Settings Ports UserManagementView logic (users list, invitations, registration toggle) directly into SettingsView as a lazy-loaded 'users' admin tab. Adds loadLogsPanel stub for Task 4. Adds apiDelete import and User type import at script top. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/views/SettingsView.vue | 372 +++++++++++++++++++++++++++- 1 file changed, 370 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index ef18451..80b7fde 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -3,8 +3,9 @@ import { ref, watch, onMounted } from "vue"; import { useSettingsStore } from "@/stores/settings"; import { useAuthStore } from "@/stores/auth"; import { useToastStore } from "@/stores/toast"; -import { apiGet, apiPost, apiPut } from "@/api/client"; +import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client"; import { usePushStore } from "@/stores/push"; +import type { User } from "@/types/auth"; const store = useSettingsStore(); const authStore = useAuthStore(); @@ -32,7 +33,11 @@ const restoreFileInput = ref(null); const VALID_TABS = new Set(["general", "account", "notifications", "integrations", "data", "config", "users", "logs"]); const _stored = localStorage.getItem("settings_tab") ?? "general"; const activeTab = ref(VALID_TABS.has(_stored) ? (_stored === "admin" ? "config" : _stored) : "general"); -watch(activeTab, (v) => localStorage.setItem("settings_tab", v === "admin" ? "config" : v)); +watch(activeTab, (v) => { + localStorage.setItem("settings_tab", v === "admin" ? "config" : v); + if (v === "users" && authStore.isAdmin) loadUsersPanel(); + if (v === "logs" && authStore.isAdmin) loadLogsPanel(); +}); // Chat retention const chatRetentionDays = ref(90); @@ -439,6 +444,133 @@ function onSearchKeydown(e: KeyboardEvent) { function hostname(url: string): string { try { return new URL(url).hostname; } catch { return url; } } + +// ── Users panel ── + +interface Invitation { + id: number; + email: string; + created_at: string; + expires_at: string; +} + +const users = ref([]); +const registrationOpen = ref(false); +const usersLoading = ref(false); +const toggling = ref(false); +const confirmDeleteId = ref(null); +const deleting = ref(null); +const inviteEmail = ref(""); +const sendingInvite = ref(false); +const invitations = ref([]); +const revokingId = ref(null); + +async function fetchUsers() { + try { + const data = await apiGet<{ users: User[] }>("/api/admin/users"); + users.value = data.users; + } catch { + toastStore.show("Failed to load users", "error"); + } +} + +async function fetchRegistration() { + try { + const data = await apiGet<{ open: boolean }>("/api/admin/registration"); + registrationOpen.value = data.open; + } catch { /* ignore */ } +} + +async function fetchInvitations() { + try { + const data = await apiGet<{ invitations: Invitation[] }>("/api/admin/invitations"); + invitations.value = data.invitations; + } catch { /* ignore */ } +} + +async function loadUsersPanel() { + if (users.value.length > 0) return; // already loaded + usersLoading.value = true; + await Promise.all([fetchUsers(), fetchRegistration(), fetchInvitations()]); + usersLoading.value = false; +} + +async function loadLogsPanel() { /* implemented in Task 4 */ } + +async function sendInvite() { + const email = inviteEmail.value.trim().toLowerCase(); + if (!email) return; + sendingInvite.value = true; + try { + await apiPost("/api/admin/invitations", { email }); + toastStore.show(`Invitation sent to ${email}`); + inviteEmail.value = ""; + await fetchInvitations(); + } catch (e: unknown) { + const body = (e as { body?: { error?: string } })?.body; + toastStore.show(body?.error || "Failed to send invitation", "error"); + } finally { + sendingInvite.value = false; + } +} + +async function revokeInvitation(id: number) { + revokingId.value = id; + try { + await apiDelete(`/api/admin/invitations/${id}`); + invitations.value = invitations.value.filter((inv) => inv.id !== id); + toastStore.show("Invitation revoked"); + } catch { + toastStore.show("Failed to revoke invitation", "error"); + } finally { + revokingId.value = null; + } +} + +async function toggleRegistration() { + toggling.value = true; + try { + const data = await apiPut<{ open: boolean }>("/api/admin/registration", { + open: !registrationOpen.value, + }); + registrationOpen.value = data.open; + toastStore.show(data.open ? "Registration opened" : "Registration closed"); + } catch { + toastStore.show("Failed to update registration setting", "error"); + } finally { + toggling.value = false; + } +} + +function confirmDelete(userId: number) { + if (confirmDeleteId.value === userId) { + deleteUser(userId); + } else { + confirmDeleteId.value = userId; + } +} +function cancelDelete() { confirmDeleteId.value = null; } + +async function deleteUser(userId: number) { + confirmDeleteId.value = null; + deleting.value = userId; + try { + await apiDelete(`/api/admin/users/${userId}`); + users.value = users.value.filter((u) => u.id !== userId); + toastStore.show("User deleted"); + } catch (e: unknown) { + const body = (e as { body?: { error?: string } })?.body; + toastStore.show(body?.error || "Failed to delete user", "error"); + } finally { + deleting.value = null; + } +} + +function formatUserDate(iso: string): string { + return new Date(iso).toLocaleDateString(undefined, { + year: "numeric", month: "short", day: "numeric", + }); +} @@ -1396,4 +1642,126 @@ function hostname(url: string): string { grid-template-columns: 1fr; } } + +/* Users panel */ +.registration-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} +.registration-info { flex: 1; } +.registration-status { margin: 0; font-size: 0.95rem; } +.text-success { color: var(--color-success); } +.text-muted { color: var(--color-text-muted); } +.invite-form { + display: flex; + gap: 0.5rem; + margin-bottom: 0.5rem; +} +.invite-input { flex: 1; } +.invite-list { margin-top: 1rem; } +.subsection-label { + margin: 0 0 0.5rem; + font-size: 0.85rem; + font-weight: 600; + color: var(--color-text-secondary); +} +.users-table { width: 100%; border-collapse: collapse; } +.users-table th { + text-align: left; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--color-text-muted); + padding: 0.5rem 0.75rem; + border-bottom: 1px solid var(--color-border); +} +.users-table td { + padding: 0.65rem 0.75rem; + border-bottom: 1px solid var(--color-border); + font-size: 0.9rem; +} +.users-table tbody tr:last-child td { border-bottom: none; } +.cell-username { font-weight: 600; } +.cell-email { color: var(--color-text-secondary); } +.cell-date { color: var(--color-text-muted); font-size: 0.85rem; } +.cell-actions { white-space: nowrap; } +.role-badge { + display: inline-block; + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.15rem 0.4rem; + border-radius: var(--radius-sm); +} +.role-admin { + color: var(--color-primary); + background: color-mix(in srgb, var(--color-primary) 15%, transparent); +} +.role-user { + color: var(--color-text-muted); + background: var(--color-bg-secondary); +} +.you-label { font-size: 0.8rem; color: var(--color-text-muted); font-style: italic; } +.btn-delete { + padding: 0.25rem 0.6rem; + background: transparent; + color: var(--color-text-muted); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + cursor: pointer; + font-size: 0.8rem; +} +.btn-delete:hover:not(:disabled) { border-color: var(--color-danger); color: var(--color-danger); } +.btn-delete:disabled { opacity: 0.4; cursor: default; } +.btn-confirm-delete { + padding: 0.25rem 0.6rem; + background: var(--color-danger); + color: #fff; + border: none; + border-radius: var(--radius-sm); + cursor: pointer; + font-size: 0.8rem; + font-weight: 600; + margin-right: 0.25rem; +} +.btn-confirm-delete:hover:not(:disabled) { filter: brightness(0.9); } +.btn-confirm-delete:disabled { opacity: 0.6; cursor: default; } +.btn-cancel-delete { + padding: 0.25rem 0.6rem; + background: transparent; + color: var(--color-text-muted); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + cursor: pointer; + font-size: 0.8rem; +} +.btn-cancel-delete:hover { color: var(--color-text); border-color: var(--color-text-muted); } +.btn-toggle { + padding: 0.45rem 1rem; + border: none; + border-radius: var(--radius-sm); + cursor: pointer; + font-size: 0.9rem; + font-weight: 600; + white-space: nowrap; +} +.btn-toggle:disabled { opacity: 0.6; cursor: default; } +.btn-toggle-open { background: var(--color-primary); color: #fff; } +.btn-toggle-open:hover:not(:disabled) { opacity: 0.9; } +.btn-toggle-close { + background: var(--color-bg-secondary); + color: var(--color-text); + border: 1px solid var(--color-border); +} +.btn-toggle-close:hover:not(:disabled) { border-color: var(--color-warning); color: var(--color-warning); } +.loading-msg, .empty-msg { + text-align: center; + color: var(--color-text-muted); + font-size: 0.9rem; + padding: 1rem 0; +} From f755067cbdf39b97af938255b69f1df8d9ee78e2 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 10 Mar 2026 22:26:52 -0400 Subject: [PATCH 47/79] feat: inline Logs panel into Settings Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/views/SettingsView.vue | 294 +++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 80b7fde..83e27e6 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -6,6 +6,7 @@ import { useToastStore } from "@/stores/toast"; import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client"; import { usePushStore } from "@/stores/push"; import type { User } from "@/types/auth"; +import PaginationBar from "@/components/PaginationBar.vue"; const store = useSettingsStore(); const authStore = useAuthStore(); @@ -495,7 +496,119 @@ async function loadUsersPanel() { usersLoading.value = false; } -async function loadLogsPanel() { /* implemented in Task 4 */ } +// ── Logs panel ── +interface LogEntry { + id: number; + category: string; + user_id: number | null; + username: string | null; + action: string | null; + endpoint: string | null; + method: string | null; + status_code: number | null; + duration_ms: number | null; + ip_address: string | null; + details: string | null; + created_at: string; +} + +interface LogStats { + audit: number; + usage: number; + error: number; + total: number; +} + +const logs = ref([]); +const logStats = ref({ audit: 0, usage: 0, error: 0, total: 0 }); +const logTotal = ref(0); +const logsLoading = ref(false); +const logsLoaded = ref(false); +const expandedLogId = ref(null); +const logCategory = ref(""); +const logSearch = ref(""); +const logDateFrom = ref(""); +const logDateTo = ref(""); +const logLimit = 50; +const logOffset = ref(0); +let logSearchTimeout: ReturnType | null = null; + +watch([logCategory, logDateFrom, logDateTo], () => { + logOffset.value = 0; + if (logsLoaded.value) fetchLogs(); +}); +watch(logSearch, () => { + if (logSearchTimeout) clearTimeout(logSearchTimeout); + logSearchTimeout = setTimeout(() => { + logOffset.value = 0; + if (logsLoaded.value) fetchLogs(); + }, 300); +}); +watch(logOffset, () => { + if (logsLoaded.value) fetchLogs(); +}); + +async function fetchLogs() { + try { + const params = new URLSearchParams(); + if (logCategory.value) params.set("category", logCategory.value); + if (logSearch.value) params.set("search", logSearch.value); + if (logDateFrom.value) params.set("date_from", logDateFrom.value); + if (logDateTo.value) params.set("date_to", logDateTo.value); + params.set("limit", String(logLimit)); + params.set("offset", String(logOffset.value)); + const data = await apiGet<{ logs: LogEntry[]; total: number }>(`/api/admin/logs?${params}`); + logs.value = data.logs; + logTotal.value = data.total; + } catch { + toastStore.show("Failed to load logs", "error"); + } +} + +async function fetchLogStats() { + try { + logStats.value = await apiGet("/api/admin/logs/stats"); + } catch { /* ignore */ } +} + +async function loadLogsPanel() { + if (logsLoaded.value) return; + logsLoading.value = true; + await Promise.all([fetchLogs(), fetchLogStats()]); + logsLoaded.value = true; + logsLoading.value = false; +} + +function toggleLogExpand(id: number) { + expandedLogId.value = expandedLogId.value === id ? null : id; +} + +function formatLogTime(iso: string): string { + const d = new Date(iso); + return d.toLocaleString(undefined, { + month: "short", day: "numeric", + hour: "2-digit", minute: "2-digit", second: "2-digit", + }); +} + +function formatLogDetails(details: string | null): string { + if (!details) return ""; + try { return JSON.stringify(JSON.parse(details), null, 2); } catch { return details; } +} + +function logDisplayLabel(entry: LogEntry): string { + if (entry.category === "audit" && entry.action) return entry.action; + if (entry.endpoint) return entry.endpoint; + return "—"; +} + +function clearLogFilters() { + logCategory.value = ""; + logSearch.value = ""; + logDateFrom.value = ""; + logDateTo.value = ""; + logOffset.value = 0; +} async function sendInvite() { const email = inviteEmail.value.trim().toLowerCase(); @@ -1172,6 +1285,106 @@ function formatUserDate(iso: string): string { + +
+ +
+

Overview

+
+
+ {{ logStats.total.toLocaleString() }} + Total +
+
+ {{ logStats.audit.toLocaleString() }} + Audit +
+
+ {{ logStats.usage.toLocaleString() }} + Usage +
+
+ {{ logStats.error.toLocaleString() }} + Error +
+
+
+ +
+

Log Entries

+
+ + + + + +
+ +
Loading logs...
+
No log entries found.
+ +
+ +
+ @@ -1764,4 +1977,83 @@ function formatUserDate(iso: string): string { font-size: 0.9rem; padding: 1rem 0; } + +/* Logs panel */ +.stats-section { padding: 1rem 1.25rem; } +.stats-grid { display: flex; gap: 1rem; flex-wrap: wrap; } +.stat-card { + flex: 1; + min-width: 80px; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.15rem; +} +.stat-count { font-size: 1.5rem; font-weight: 700; color: var(--color-text); } +.stat-label { + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--color-text-muted); +} +.stat-audit { color: var(--color-primary); } +.stat-usage { color: var(--color-success); } +.stat-error { color: var(--color-danger); } + +.filter-bar { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.75rem; } +.filter-select { min-width: 140px; } +.filter-input { flex: 1; min-width: 150px; } +.filter-date { width: 140px; } + +.logs-table { width: 100%; border-collapse: collapse; margin-top: 0.5rem; } +.logs-table th { + text-align: left; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--color-text-muted); + padding: 0.5rem 0.75rem; + border-bottom: 1px solid var(--color-border); +} +.logs-table td { + padding: 0.5rem 0.75rem; + border-bottom: 1px solid var(--color-border); + font-size: 0.85rem; +} +.logs-table tbody tr:last-child td { border-bottom: none; } +.log-row { cursor: pointer; transition: background 0.1s; } +.log-row:hover { background: var(--color-bg-secondary); } +.row-expanded { background: var(--color-bg-secondary); } +.cell-time { white-space: nowrap; color: var(--color-text-muted); font-size: 0.8rem; } +.cell-user { color: var(--color-text-secondary); } +.cell-action { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.cell-status { font-family: monospace; font-size: 0.85rem; } +.cell-duration { color: var(--color-text-muted); font-size: 0.8rem; white-space: nowrap; } +.text-error { color: var(--color-danger); } +.detail-row td { padding: 0 0.75rem 0.75rem; border-bottom: 1px solid var(--color-border); } +.detail-ip { font-family: monospace; font-size: 0.8rem; color: var(--color-text-muted); margin-bottom: 0.4rem; } +.detail-json { + margin: 0; padding: 0.75rem; + background: var(--color-bg); border: 1px solid var(--color-border); + border-radius: var(--radius-sm); font-size: 0.8rem; + overflow-x: auto; white-space: pre-wrap; word-break: break-all; max-height: 300px; +} +.category-badge { + display: inline-block; + font-size: 0.65rem; font-weight: 700; + text-transform: uppercase; letter-spacing: 0.05em; + padding: 0.1rem 0.35rem; border-radius: var(--radius-sm); +} +.cat-audit { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 15%, transparent); } +.cat-usage { color: var(--color-success); background: color-mix(in srgb, var(--color-success) 15%, transparent); } +.cat-error { color: var(--color-danger); background: color-mix(in srgb, var(--color-danger) 15%, transparent); } +.method-tag { + display: inline-block; + font-size: 0.65rem; font-weight: 700; font-family: monospace; + padding: 0.05rem 0.25rem; border-radius: 3px; + background: var(--color-bg-secondary); color: var(--color-text-muted); + margin-right: 0.25rem; +} From 6e9ec26c8e9016e52f386dcbb29f2026b75ea2a8 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 10 Mar 2026 22:39:05 -0400 Subject: [PATCH 48/79] UI polish: notes/tasks list views - NotesListView: skeleton shimmer for grid and list modes; grid columns change from fixed 3 to auto-fill(260px) - NoteCard compact: flat border-bottom row style instead of stacked mini-cards; gradient fade mask on grid preview text - TaskCard compact: flat border-bottom row style; show up to 2 tags - TasksListView: gradient + shadow on New Task button (matches NotesListView) Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/NoteCard.vue | 16 ++++++++++ frontend/src/components/TaskCard.vue | 25 ++++++++++++++++ frontend/src/views/NotesListView.vue | 44 ++++++++++++++++++++++++++-- frontend/src/views/TasksListView.vue | 7 ++++- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/NoteCard.vue b/frontend/src/components/NoteCard.vue index cefdc8c..eacdcf8 100644 --- a/frontend/src/components/NoteCard.vue +++ b/frontend/src/components/NoteCard.vue @@ -78,6 +78,19 @@ function goEdit() { align-items: center; gap: 0.6rem; padding: 0.45rem 0.75rem; + background: var(--color-bg-card); + box-shadow: none; + border-radius: 0; + border-bottom: 1px solid var(--color-border); + transform: none !important; +} +.note-card.compact:first-child { + border-top: 1px solid var(--color-border); +} +.note-card.compact:hover { + box-shadow: none; + background: rgba(99, 102, 241, 0.04); + transform: none; } .note-title-compact { font-size: 0.9rem; @@ -137,6 +150,9 @@ function goEdit() { font-size: 0.9rem; max-height: 7.5em; overflow: hidden; + position: relative; + -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%); + mask-image: linear-gradient(to bottom, black 60%, transparent 100%); } .note-meta { display: flex; diff --git a/frontend/src/components/TaskCard.vue b/frontend/src/components/TaskCard.vue index 9a97798..28176ff 100644 --- a/frontend/src/components/TaskCard.vue +++ b/frontend/src/components/TaskCard.vue @@ -59,6 +59,14 @@ function isOverdue(): boolean { {{ task.title || "Untitled" }} {{ projectTitle }} +
+ +
{{ task.due_date }} @@ -115,6 +123,18 @@ function isOverdue(): boolean { align-items: center; gap: 0.5rem; padding: 0.4rem 0.75rem; + box-shadow: none; + border-radius: 0; + border-bottom: 1px solid var(--color-border); + transform: none !important; +} +.task-card.compact:first-child { + border-top: 1px solid var(--color-border); +} +.task-card.compact:hover { + box-shadow: none; + background: rgba(99, 102, 241, 0.04); + transform: none; } /* Status dot */ @@ -164,6 +184,11 @@ function isOverdue(): boolean { white-space: nowrap; flex-shrink: 0; } +.task-tags-compact { + display: flex; + gap: 0.25rem; + flex-shrink: 0; +} .due-compact { font-size: 0.75rem; color: var(--color-text-muted); diff --git a/frontend/src/views/NotesListView.vue b/frontend/src/views/NotesListView.vue index 33e480f..0e9a54c 100644 --- a/frontend/src/views/NotesListView.vue +++ b/frontend/src/views/NotesListView.vue @@ -139,7 +139,14 @@ function onOffsetUpdate(offset: number) { -

Loading...

+
+
+
+
+
+
+
+
-

- Ask the agent to create notes or tasks for this project. -

+

What would you like to work on?

+
+ + + +
+
@@ -428,10 +438,13 @@ onUnmounted(async () => { } .ws-title { - font-weight: 600; - font-size: 0.9rem; + font-size: 0.78rem; color: var(--color-text-muted); flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-style: italic; } .ws-panel-toggles { @@ -501,12 +514,37 @@ onUnmounted(async () => { gap: 0.75rem; } -.empty-chat-msg { - color: var(--color-text-muted); - font-size: 0.875rem; +.empty-chat-prompt { text-align: center; padding: 2rem 1rem; } +.empty-hint { + margin: 0 0 1rem; + color: var(--color-text-secondary); + font-size: 0.9rem; +} +.quick-chips { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; +} +.quick-chip { + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: 20px; + padding: 0.4rem 0.85rem; + font-size: 0.82rem; + color: var(--color-text-secondary); + cursor: pointer; + transition: border-color 0.15s, color 0.15s, background 0.15s; + font-family: inherit; +} +.quick-chip:hover { + border-color: var(--color-primary); + color: var(--color-primary); + background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface)); +} .chat-input-area { display: flex; From 810f63e749bbce77150ddd3ead91797353256681 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 11 Mar 2026 09:29:56 -0400 Subject: [PATCH 52/79] Associate research_topic notes with workspace project run_research_pipeline now accepts project_id; generation_task.py passes workspace_project_id when the tool is called from a workspace context. Co-Authored-By: Claude Sonnet 4.6 --- src/fabledassistant/services/generation_task.py | 2 +- src/fabledassistant/services/research.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fabledassistant/services/generation_task.py b/src/fabledassistant/services/generation_task.py index 5d22ee6..1d6f869 100644 --- a/src/fabledassistant/services/generation_task.py +++ b/src/fabledassistant/services/generation_task.py @@ -260,7 +260,7 @@ async def run_generation( if tool_name == "research_topic": topic = arguments.get("topic", "") try: - note = await run_research_pipeline(topic, user_id, model, buf) + note = await run_research_pipeline(topic, user_id, model, buf, project_id=workspace_project_id) result = { "success": True, "type": "research_note", diff --git a/src/fabledassistant/services/research.py b/src/fabledassistant/services/research.py index 66bc7c0..0f6233b 100644 --- a/src/fabledassistant/services/research.py +++ b/src/fabledassistant/services/research.py @@ -26,6 +26,7 @@ async def run_research_pipeline( user_id: int, model: str, buf=None, + project_id: int | None = None, ) -> Note: """Full research pipeline: search → fetch → synthesize → create note. @@ -112,6 +113,7 @@ async def run_research_pipeline( title=title, body=body, tags=["research"], + project_id=project_id, ) logger.info("Research: created note id=%d title='%s'", note.id, note.title) return note From 978a2627fbd5b0d4e40cbf7aa1ad770355be6e79 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 11 Mar 2026 10:57:02 -0400 Subject: [PATCH 53/79] UI refinement: toolbar icons, gradient CTA, Fraunces title, viewer polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MarkdownToolbar: - Replace text labels with SVG icons (Material Design paths) - Group buttons with visual separators: text / headings / lists / code / links - Add Strikethrough and Blockquote buttons (previously missing) - Active state: tinted bg + ring instead of solid fill; hover lift shadow - Toolbar container: pill shape with border (matches rest of UI) editor-shared.css: - btn-save: gradient + glow (linear-gradient(135deg, #6366f1, #4f46e5)) - title-input: borderless with Fraunces font and focus underline NoteEditorView: - Back button label standardized to "← Notes" (was "Back") - Write/Preview tabs and toolbar now share the same row (flex-direction row) NoteViewerView: - Shimmer skeleton loader replaces plain "Loading..." text - Note title uses Fraunces font at 2rem - Edit button becomes primary gradient CTA - Meta line shows clock/pencil SVG icons alongside timestamps - Backlinks section: card grid with colored type badges (note=indigo, task=amber) Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/assets/editor-shared.css | 39 +++- frontend/src/components/MarkdownToolbar.vue | 235 +++++++++++--------- frontend/src/views/NoteEditorView.vue | 12 +- frontend/src/views/NoteViewerView.vue | 231 +++++++++++++++---- 4 files changed, 352 insertions(+), 165 deletions(-) diff --git a/frontend/src/assets/editor-shared.css b/frontend/src/assets/editor-shared.css index 80ce3e8..42123fe 100644 --- a/frontend/src/assets/editor-shared.css +++ b/frontend/src/assets/editor-shared.css @@ -51,15 +51,23 @@ color: var(--color-primary); } .btn-save { - padding: 0.45rem 1rem; - background: var(--color-primary); + padding: 0.45rem 1.1rem; + background: linear-gradient(135deg, #6366f1, #4f46e5); color: #fff; border: none; border-radius: var(--radius-sm); cursor: pointer; + font-weight: 600; + font-size: 0.875rem; + box-shadow: 0 2px 8px rgba(99, 102, 241, 0.28); + transition: box-shadow 0.15s, opacity 0.15s; +} +.btn-save:hover:not(:disabled) { + box-shadow: 0 4px 14px rgba(99, 102, 241, 0.42); + opacity: 0.95; } .btn-save:disabled { - opacity: 0.6; + opacity: 0.55; cursor: default; } .btn-delete { @@ -86,13 +94,26 @@ color: var(--color-primary); } .title-input { - padding: 0.5rem 0.75rem; - border: 1px solid var(--color-input-border); - border-radius: var(--radius-sm); - font-size: 1.25rem; - font-weight: 600; - background: var(--color-bg-card); + padding: 0.4rem 0; + border: none; + border-bottom: 1.5px solid var(--color-border); + border-radius: 0; + font-size: 1.5rem; + font-weight: 700; + font-family: "Fraunces", Georgia, serif; + background: transparent; color: var(--color-text); + width: 100%; + transition: border-color 0.15s; +} +.title-input:focus { + outline: none; + border-bottom-color: var(--color-primary); +} +.title-input::placeholder { + color: var(--color-text-muted); + font-style: italic; + font-weight: 400; } .editor-tabs { display: flex; diff --git a/frontend/src/components/MarkdownToolbar.vue b/frontend/src/components/MarkdownToolbar.vue index 3be8101..e3350d5 100644 --- a/frontend/src/components/MarkdownToolbar.vue +++ b/frontend/src/components/MarkdownToolbar.vue @@ -1,130 +1,157 @@ diff --git a/frontend/src/views/NoteEditorView.vue b/frontend/src/views/NoteEditorView.vue index 014c9a2..e664048 100644 --- a/frontend/src/views/NoteEditorView.vue +++ b/frontend/src/views/NoteEditorView.vue @@ -321,7 +321,7 @@ onUnmounted(() => assist.clearSelection());
- Back + ← Notes @@ -575,8 +575,12 @@ onUnmounted(() => assist.clearSelection()); .body-tabs-row { display: flex; - flex-direction: column; - gap: 0.25rem; + flex-direction: row; + align-items: center; + gap: 0.75rem; + flex-wrap: wrap; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--color-border); } .editor-tabs { @@ -586,7 +590,7 @@ onUnmounted(() => assist.clearSelection()); border-radius: 8px; padding: 2px; gap: 2px; - align-self: flex-start; + flex-shrink: 0; } .tab { diff --git a/frontend/src/views/NoteViewerView.vue b/frontend/src/views/NoteViewerView.vue index 142dcbf..a91ab2b 100644 --- a/frontend/src/views/NoteViewerView.vue +++ b/frontend/src/views/NoteViewerView.vue @@ -138,7 +138,20 @@ async function convertToTask() {