14 Commits

Author SHA1 Message Date
Roberto
865220d9eb docs: mark Phase 0 complete in REFACTOR_PROGRESS
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:38:51 +02:00
Roberto
624bf8ff84 CORR-20: guard tzinfo on refresh-token expiry compare
Unconditional .replace(tzinfo=timezone.utc) would mislabel a non-UTC
aware datetime. Now only assume UTC when expires_at is naive, matching
the scout_runner pattern. 3 refresh tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:38:22 +02:00
Roberto
9440560e9b PERF-18: reuse AsyncOpenAI clients via lazy singletons
embeddings.embed_text and llm.embed created a fresh AsyncOpenAI client
(new HTTP connection pool) on every call, never closed. Replaced with
module-level lazy singletons reused across calls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:23:16 +02:00
Roberto
15499ff768 PERF-14: tame QueryClient focus-refetch storms
Electron renderer used a default QueryClient → every window-focus
refetched all queries into the synchronous SQLite layer, blocking IPC.
Set staleTime 30s + refetchOnWindowFocus:false; local writes already
invalidate explicitly. Single-window app, so no staleness concern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:22:06 +02:00
Roberto
70af1c6ba7 DEAD-12: split dev deps into requirements-dev.txt
Moved pytest, pytest-asyncio, aiosqlite, ruff out of runtime
requirements.txt into requirements-dev.txt (which -r includes runtime).
Docker/deploy install runtime only; CI test job installs the dev file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:21:01 +02:00
Roberto
52718655fd DEAD-11: remove dead TS exports
Deleted fully-unused getDbPath/getRawSqlite/closeDb (+ now-dead
_rawSqlite) and parseDateRange. Dropped `export` from internally-used
generateAndCacheBrief, attachmentsRoot, formatTime. Error classes kept
(instanceof). parseMutationsToEntityTags deferred to DEAD-06 (still
imported by the not-yet-removed dead useChatStream.ts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:19:49 +02:00
Roberto
759953b576 DEPS-08: move @types/ws to devDependencies
Type-only package; belongs in devDependencies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:16:16 +02:00
Roberto
4cec7cd79e DEAD-08: add web-SPA entries to knip.json
web.html + src/renderer/web-main.tsx are live via the standalone web
build but were false-flagged. Adding them makes knip runs trustworthy
for later dead-code items.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:15:31 +02:00
Roberto
f2c00f57b7 DEAD-05: remove 4 unused npm deps
next-themes, mammoth, pdf-parse, @hello-pangea/dnd — zero imports
(knip + grep verified; mammoth/pdf-parse are LanceDB-era leftovers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:14:31 +02:00
Roberto
c2afb9f054 DEAD-02: delete orphaned scout_registry.py
BaseAgent had zero importers/subclasses; referenced the deleted
vector-store era. 318 tests still collect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:13:47 +02:00
Roberto
e3328a7a29 DEAD-01: remove 5 dead Python deps
boto3, moto[s3], pinecone, qdrant-client, google-auth-oauthlib — zero
imports (grep-verified; pgvector is the live vector path, oauth flow is
hand-rolled httpx). 318 tests still collect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:13:00 +02:00
Roberto
6c1ddfd389 DEAD-10: remove 13 unused imports (ruff F401)
ruff check . --select F401 --fix across quota.py, deep_agent.py and 8
test files. Pytest still collects 318 tests; removed names were unused.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:11:48 +02:00
Roberto
78395ec9ee DEPS-01: bump ws to ^8.21.0 (GHSA-58qx-3vcg-4xpx)
ws <=8.20.0 had an uninitialized-memory disclosure. Raised floor to
^8.21.0; npm audit no longer reports the advisory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:10:16 +02:00
Roberto
a5910256e9 TYPE-01: fix broken shared/api-types relative imports in chat blocks
Removed one extra `../` (5 levels reached repo root, not src/) so the
block data types resolve instead of silently falling back to `any`.
Covers the 4th file (ChatTableBlock) the plan omitted; same bug.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 18:08:49 +02:00
31 changed files with 94 additions and 617 deletions

View File

@@ -41,11 +41,11 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt', 'requirements-dev.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Install dependencies
run: pip install -r requirements.txt
run: pip install -r requirements-dev.txt
- name: Run tests
run: pytest -v --tb=short

View File

@@ -202,7 +202,14 @@ async def refresh(
rt = result.scalar_one_or_none()
now = datetime.now(timezone.utc)
if rt is None or rt.expires_at.replace(tzinfo=timezone.utc) < now:
rt_exp = None
if rt is not None:
rt_exp = (
rt.expires_at
if rt.expires_at.tzinfo is not None
else rt.expires_at.replace(tzinfo=timezone.utc)
)
if rt is None or rt_exp < now:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Invalid or expired refresh token")
# Rotate: delete old token, issue new one.

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timezone
from sqlalchemy import select, update
from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.ext.asyncio import AsyncSession

View File

@@ -1244,7 +1244,7 @@ async def run_contextual_stream(
tracing and episode storage downstream. The WS handler in device_ws.py
satisfies this by always populating ``_debug`` before calling this function.
"""
from app.schemas.contextual import ContextualScope, render_scope_block # noqa: PLC0415
from app.schemas.contextual import render_scope_block # noqa: PLC0415
prepared_context = await _prepare_context(message, context)
trace_id = _trace_id_from_context(prepared_context)

View File

@@ -16,11 +16,21 @@ logger = logging.getLogger(__name__)
_MAX_INPUT_CHARS = 8000
_EMBEDDING_MODEL = "text-embedding-3-small"
_client: AsyncOpenAI | None = None
def _get_client() -> AsyncOpenAI:
"""Lazily create and reuse a single AsyncOpenAI client across calls."""
global _client
if _client is None:
_client = AsyncOpenAI()
return _client
async def embed_text(text: str) -> list[float] | None:
"""Call OpenAI text-embedding-3-small. Return None on failure (caller falls back to keyword)."""
try:
client = AsyncOpenAI()
client = _get_client()
truncated = text[:_MAX_INPUT_CHARS]
response = await client.embeddings.create(
input=truncated,

View File

@@ -30,6 +30,16 @@ from litellm import get_supported_openai_params # noqa: F401 validates inst
from app.config.settings import settings
_embed_client: AsyncOpenAI | None = None
def _get_embed_client() -> AsyncOpenAI:
"""Lazily create and reuse a single AsyncOpenAI embedding client."""
global _embed_client
if _embed_client is None:
_embed_client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
return _embed_client
# Some models (e.g. gpt-5, o-series) reject unsupported params like temperature.
# Drop them silently instead of raising UnsupportedParamsError.
litellm.drop_params = True
@@ -151,6 +161,6 @@ async def embed(text: str) -> list[float]:
return response.data[0]["embedding"]
# Plain OpenAI model name — use the raw AsyncOpenAI client (existing path).
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
client = _get_embed_client()
response = await client.embeddings.create(model=model, input=text)
return response.data[0].embedding

View File

@@ -1,30 +0,0 @@
"""Minimal agent base types retained for compatibility with batch runners."""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any
class BaseAgent(ABC):
"""Common base for non-chat agents still using the old base contract."""
def __init__(
self,
user_id: str = "",
shared_memory: dict[str, Any] | None = None,
vector_store_context: list[str] | None = None,
) -> None:
self.user_id = user_id
self.shared_memory: dict[str, Any] = shared_memory or {}
self.vector_store_context: list[str] = vector_store_context or []
@abstractmethod
def get_name(self) -> str: ...
@abstractmethod
def get_description(self) -> str: ...
@property
def skills(self) -> list[str]:
return []

7
api/requirements-dev.txt Normal file
View File

@@ -0,0 +1,7 @@
# Development/CI-only dependencies. Installs runtime deps too.
-r requirements.txt
pytest>=8.0.0
pytest-asyncio>=0.24.0
aiosqlite>=0.20.0
ruff>=0.8.0

View File

@@ -9,7 +9,6 @@ pydantic>=2.10.0
pydantic-settings>=2.7.0
python-jose[cryptography]>=3.3.0
stripe>=11.0.0
boto3>=1.35.0
slowapi>=0.1.9
sqlalchemy>=2.0.0
asyncpg>=0.30.0
@@ -19,16 +18,9 @@ python-dotenv>=1.0.0
httpx>=0.28.0
websockets>=14.0
psycopg2-binary>=2.9.0
pytest>=8.0.0
pytest-asyncio>=0.24.0
aiosqlite>=0.20.0
moto[s3]>=5.0.0
pinecone>=5.0.0
qdrant-client>=1.7.0
croniter>=3.0.0
google-api-python-client>=2.130.0
google-auth>=2.29.0
google-auth-oauthlib>=1.2.0
google-auth-httplib2>=0.2.0
msal>=1.28.0
cryptography>=42.0.0
@@ -38,6 +30,5 @@ beautifulsoup4>=4.12.0
lxml>=5.0.0
PyYAML>=6.0.0
apscheduler>=3.10.0
ruff>=0.8.0
pypdf>=4.0
python-docx>=1.1

View File

@@ -1,4 +1,3 @@
import pytest
from app.schemas.contextual import ContextualScope, render_scope_block

View File

@@ -5,7 +5,7 @@ not depend on litellm or the full deep_agent import chain. They monkeypatch
run_contextual_stream so no LLM call is made.
"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import AsyncMock, MagicMock
@pytest.mark.asyncio

View File

@@ -125,7 +125,7 @@ def _parse_ms(block: str, key: str) -> tuple[int, int]:
def test_datetime_context_injection_europe_rome_late_evening():
"""22:16 CEST on 2026-04-26 — 'tomorrow' must be 2026-04-27 00:00→23:59:59.999 CEST."""
from zoneinfo import ZoneInfo
from datetime import datetime, timezone
from datetime import datetime
block = _datetime_context_injection({"format_prefs": _fp("Europe/Rome", "2026-04-26T20:16:02.155Z")})
assert "DATE CONTEXT" in block

View File

@@ -5,7 +5,6 @@ rather than the plan's fictional _run_agent_loop, matching the real
deep_agent.py architecture.
"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from app.schemas.contextual import ContextualScope

View File

@@ -4,7 +4,6 @@ from __future__ import annotations
import pytest
from app.scouts.connectors.base import ItemRef
from app.scouts.connectors.registry import (
get_connector,
register_connector,

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
import uuid
from unittest.mock import MagicMock, patch
from unittest.mock import patch
import pytest

View File

@@ -9,7 +9,7 @@ from unittest.mock import AsyncMock
import pytest
from sqlalchemy import select
from app.models import CloudScoutConfig, ScoutTriageQueue, User, Subscription
from app.models import CloudScoutConfig, ScoutTriageQueue
from app.scouts.connectors.base import ItemContent, ItemMetadata, ItemRef, TriageVerdict
from app.scouts.connectors.registry import register_connector, _reset_for_tests
from app.scouts.engine import ScoutEngine

View File

@@ -19,7 +19,6 @@ from app.api.routes.device_ws import (
_handle_index_session_cancel,
_index_sessions,
)
from app.billing.quota import add_token_usage
from app.core.folder_indexer import IndexResult
from app.models import MonthlyTokenUsage
from app.schemas import WsFrameType

View File

@@ -33,19 +33,19 @@ Branch: `refactor/phase-0` · Verify after each: `cd api && ruff check . && pyte
| ID | ⚠️ | Status | Commit | Notes |
|---|---|---|---|---|
| TYPE-01 | | pending | | |
| DEPS-01 | | pending | | |
| DEAD-10 | | pending | | |
| DEAD-01 | | pending | | |
| DEAD-02 | | pending | | |
| DEAD-05 | | pending | | |
| DEAD-08 | | pending | | |
| DEPS-08 | | pending | | |
| DEAD-11 | | pending | | |
| DEAD-12 | | pending | | |
| PERF-14 | | pending | | |
| PERF-18 | | pending | | |
| CORR-20 | | pending | | |
| TYPE-01 | | done | a591025 | Files at `electron/src/...` not `adiuvAI/src/...` (monorepo move). Plan listed 3 files; 4th (ChatTableBlock.tsx) had identical bug — fixed too. |
| DEPS-01 | | done | 78395ec | ws@8.21.0; GHSA-58qx confirmed gone via npm audit. Other 57 advisories untouched (DEPS-05/06/07 scope). |
| DEAD-10 | | done | 6c1ddfd | 13 F401 fixed (quota.py, deep_agent.py, 8 test files). 318 tests still collect. Full `ruff check .` still has 21 errors from other rules (pre-existing, out of scope). |
| DEAD-01 | | done | e3328a7 | Removed boto3, moto[s3], pinecone, qdrant-client, google-auth-oauthlib. Only ref was a comment in oauth_providers.py confirming non-use. |
| DEAD-02 | | done | c2afb9f | Deleted; zero importers confirmed. |
| DEAD-05 | | done | f2c00f5 | Uninstalled next-themes, mammoth, pdf-parse, @hello-pangea/dnd. Zero imports confirmed. |
| DEAD-08 | | done | 4cec7cd | Added web.html + web-main.tsx to knip entry. knip no longer flags web-main/httpLink. |
| DEPS-08 | | done | 759953b | Moved @types/ws dependencies → devDependencies; lock marks dev:true. |
| DEAD-11 | | done | 5271865 | Deleted getDbPath/getRawSqlite/closeDb (+dead _rawSqlite), parseDateRange. Dropped export on generateAndCacheBrief/attachmentsRoot/formatTime. **parseMutationsToEntityTags NOT removed** — still imported by dead useChatStream.ts; defer to DEAD-06. No BackupManager exists (the "Used by BackupManager" comments were aspirational). |
| DEAD-12 | | done | 70af1c6 | New requirements-dev.txt (-r requirements.txt + pytest/pytest-asyncio/aiosqlite/ruff). CI test job → dev file; lint job already installs ruff standalone. Dockerfile/deploy already runtime-only. Stale-doc-comment part of plan not found; n/a. |
| PERF-14 | | done | 15499ff | QueryClient defaultOptions staleTime 30s + refetchOnWindowFocus:false. |
| PERF-18 | | done | 9440560 | Lazy module-level singletons in embeddings.py (_get_client) + llm.py (_get_embed_client). |
| CORR-20 | | done | 624bf8f | tzinfo guard before expiry compare. 3 refresh tests pass. |
## Phase 1 — Critical & High security (ALL ⚠️ — implement, never merge unreviewed)
Branch: `refactor/phase-1-security`
@@ -194,10 +194,14 @@ Branch: `refactor/phase-6-quality`
_Append findings that affect later items. Format: `- [ID] lesson`_
(none yet)
- [paths] Electron app now lives at `electron/`, FastAPI at `api/` (monorepo merge). Plan's `adiuvAI/src/...` paths map to `electron/src/...`. `npx tsc`/`npx eslint` need `node_modules` — run `npm install` in `electron/` first (was absent).
- [TYPE-01] Plan undercounted: 4 chat blocks had the broken import, not 3 (added ChatTableBlock.tsx).
- [TYPE-03] Fixing TYPE-01 surfaces a real latent bug now that types resolve: `ChatChartBlock.tsx:38` TS2488 — `Object.entries(config)[i]` destructured under `noUncheckedIndexedAccess` is possibly-undefined. Was hidden under `any`. Address in TYPE-03. Baseline tsc error count after TYPE-01 = 38 (unchanged through DEAD-11).
- [DEAD-06] `parseMutationsToEntityTags` (useAIChat.ts) export was left in place by DEAD-11 because dead file `useChatStream.ts` still imports it. When DEAD-06 deletes useChatStream.ts, also drop the `export` keyword (it's used internally at useAIChat.ts:191).
- [DEAD-07] No `BackupManager` exists in the codebase. The backup-key.ts (DEAD-07) + the removed getRawSqlite/closeDb were scaffolding for an unwired backup feature. DEAD-11 removed the db helpers per plan; backup-key.ts decision still owner-pending.
## Session Log
| Date | Model | Phase | Items touched | Outcome |
|---|---|---|---|---|
| | | | | |
| 2026-06-12 | Opus 4.8 | 0 | TYPE-01, DEPS-01, DEAD-10, DEAD-01, DEAD-02, DEAD-05, DEAD-08, DEPS-08, DEAD-11, DEAD-12, PERF-14, PERF-18, CORR-20 | **Phase 0 complete** — all 13 items done. One commit each. node_modules installed for verify. Pytest uses in-memory sqlite (no Postgres needed); heavy first-import (~min) makes pytest slow to start — use streaming output, not `Select-Object -Last`. |

View File

@@ -8,7 +8,9 @@
"forge.config.ts",
"vite.main.config.mts",
"vite.preload.config.mts",
"vite.renderer.config.mts"
"vite.renderer.config.mts",
"web.html",
"src/renderer/web-main.tsx"
],
"ignoreDependencies": [
"postcss",

View File

@@ -10,7 +10,6 @@
"license": "MIT",
"dependencies": {
"@fontsource/geist": "^5.2.8",
"@hello-pangea/dnd": "^18.0.1",
"@milkdown/crepe": "^7.18.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.0",
@@ -19,7 +18,6 @@
"@trpc/client": "^11.10.0",
"@trpc/react-query": "^11.10.0",
"@trpc/server": "^11.10.0",
"@types/ws": "^8.18.1",
"better-sqlite3": "^12.6.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -30,9 +28,6 @@
"framer-motion": "^12.34.2",
"i18next": "^26.0.4",
"lucide-react": "^0.575.0",
"mammoth": "^1.11.0",
"next-themes": "^0.4.6",
"pdf-parse": "^2.4.5",
"radix-ui": "^1.4.3",
"react": "^19.2.4",
"react-day-picker": "^9.13.2",
@@ -46,7 +41,7 @@
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"ws": "^8.19.0",
"ws": "^8.21.0",
"zod": "^4.3.6"
},
"devDependencies": {
@@ -65,6 +60,7 @@
"@types/node": "^25.3.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^5.1.4",
@@ -3055,23 +3051,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@hello-pangea/dnd": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz",
"integrity": "sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==",
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.26.7",
"css-box-model": "^1.2.1",
"raf-schd": "^4.0.3",
"react-redux": "^9.2.0",
"redux": "^5.0.1"
},
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/@hono/node-server": {
"version": "1.19.9",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
@@ -4301,190 +4280,6 @@
"node": ">=18"
}
},
"node_modules/@napi-rs/canvas": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.80.tgz",
"integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==",
"license": "MIT",
"workspaces": [
"e2e/*"
],
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@napi-rs/canvas-android-arm64": "0.1.80",
"@napi-rs/canvas-darwin-arm64": "0.1.80",
"@napi-rs/canvas-darwin-x64": "0.1.80",
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80",
"@napi-rs/canvas-linux-arm64-gnu": "0.1.80",
"@napi-rs/canvas-linux-arm64-musl": "0.1.80",
"@napi-rs/canvas-linux-riscv64-gnu": "0.1.80",
"@napi-rs/canvas-linux-x64-gnu": "0.1.80",
"@napi-rs/canvas-linux-x64-musl": "0.1.80",
"@napi-rs/canvas-win32-x64-msvc": "0.1.80"
}
},
"node_modules/@napi-rs/canvas-android-arm64": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz",
"integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-darwin-arm64": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz",
"integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-darwin-x64": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz",
"integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm-gnueabihf": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz",
"integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-gnu": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz",
"integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-musl": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz",
"integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-riscv64-gnu": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz",
"integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-x64-gnu": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz",
"integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-x64-musl": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz",
"integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-win32-x64-msvc": {
"version": "0.1.80",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz",
"integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
@@ -7991,6 +7786,7 @@
"version": "25.3.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz",
"integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
@@ -8052,12 +7848,6 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
"license": "MIT"
},
"node_modules/@types/validate-npm-package-name": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz",
@@ -8076,6 +7866,7 @@
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -8856,6 +8647,7 @@
"version": "0.8.11",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
"integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -10349,12 +10141,6 @@
"node": ">=6.6.0"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@@ -10471,15 +10257,6 @@
"node": ">=12.10"
}
},
"node_modules/css-box-model": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
"license": "MIT",
"dependencies": {
"tiny-invariant": "^1.0.6"
}
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -10994,12 +10771,6 @@
"node": ">=0.3.1"
}
},
"node_modules/dingbat-to-unicode": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz",
"integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==",
"license": "BSD-2-Clause"
},
"node_modules/dir-compare": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz",
@@ -11709,15 +11480,6 @@
}
}
},
"node_modules/duck": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz",
"integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==",
"license": "BSD",
"dependencies": {
"underscore": "^1.13.1"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -14719,12 +14481,6 @@
"node": ">= 4"
}
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -15684,54 +15440,6 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/jszip/node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/jszip/node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/jszip/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/jszip/node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/junk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
@@ -15869,15 +15577,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lightningcss": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
@@ -16313,17 +16012,6 @@
"loose-envify": "cli.js"
}
},
"node_modules/lop": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/lop/-/lop-0.4.2.tgz",
"integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==",
"license": "BSD-2-Clause",
"dependencies": {
"duck": "^0.1.12",
"option": "~0.2.1",
"underscore": "^1.13.1"
}
},
"node_modules/lowercase-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
@@ -16390,60 +16078,6 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/mammoth": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.11.0.tgz",
"integrity": "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ==",
"license": "BSD-2-Clause",
"dependencies": {
"@xmldom/xmldom": "^0.8.6",
"argparse": "~1.0.3",
"base64-js": "^1.5.1",
"bluebird": "~3.4.0",
"dingbat-to-unicode": "^1.0.1",
"jszip": "^3.7.1",
"lop": "^0.4.2",
"path-is-absolute": "^1.0.0",
"underscore": "^1.13.1",
"xmlbuilder": "^10.0.0"
},
"bin": {
"mammoth": "bin/mammoth"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/mammoth/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/mammoth/node_modules/bluebird": {
"version": "3.4.7",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
"license": "MIT"
},
"node_modules/mammoth/node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
"node_modules/mammoth/node_modules/xmlbuilder": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz",
"integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
},
"node_modules/map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
@@ -17966,16 +17600,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/next-themes": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -18319,12 +17943,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/option": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz",
"integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==",
"license": "BSD-2-Clause"
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -18565,12 +18183,6 @@
"node": ">=4"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -18679,6 +18291,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -18725,38 +18338,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/pdf-parse": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-2.4.5.tgz",
"integrity": "sha512-mHU89HGh7v+4u2ubfnevJ03lmPgQ5WU4CxAVmTSh/sxVTEDYd1er/dKS/A6vg77NX47KTEoihq8jZBLr8Cxuwg==",
"license": "Apache-2.0",
"dependencies": {
"@napi-rs/canvas": "0.1.80",
"pdfjs-dist": "5.4.296"
},
"bin": {
"pdf-parse": "bin/cli.mjs"
},
"engines": {
"node": ">=20.16.0 <21 || >=22.3.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/mehmet-kozan"
}
},
"node_modules/pdfjs-dist": {
"version": "5.4.296",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz",
"integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==",
"license": "Apache-2.0",
"engines": {
"node": ">=20.16.0 || >=22.3.0"
},
"optionalDependencies": {
"@napi-rs/canvas": "^0.1.80"
}
},
"node_modules/pe-library": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pe-library/-/pe-library-1.0.1.tgz",
@@ -19083,12 +18664,6 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -19588,12 +19163,6 @@
}
}
},
"node_modules/raf-schd": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
"integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==",
"license": "MIT"
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -19799,29 +19368,6 @@
"react": ">=18"
}
},
"node_modules/react-redux": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
},
"peerDependencies": {
"@types/react": "^18.2.25 || ^19",
"react": "^18.0 || ^19",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
@@ -20180,12 +19726,6 @@
"node": ">= 10.13.0"
}
},
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -20994,12 +20534,6 @@
"node": ">= 0.4"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -23332,16 +22866,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/underscore": {
"version": "1.13.8",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
"integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
"license": "MIT"
},
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/unicorn-magic": {
@@ -24189,9 +23718,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"

View File

@@ -35,6 +35,7 @@
"@types/node": "^25.3.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^5.1.4",
@@ -53,7 +54,6 @@
},
"dependencies": {
"@fontsource/geist": "^5.2.8",
"@hello-pangea/dnd": "^18.0.1",
"@milkdown/crepe": "^7.18.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.0",
@@ -62,7 +62,6 @@
"@trpc/client": "^11.10.0",
"@trpc/react-query": "^11.10.0",
"@trpc/server": "^11.10.0",
"@types/ws": "^8.18.1",
"better-sqlite3": "^12.6.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -73,9 +72,6 @@
"framer-motion": "^12.34.2",
"i18next": "^26.0.4",
"lucide-react": "^0.575.0",
"mammoth": "^1.11.0",
"next-themes": "^0.4.6",
"pdf-parse": "^2.4.5",
"radix-ui": "^1.4.3",
"react": "^19.2.4",
"react-day-picker": "^9.13.2",
@@ -89,7 +85,7 @@
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"ws": "^8.19.0",
"ws": "^8.21.0",
"zod": "^4.3.6"
}
}

View File

@@ -254,7 +254,7 @@ function scheduleBriefRegeneration(delayMs = BRIEF_REGEN_DEBOUNCE_MS): void {
}
/** Regenerate the brief silently in background, cache it, then push to all windows. */
export async function generateAndCacheBrief(): Promise<boolean> {
async function generateAndCacheBrief(): Promise<boolean> {
const check = await checkConnectivity();
if (!check.ok) return false;

View File

@@ -14,7 +14,7 @@ function sanitizeFilename(name: string): string {
return stripped.length > FILENAME_MAX ? stripped.slice(0, FILENAME_MAX) : stripped;
}
export function attachmentsRoot(): string {
function attachmentsRoot(): string {
return path.join(app.getPath('userData'), 'attachments');
}

View File

@@ -9,9 +9,6 @@ import * as schema from './schema';
/** Resolved path to the SQLite database file. Set once in initDb(). */
let _dbPath: string | null = null;
/** Raw better-sqlite3 instance (needed for .backup() API). */
let _rawSqlite: Database.Database | null = null;
type DbInstance = ReturnType<typeof drizzle<typeof schema>>;
let dbInstance: DbInstance | null = null;
@@ -92,7 +89,6 @@ export function initDb(): DbInstance {
_dbPath = path.join(userDataPath, 'adiuvai.db');
const sqlite = new Database(_dbPath);
_rawSqlite = sqlite;
// Enable WAL mode for better concurrent read performance
sqlite.pragma('journal_mode = WAL');
@@ -114,30 +110,3 @@ export function getDb(): DbInstance {
return dbInstance;
}
/** Returns the absolute path to the active SQLite database file. */
export function getDbPath(): string {
if (!_dbPath) throw new Error('Database not initialized.');
return _dbPath;
}
/**
* Returns the raw better-sqlite3 Database instance.
* Used by BackupManager for the `.backup()` API.
*/
export function getRawSqlite(): Database.Database {
if (!_rawSqlite) throw new Error('Database not initialized.');
return _rawSqlite;
}
/**
* Closes the database connection and clears all module-level references.
* Called by BackupManager before atomically replacing the DB file.
* After calling this, you must call `initDb()` again to re-open.
*/
export function closeDb(): void {
if (_rawSqlite) {
try { _rawSqlite.close(); } catch { /* ignore */ }
_rawSqlite = null;
}
dbInstance = null;
}

View File

@@ -24,7 +24,7 @@ import {
ChartTooltipContent,
type ChartConfig,
} from '@/components/ui/chart';
import type { ChartBlockData } from '../../../../../shared/api-types';
import type { ChartBlockData } from '../../../../shared/api-types';
export function ChatChartBlock({ data: blockData }: { data: ChartBlockData }) {
const { chartType, title, data } = blockData;

View File

@@ -10,7 +10,7 @@ import { EditTaskDialog } from '@/components/tasks/EditTaskDialog';
import { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription } from '@/components/ui/item';
import { ChatTimelineBlock } from './ChatTimelineBlock';
import { useFormatPrefs, formatDate } from '@/lib/date';
import type { EntityRefBlockData } from '../../../../../shared/api-types';
import type { EntityRefBlockData } from '../../../../shared/api-types';
export function ChatEntityBlock({ data }: { data: EntityRefBlockData }) {
const { entity, ids } = data;

View File

@@ -6,7 +6,7 @@ import {
TableRow,
TableCell,
} from '@/components/ui/table';
import type { TableBlockData } from '../../../../../shared/api-types';
import type { TableBlockData } from '../../../../shared/api-types';
export function ChatTableBlock({ data }: { data: TableBlockData }) {
const { headers, rows } = data;

View File

@@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { trpc } from '@/lib/trpc';
import { ProjectTimelineBox, type ProjectGroup } from '@/components/timeline/ProjectTimelineBox';
import type { TimelineEvent } from '@/components/timeline/ProjectTimeline';
import type { TimelineBlockData } from '../../../../../shared/api-types';
import type { TimelineBlockData } from '../../../../shared/api-types';
export function ChatTimelineBlock({ data }: { data: TimelineBlockData }) {
const { events: rawEvents } = data;

View File

@@ -12,7 +12,14 @@ import i18n from './i18n';
import './globals.css';
function App() {
const [queryClient] = useState(() => new QueryClient());
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: { staleTime: 30_000, refetchOnWindowFocus: false },
},
}),
);
const [trpcClient] = useState(() =>
trpc.createClient({
links: [ipcLink()],

View File

@@ -69,7 +69,7 @@ export function formatDate(ms: number, prefs: FormatPrefs): string {
}
/** Format the time portion of a ms-epoch timestamp per user prefs. */
export function formatTime(ms: number, prefs: FormatPrefs): string {
function formatTime(ms: number, prefs: FormatPrefs): string {
return new Date(ms).toLocaleTimeString('en-US', {
timeZone: prefs.timezone,
hour12: prefs.timeFormat === '12h',

View File

@@ -148,24 +148,3 @@ export function parseDate(
return null;
}
export function parseDateRange(
input: ParseInput,
prefs: FormatPrefs,
keywords: DateKeywords,
baseDate: Date = new Date(),
): { from: Date; to?: Date } | null {
if (!input) return null;
const parts = input.split(/\s+(?:-{1,2}||to)\s+/i);
if (parts.length === 1) {
const single = parseDate(parts[0], prefs, keywords, baseDate);
return single ? { from: single } : null;
}
if (parts.length === 2) {
const from = parseDate(parts[0], prefs, keywords, baseDate);
if (!from) return null;
const to = parseDate(parts[1], prefs, keywords, from);
if (!to) return null;
return { from, to };
}
return null;
}