From f3750f8469f234a96440b1b58dfb8a84d1440f15 Mon Sep 17 00:00:00 2001 From: Lukas Geiger Date: Mon, 12 Oct 2026 14:22:13 +0200 Subject: [PATCH] Complete KnowledgeDigest full-care and packaging Signed-off-by: Lukas Geiger --- .github/workflows/tests.yml | 86 +++++++++++ ARCHITECTURE.md | 29 ++-- CHANGELOG.md | 2 + MANIFEST.in | 18 +++ MARKETING-LOG.txt | 10 ++ README.md | 293 +++++++++++------------------------ README_de.md | 298 +++++++++++------------------------- SECURITY.md | 38 ++--- SMOKE-CHECKS.md | 203 +++--------------------- THIRD_PARTY_LICENSES.md | 90 ++++------- llms.txt | 93 ++++------- pyproject.toml | 6 +- tests/package_smoke.py | 24 +++ tests/test_metadata.py | 73 +-------- tests/test_no_agpl.py | 23 ++- tests/test_packaging.py | 15 ++ 16 files changed, 467 insertions(+), 834 deletions(-) create mode 100644 MANIFEST.in create mode 100644 tests/package_smoke.py create mode 100644 tests/test_packaging.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5efa91b..1c16919 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,3 +47,89 @@ jobs: run: | python -m KnowledgeDigest --help knowledgedigest --help + + package-artifacts: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install Qt runtime libraries + run: | + sudo apt-get update + sudo apt-get install --yes libegl1 libgl1 libxkbcommon-x11-0 libdbus-1-3 + + - name: Build wheel and source distribution + run: | + python -m pip install --upgrade pip + python -m pip install build PySide6 + python -m build --wheel --sdist --outdir "$RUNNER_TEMP/dist" + + - name: Verify package icon and source documentation links + run: | + python - <<'PY' + from pathlib import Path + import os + import re + import tarfile + from urllib.parse import unquote, urlsplit + import zipfile + + dist = Path(os.environ["RUNNER_TEMP"]) / "dist" + wheel = next(dist.glob("*.whl")) + sdist = next(dist.glob("*.tar.gz")) + with zipfile.ZipFile(wheel) as archive: + assert any(name.endswith("/KnowledgeDigest.ico") for name in archive.namelist()) + with tarfile.open(sdist, "r:gz") as archive: + names = set(archive.getnames()) + root = next(name.split("/", 1)[0] for name in names if name.endswith("/PKG-INFO")) + required = [ + "ARCHITECTURE.md", "CHANGELOG.md", "LICENSE", "MARKETING-LOG.txt", "NOTICE", + "README.md", "README_de.md", "SECURITY.md", "SMOKE-CHECKS.md", + "THIRD_PARTY_LICENSES.md", "llms.txt", "assets/banner.png", "assets/banner.svg", + ".github/workflows/tests.yml", "tests/package_smoke.py", "tests/test_metadata.py", + "tests/test_no_agpl.py", "tests/test_packaging.py", "KnowledgeDigest.ico", + ] + missing = [path for path in required if f"{root}/{path}" not in names] + assert not missing, f"source archive is missing documented files: {missing}" + + link_pattern = re.compile(r"!?\[[^\]]*\]\(([^\s)]+)|]*?\bsrc=[\"']([^\"']+)", re.I) + for readme in ("README.md", "README_de.md"): + content = archive.extractfile(f"{root}/{readme}").read().decode("utf-8") + for markdown_link, image_src in link_pattern.findall(content): + link = markdown_link or image_src + parsed = urlsplit(link) + if parsed.scheme or parsed.netloc or not parsed.path: + continue + target = Path(unquote(parsed.path).replace("/", os.sep)) + member = f"{root}/{target.as_posix()}" + assert member in names, f"{readme} links to missing source archive member: {link}" + PY + + - name: Install and smoke-test wheel + env: + QT_QPA_PLATFORM: offscreen + run: | + mkdir -p "$RUNNER_TEMP/wheel-target" + wheel="$(find "$RUNNER_TEMP/dist" -maxdepth 1 -name '*.whl' -print -quit)" + python -m pip install --no-deps --target "$RUNNER_TEMP/wheel-target" "$wheel" + cd "$RUNNER_TEMP" + PYTHONPATH="$RUNNER_TEMP/wheel-target" python -m KnowledgeDigest --help + PYTHONPATH="$RUNNER_TEMP/wheel-target" python "$GITHUB_WORKSPACE/tests/package_smoke.py" + + - name: Install and smoke-test source distribution + env: + QT_QPA_PLATFORM: offscreen + run: | + mkdir -p "$RUNNER_TEMP/sdist-target" + sdist="$(find "$RUNNER_TEMP/dist" -maxdepth 1 -name '*.tar.gz' -print -quit)" + python -m pip install --no-deps --target "$RUNNER_TEMP/sdist-target" "$sdist" + cd "$RUNNER_TEMP" + PYTHONPATH="$RUNNER_TEMP/sdist-target" python -m KnowledgeDigest --help + PYTHONPATH="$RUNNER_TEMP/sdist-target" python "$GITHUB_WORKSPACE/tests/package_smoke.py" diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 8d335ab..9f8dfbb 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,10 +2,7 @@ ## Overview -KnowledgeDigest is a portable, self-contained knowledge database. It indexes -documents from local directories, chunks them into searchable segments, and -provides FTS5 full-text search via three interfaces: Desktop GUI, Web Viewer, -and Python API. +KnowledgeDigest indexes user-selected documents into a local SQLite database and provides FTS5 search through its desktop GUI, web viewer, CLI, and Python API. Optional summarization sends selected chunks and prompts to a configured provider; a custom API endpoint may be remote. ## Module Structure @@ -88,7 +85,7 @@ sequenceDiagram participant Core as "Digest Core" participant Ingest as "Ingestor & Chunker" participant DB as "SQLite (FTS5 & Triggers)" - participant LLM as "LLM Summarizer" + participant LLM as "Configured LLM endpoint" Note over User,DB: Phase 1: Ingestion & Indexing User->>CLI: "Ingest directory (/path/to/docs)" @@ -97,8 +94,9 @@ sequenceDiagram Ingest->>DB: "Store metadata, chunks & keywords" DB-->>DB: "Auto-sync BM25 FTS5 index via triggers" opt "Optional Summarization" - Core->>LLM: "Queue chunks (Gemini Flash / Claude Haiku)" - LLM-->>DB: "Store structured summaries & domain tags" + Core->>LLM: "Send selected chunks + prompt when invoked" + LLM-->>Core: "Return summary" + Core->>DB: "Store summary locally" end Core-->>CLI: "Ingestion complete & indexed" @@ -132,8 +130,9 @@ Normalized multi-table schema with FTS5 full-text search: ### Portable JSON Config - No hardcoded paths; everything configurable via `knowledgedigest.json` -- Config searched in: CWD → data/ → %APPDATA% → defaults -- Copy the folder to another machine and it works +- Config search order: CWD → package data/ → %APPDATA% (Windows, when set) → XDG_CONFIG_HOME or ~/.config/knowledgedigest/. +- If no file exists, defaults and package data/ paths are used; an installed package directory may not be writable. +- There is no --config CLI option. Python callers may pass an explicit path to get_config(config_path). ### FTS5 over Keyword Search - SQLite FTS5 provides BM25 ranking, snippet highlighting, prefix search @@ -154,7 +153,7 @@ Normalized multi-table schema with FTS5 full-text search: ### Two Frontends - **PySide6 GUI**: Full desktop app with 3-panel layout, dark theme -- **Web Viewer**: Python stdlib only (no dependencies), runs on localhost +- **Web Viewer**: Python stdlib only; current HTTP server binds to 127.0.0.1 and is not an authenticated remote service ## API @@ -178,9 +177,17 @@ python -m KnowledgeDigest status # Index statistics python -m KnowledgeDigest search "query" # FTS5 search ``` +## Provider and Data Boundaries + +- Local parsing, indexing, and FTS5 search do not require an LLM provider. +- CLI summarize uses Anthropic by default; --flash selects Google GenAI. The Python API supports Ollama/custom base URLs. +- Provider requests include selected document content and prompts. Custom endpoints may be remote. +- Optional SQLite Transit synchronization can move configured snapshots between nodes. +- The current desktop GUI has German-only visible strings and no language selector. + ## Technical Constraints - Python 3.10+ with sqlite3 FTS5 support - `PYTHONIOENCODING=utf-8` required on Windows - Windows-compatible paths and encoding -- PySide6 (LGPL) for GUI, no PyQt dependency +- PySide6 for GUI, no PyQt dependency; upstream licensing options vary, so inspect the selected distribution's license files diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f91e45..0d2a775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +- **Documentation and package boundary corrections (2026-10-12)**: Clarified that core indexing/search use the local database while optional provider and synchronization paths may transfer configured data; corrected CLI/configuration documentation; bounded dependency/license and security statements; added a wheel/sdist smoke gate for the packaged GUI icon. Version remains 0.4.0. + - **Bugfix-Sweep (2026-10-06)**: - **FTS5-Delete-Trigger repariert (Schema v5)**: Die Trigger nutzten den FTS5-`'delete'`-Befehl auf regulären FTS5-Tabellen → `SQL logic error` bei jedem Löschen von Chunks (Re-Ingest, `index --force`, Web-Viewer-Löschen, `deduplicate`). Bestehende Datenbanken werden beim Öffnen migriert. - **Löschen konsistent**: Web-Viewer und `deduplicate` entfernen zuerst die DB-Einträge (Transaktion) und verschieben danach die Datei in `_Papierkorb`; Fehler pro Eintrag brechen den Lauf nicht mehr ab. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..6eb6140 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,18 @@ +include ARCHITECTURE.md +include CHANGELOG.md +include LICENSE +include MARKETING-LOG.txt +include NOTICE +include README.md +include README_de.md +include SECURITY.md +include SMOKE-CHECKS.md +include THIRD_PARTY_LICENSES.md +include llms.txt +include assets/banner.png +include assets/banner.svg +include .github/workflows/tests.yml +include tests/package_smoke.py +include tests/test_metadata.py +include tests/test_no_agpl.py +include tests/test_packaging.py diff --git a/MARKETING-LOG.txt b/MARKETING-LOG.txt index b1933a1..c4418e5 100644 --- a/MARKETING-LOG.txt +++ b/MARKETING-LOG.txt @@ -1,3 +1,13 @@ +# Supersession note — 2026-10-12 + +Entries below record historical work and do not verify current security, privacy, licensing, test-count, service-level, or compliance guarantees. Current public descriptions are limited to reviewed source paths and declared direct dependencies: + +- Core indexing and search use the configured local SQLite database. Optional summarization sends selected text and prompts to the configured provider when invoked; optional synchronization can move configured snapshots. +- The dependency note is manually maintained and is not a generated SBOM or complete transitive-dependency audit. +- The GUI currently has German-only strings. README validation checks 18 matching navigation anchors, not full translation parity. +- Response times are maintainer goals, not guaranteed SLAs. GitHub Private Vulnerability Reporting availability depends on repository settings. +- Version 0.4.0 remains frozen; this documentation update is not a release or store submission. + # MARKETING-LOG.txt — KnowledgeDigest # Chronologisches Log fuer Repository-Pflege, Hygiene (Pfad A) und Sichtbarkeit/Marketing (Pfad B) diff --git a/README.md b/README.md index 13e0c80..bd73c74 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,15 @@ [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue.svg)](https://www.python.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Attribution: NOTICE](https://img.shields.io/badge/Attribution-NOTICE-blue.svg)](NOTICE) -[![SBOM: Level 1 Audited](https://img.shields.io/badge/SBOM-Level%201%20Audited-blue.svg)](THIRD_PARTY_LICENSES.md) [![Version: 0.4.0](https://img.shields.io/badge/Version-0.4.0-informational.svg)](CHANGELOG.md) -[![Tests: 163 Passed](https://img.shields.io/badge/tests-163%20passed%20%7C%20100%25%20green-brightgreen.svg)](#16-testing-contract-verification) [![Search: SQLite FTS5](https://img.shields.io/badge/Search-SQLite%20FTS5%20BM25-green.svg)](#3-architecture) -[![Privacy: Zero-Egress](https://img.shields.io/badge/Privacy-100%25%20Local%20%7C%20Zero--Egress-brightgreen.svg)](#7-governance-invariants) -[![Execution: RunAsInvoker](https://img.shields.io/badge/Execution-RunAsInvoker-brightgreen.svg)](SECURITY.md) -[![Security SLA: 48h](https://img.shields.io/badge/Security%20SLA-48h%20Response-blue.svg)](SECURITY.md) [![GUI: PySide6](https://img.shields.io/badge/GUI-PySide6-41CD52.svg?logo=qt&logoColor=white)](#9-desktop-gui) [![Web: Stdlib](https://img.shields.io/badge/Web-Stdlib%20Zero--Dep-blue.svg)](#10-web-viewer) [![LLM-Ready](https://img.shields.io/badge/LLM-Ready%20%7C%20Opt--in-purple.svg)](#14-optional-integrations-ecosystem) -[![Last Checked: 2026-09-22](https://img.shields.io/badge/Last--Checked-2026--09--22-informational.svg)](MARKETING-LOG.txt) [![Organization: file-bricks](https://img.shields.io/badge/Organization-file--bricks-purple.svg)](https://github.com/file-bricks) [![Umbrella: open-bricks](https://img.shields.io/badge/Umbrella-open--bricks-blue.svg)](https://github.com/open-bricks) -> Portable, self-contained knowledge database — indexes local documents, performs sentence-bounded semantic chunking, and provides instant SQLite FTS5 full-text search with BM25 ranking. Includes a native PySide6 desktop GUI and a zero-dependency local web viewer. +> A local-first Python tool for document indexing and SQLite FTS5 search. Optional summarization sends selected text to the configured provider when invoked; provider requests can leave the machine. > [!NOTE] > **AI / LLM Integration & Machine-Readable Context**
@@ -31,34 +25,30 @@ ## 🧭 Quick Navigation -[1. Overview](#1-overview) • [2. Key Features](#2-key-features) • [3. Architecture](#3-architecture) • [4. Lifecycle](#4-lifecycle) • [5. Target Personas](#5-target-personas) • [6. Comparison Matrix](#6-comparison-matrix) • [7. Governance Invariants](#7-governance-invariants) • [8. Search Disambiguation](#8-search-disambiguation) • [9. Desktop GUI](#9-desktop-gui) • [10. Web Viewer](#10-web-viewer) • [11. Multi-Interface CLI](#11-multi-interface-cli) • [12. Python API](#12-python-api) • [13. Configuration & Paths](#13-configuration-paths) • [14. Integrations & Ecosystem](#14-integrations-ecosystem) • [15. Setup & Installation](#15-setup-installation) • [16. Testing & Verification](#16-testing-contract-verification) • [17. Level 1 SBOM](#17-level-1-sbom-third-party-licenses) • [18. Legal Disclaimer & SLA](#18-legal-disclaimer-521-bgb-security-sla) +[1. Overview](#1-overview) • [2. Key Features](#2-key-features) • [3. Architecture](#3-architecture) • [4. Lifecycle](#4-lifecycle) • [5. Target Personas](#5-target-personas) • [6. Comparison Matrix](#6-comparison-matrix) • [7. Governance Invariants](#7-governance-invariants) • [8. Search Disambiguation](#8-search-disambiguation) • [9. Desktop GUI](#9-desktop-gui) • [10. Web Viewer](#10-web-viewer) • [11. Multi-Interface CLI](#11-multi-interface-cli) • [12. Python API](#12-python-api) • [13. Configuration & Paths](#13-configuration-paths) • [14. Integrations & Ecosystem](#14-integrations-ecosystem) • [15. Setup & Installation](#15-setup-installation) • [16. Testing & Verification](#16-testing-contract-verification) • [17. Dependency Notes](#17-level-1-sbom-third-party-licenses) • [18. Legal and Support](#18-legal-disclaimer-521-bgb-security-sla) --- ## 1. Overview -**KnowledgeDigest** is an offline-first, local Python knowledge database and search engine. It transforms unorganized document directories (PDF, Microsoft Word DOCX, HTML, Markdown, and TXT) into a structured, relational SQLite database equipped with an FTS5 full-text index and BM25 relevance ranking. +**KnowledgeDigest** indexes user-selected documents into a local SQLite database and provides FTS5 full-text search with BM25 ranking. Parsing, chunking, indexing, and ordinary search use the local database and do not require an LLM provider. -Unlike cloud-based knowledge systems that require transmitting confidential documents to remote third parties, KnowledgeDigest operates 100% locally on your machine. Persistent state is stored in a single, portable database file (`data/knowledge.db`). Zero external daemons, Docker containers, or background telemetry services are required. +Optional summarization is a separate data-flow boundary. When run, selected document chunks and the prompt are sent to the configured provider. The CLI defaults to Anthropic; --flash selects Google GenAI. The Python Summarizer API also supports Ollama or a custom endpoint. A custom endpoint may be remote, so local storage alone does not guarantee that all data stays on the device. ---- +The desktop GUI and web viewer provide alternate interfaces to the configured database. ## 2. Key Features -- **Local Document Parsing**: Deep text and metadata extraction from PDF (via `pdfplumber`), DOCX (`python-docx`), HTML (`beautifulsoup4`), Markdown, and plain text. -- **Sentence-Bounded Semantic Chunking**: Segments prose into ~350-word passages respecting punctuation and paragraph boundaries, eliminating disjointed mid-sentence cuts for LLM prompts. -- **SQLite FTS5 Full-Text Engine**: Instant BM25-ranked full-text search with trigger-based automatic index synchronization and snippet highlighting. -- **Dual Presentation Interfaces**: - - **Native PySide6 Desktop GUI**: 3-panel split view with directory explorer, sortable document table, and live document preview (including in-app PDF rendering via `pypdfium2`). - - **Stdlib Web Viewer**: Zero-dependency browser interface (`http://localhost:8787`) powered solely by Python's built-in `http.server`. -- **Optional Asynchronous LLM Summarization**: Optional batch processing for document chunks using Gemini Flash (`--flash`) or Anthropic Claude Haiku (`--haiku`), generating structured key takeaways and domain tags. -- **Cryptographic Deduplication**: SHA-256 duplicate detection with non-destructive physical quarantine into a dynamic `_Papierkorb` folder. -- **Zero-Copyleft Permissive Architecture**: Governed by the MIT License with no AGPL/GPL dependencies (Decision E08: `pypdfium2` chosen over PyMuPDF to eliminate copyleft risks). -- **Unprivileged Execution (`RunAsInvoker`)**: Runs strictly within standard user permissions without administrator elevation. - ---- +- **Local document indexing**: Extracts text and metadata from PDF, DOCX, HTML, Markdown, and text files using optional format-specific packages. +- **SQLite FTS5 search**: Stores indexed content in SQLite and ranks full-text results with BM25. +- **Sentence-bounded chunking**: Splits prose into configurable passages for retrieval and optional summarization. +- **Desktop GUI**: PySide6 interface with directory, document, and preview panels. The current desktop interface is German-only. +- **Local web viewer**: Python standard-library HTTP interface bound to loopback by current source; it is not an authentication or remote-hosting boundary. +- **Optional provider calls**: summarize uses Anthropic by default; summarize --flash uses Google GenAI. The Python API also exposes Ollama/custom endpoint configuration. Provider requests include selected document text and prompts. +- **Optional integrations**: BACH import and SQLite Transit synchronization are separate opt-in paths; they are not required for local indexing or search. +- **MIT-licensed project source**: This describes the project’s own source license, not every transitive dependency or binary distribution. ## 3. Architecture & System Topology @@ -76,7 +66,7 @@ flowchart TD CHUNK["Sentence-Bounded Chunking (~350 words)"] DEDUPE["SHA-256 Hash & Deduplication Engine"] FTS["SQLite FTS5 Search Index (BM25)"] - SUMM["Optional LLM Summarizer (Flash / Haiku)"] + SUMM["Optional LLM request (selected chunks + prompt)"] end subgraph Storage["Persistent Local Storage"] @@ -101,6 +91,9 @@ flowchart TD DB --> WEB DB --> CLI DB --> API + PROVIDER["Configured provider (optional, may be remote)"] + SUMM -->|"Request when invoked"| PROVIDER + PROVIDER -->|"Summary response"| SUMM ``` --- @@ -116,7 +109,7 @@ sequenceDiagram participant Core as "Digest Core" participant Ingest as "Ingestor & Chunker" participant DB as "SQLite (FTS5 & Triggers)" - participant LLM as "Optional LLM Summarizer" + participant LLM as "Configured external provider (optional)" Note over User,DB: Phase 1 - Ingestion & Indexing User->>CLI: "Ingest directory (/path/to/docs)" @@ -125,8 +118,9 @@ sequenceDiagram Ingest->>DB: "Store metadata, chunks & keywords" DB-->>DB: "Auto-sync BM25 FTS5 index via triggers" opt "Optional Summarization" - Core->>LLM: "Queue chunks (Gemini Flash / Claude Haiku)" - LLM-->>DB: "Store structured summaries & domain tags" + Core->>LLM: "Send selected chunks + prompt when invoked" + LLM-->>Core: "Return summary" + Core->>DB: "Store summary locally" end Core-->>CLI: "Ingestion complete & indexed" @@ -140,146 +134,76 @@ sequenceDiagram --- -## 5. Target Personas & High-Intent SEO - -KnowledgeDigest is optimized for four primary user groups: +## 5. Typical Uses -| Persona ID & Profile | Primary Use Case & Needs | High-Intent Search Queries | KnowledgeDigest Solution | -|---|---|---|---| -| **`[PERSONA-01]` AI Engineers & Local LLM Developers** | RAG preprocessing, clean text chunking, and local context retrieval for offline agents. | `local RAG document database python`, `sentence bounded text chunker sqlite`, `offline LLM context retrieval` | Sentence-bounded chunking (~350 words), instant FTS5 BM25 retrieval, and optional Gemini Flash / Haiku batch pipelines. | -| **`[PERSONA-02]` Researchers & Knowledge Workers** | Organizing and searching massive personal collections of scientific PDFs, papers, and notes. | `offline pdf full text search python`, `portable knowledge base sqlite`, `pyside6 document search desktop` | In-app PDF rendering via `pypdfium2`, multi-format extraction, fast keyword search, and dark-theme PySide6 desktop GUI. | -| **`[PERSONA-03]` Privacy-Conscious Teams & Compliance Officers** | Searching proprietary contracts, source documentation, and financial reports with zero cloud exposure. | `zero egress document indexing`, `air gapped full text search desktop`, `privacy first document database` | 100% local execution; zero background telemetry; single portable SQLite database; unprivileged `RunAsInvoker` mode. | -| **`[PERSONA-04]` Python Developers & Automation Builders** | Embedding local search into scripts, CLI tools, or existing desktop applications. | `python fts5 document search library`, `file-bricks knowledgedigest`, `lightweight local document search engine` | Zero external database server requirements; clean Python API; rich CLI suite; standalone standard-library Web Viewer. | +| User | Use | +|---|---| +| Researchers and writers | Search local collections of PDFs, Markdown, DOCX, and text files. | +| Python developers | Embed local indexing and FTS5 retrieval through the Python API. | +| AI developers | Prepare local chunks for an optional, explicitly invoked summarization provider. | +| Small teams | Use a local database and choose whether to configure a separate provider or synchronization feature. | ---- +Optional provider and synchronization workflows are not promised to be offline. -## 6. Comprehensive Comparison Matrix - -Architectural comparison against common document search and knowledge management alternatives: - -| Dimension / Invariant | KnowledgeDigest | Cloud SaaS (Notion AI, Glean, NotebookLM) | Heavy Vector DBs (Pinecone, Chroma, Milvus) | OS Desktop Search (Everything, Spotlight) | Ad-hoc Grep / Bash Scripts | -|---|---|---|---|---|---| -| **`INV-LOCAL-01` Local-First & Zero Egress** | ✅ **100% Local SQLite** | ❌ Full Cloud Transmission | ⚠️ Often Cloud / Remote Host | ✅ Local Machine | ✅ Local Machine | -| **`INV-SQLITE-02` SQLite FTS5 Engine** | ✅ **ACID FTS5 + BM25** | ❌ Proprietary Cloud Index | ❌ Vector Embedding Only | ⚠️ Filename / Basic Content | ❌ No Index / Linear Scan | -| **`INV-CHUNK-03` Semantic Chunking** | ✅ **~350 words (Sentence-safe)** | ⚠️ Unspecified Server Logic | ⚠️ Manual Chunking Required | ❌ No Chunking (Whole File) | ❌ Raw Grep Lines | -| **`INV-COPYLEFT-04` Zero-Copyleft MIT** | ✅ **MIT (pypdfium2 / BSD)** | ❌ Proprietary Closed SaaS | ⚠️ Varies (Some AGPL/SSPL) | ❌ Proprietary OS Tooling | ⚠️ Unlicensed Scripts | -| **`INV-RUNAS-05` Unprivileged User Space** | ✅ **`RunAsInvoker` (No root)** | ❌ Cloud Multi-tenant | ⚠️ Requires Docker / Server | ⚠️ Often Needs System Indexer | ✅ User Space | -| **`INV-DUAL-06` Dual Frontends (GUI + Web)** | ✅ **PySide6 + Stdlib Web** | ❌ Web Browser Only | ❌ CLI / API Only | ⚠️ OS Window Only | ❌ Terminal Only | -| **`INV-OPTLLM-07` Optional LLM Boundary** | ✅ **Works 100% Offline** | ❌ LLM is Mandatory | ⚠️ Requires Vector Embedder | ❌ No LLM Features | ❌ No LLM Features | -| **`INV-DEDUPE-08` Cryptographic Deduplication** | ✅ **SHA-256 + `_Papierkorb`** | ❌ Cloud Versioning Only | ❌ None | ⚠️ Duplicate File Checkers | ❌ Manual Shell Pipeline | -| **`INV-DOCS-09` 100% Bilingual Parity** | ✅ **18-Point Dual Anchors** | ⚠️ Partial Localization | ❌ English Only | ⚠️ OS Localization | ❌ None | -| **`INV-SLA-10` 48h Security SLA & § 521 BGB** | ✅ **Guaranteed 48h Response** | ⚠️ Standard Cloud Ticket | ⚠️ Community Forum | ❌ OS Vendor Queue | ❌ None | +## 6. Component Boundaries ---- +| Area | KnowledgeDigest behavior | +|---|---| +| Indexing and search | Local SQLite database and FTS5; no provider is required. | +| Summarization | Optional; sends selected chunks and prompts to the configured provider when invoked. | +| Desktop | PySide6 GUI; current visible strings are German-only. | +| Web viewer | Local HTTP interface; current source binds to loopback and applies request checks to state-changing routes. | +| Synchronization | Optional SQLite Transit integration; data movement depends on configured nodes and is separate from the local core path. | +| Licensing | Project source is MIT-licensed. Dependency and distribution licensing requires checking the resolved packages and included license files. -## 7. Governance & Runtime Invariants - -KnowledgeDigest enforces ten architectural and runtime invariants across all modules: - -| Invariant Code | Category | Principle & Implementation | Verification | -|---|---|---|---| -| **`INV-LOCAL-01`** | Privacy | **Local-First & Zero Egress**: All parsing, indexing, and SQLite operations occur locally. Zero telemetry. | `SECURITY.md`, `tests/test_core.py` | -| **`INV-SQLITE-02`** | Storage | **SQLite FTS5 Full-Text Engine**: Embedded ACID persistence in `data/knowledge.db` with BM25 ranking and triggers. | `KnowledgeDigest/schema.py` | -| **`INV-CHUNK-03`** | NLP | **Sentence-Bounded Semantic Chunking**: Text segmentation into ~350-word chunks without mid-sentence chops. | `KnowledgeDigest/chunker.py` | -| **`INV-COPYLEFT-04`** | Licensing | **Zero-Copyleft Isolation Guarantee**: Permissive MIT distribution. `pypdfium2` chosen over PyMuPDF (`fitz`) per E08. | `tests/test_no_agpl.py` | -| **`INV-RUNAS-05`** | Security | **Unprivileged Execution (`RunAsInvoker`)**: Executes strictly in user space; no administrative elevation needed. | `SECURITY.md` | -| **`INV-DUAL-06`** | Interface | **Dual Frontends**: PySide6 Desktop GUI (3-panel) + Python stdlib zero-dependency Web Viewer (`localhost:8787`). | `KnowledgeDigest/gui/`, `web_viewer.py` | -| **`INV-OPTLLM-07`** | Autonomy | **Optional LLM Boundary**: Search and indexing work completely without LLM; optional Gemini Flash / Haiku queues. | `KnowledgeDigest/summarizer.py` | -| **`INV-DEDUPE-08`** | Integrity | **Cryptographic Deduplication**: SHA-256 document hashing with safe physical quarantine into `_Papierkorb`. | `KnowledgeDigest/digest.py` | -| **`INV-DOCS-09`** | Documentation | **18-Point Bilingual Parity**: Mutual reciprocal anchor alignment between English and German documentation. | `tests/test_metadata.py` | -| **`INV-SLA-10`** | Governance | **Statutory Disclaimer & 48h Security SLA**: § 521 BGB unremunerated gift rules with 48h initial response SLA. | `SECURITY.md`, `README.md` | +## 7. Data-Flow and Runtime Notes ---- +- **Local core path**: File extraction, chunking, SQLite writes, and FTS5 search run against the configured local database. +- **Optional summarization**: The CLI sends selected chunks and a prompt to Anthropic by default or Google GenAI with --flash. The Python API supports Ollama/custom base URLs; these need not be local. +- **Optional synchronization**: SQLite Transit can move configured snapshots between nodes. It is not active in the default local search path. +- **Web viewer**: Current source binds the HTTP server to 127.0.0.1 and checks Host/Origin/Referer for state-changing routes. This is not a substitute for authentication, TLS, or operating-system isolation. +- **User-controlled files**: Users select input directories and database/config paths. Keep the database in a writable location and review selected material before sending it to a provider. +- **Language**: The desktop GUI has no language selector; its visible strings are German. The English and German README share 18 navigation anchor IDs, not full line-by-line translation parity. -## 8. Search & Disambiguation - -KnowledgeDigest is a **local-first portable document knowledge database and FTS5 search engine**. It is intentionally distinct from: +## 8. Scope -- **Cloud Team Wikis & SaaS Workspaces**: We are not Notion, Confluence, or Google Drive. Your data never touches a remote server. -- **Hosted Vector Databases**: We do not require cloud embeddings, vector cluster subscriptions (Pinecone, Weaviate), or GPU infrastructure. -- **Invasive OS Background Indexers**: We do not index your entire operating system, hidden system caches, or system registry in the background. -- **File Converters or DRM Removers**: We extract clean text and structure for indexing and search, not for file format conversion or DRM cracking. +KnowledgeDigest indexes local documents and searches them with FTS5. This path does not require a hosted database or LLM provider. Optional summarization and synchronization are separate workflows and may send data to configured external systems. Check the configured provider, endpoint, selected files, and synchronization targets before using them. -### High-Intent Search Phrases: -``` -KnowledgeDigest file-bricks -portable knowledge database Python -local document search FTS5 SQLite -PySide6 document search desktop app -sentence bounded text chunking python -offline document search tool -zero egress document indexing -sqlite fts5 bm25 full text search -local first ai rag database -``` - ---- +Search phrases: portable document search, SQLite FTS5, local document index, Python knowledge database, optional LLM summarization. ## 9. Desktop GUI -KnowledgeDigest features a native **PySide6** desktop interface with a modern dark theme and a responsive 3-panel layout: - -| Panel | Content & Capabilities | -|---|---| -| **Left Panel** | Indexed directories explorer with document counters and instant directory scanning. | -| **Center Panel** | Document table with sortable columns (filename, type, size, chunk count, index timestamp) and real-time query filter. | -| **Right Panel** | Live document preview supporting raw text, formatted markdown, and native PDF rendering via `pypdfium2`. | +The PySide6 desktop application has a directory panel, document table, and preview. Its current UI strings are German-only and it has no language selector. The installed package includes the application icon; a package-artifact smoke check verifies that it is loadable. -Launch the desktop GUI: -```bash -python -m KnowledgeDigest --gui -``` +Launch: `python -m KnowledgeDigest --gui` ---- +The GUI requires the optional gui dependencies and a desktop display. ## 10. Web Viewer -KnowledgeDigest provides a standalone, zero-dependency browser interface built exclusively with the Python standard library (`http.server`): +The standard-library HTTP viewer exposes local index summaries, document browsing, and FTS5 search. Current source binds to 127.0.0.1; state-changing routes require POST and validate request headers. It uses local HTTP without TLS and is not an authenticated remote service. -- **Dashboard**: Overview of document volume, chunk counts, and indexing health. -- **Browse & Filter**: Document catalog with responsive pagination and category filtering. -- **FTS5 Full-Text Search**: Instant search with snippet highlighting and BM25 relevance ordering. -- **Summary Explorer**: Catalog of optional LLM-generated summaries and domain keywords. -- **Hardened Security**: Enforces HTTP POST for state-changing endpoints, Origin/Referer validation, and strict Host header checks. +Launch: `python -m KnowledgeDigest --web` -Launch the web viewer on `http://localhost:8787`: -```bash -python -m KnowledgeDigest --web -``` - ---- +Use --db to provide a database path. Select a writable path and do not expose the viewer through a reverse proxy without a separate security review. ## 11. Multi-Interface Access & CLI -KnowledgeDigest includes a full command-line suite: - -```bash -# Display database status, document counts, and chunk statistics -python -m KnowledgeDigest status - -# Add a directory to the index -python -m KnowledgeDigest add /path/to/documents - -# Scan and index all registered directories -python -m KnowledgeDigest scan - -# Search across all indexed documents with snippet output -python -m KnowledgeDigest search "machine learning" --limit 10 - -# Scan for cryptographic duplicates and quarantine them -python -m KnowledgeDigest deduplicate --quarantine +The command line supports local indexing and search. Examples: +- `python -m KnowledgeDigest status` +- `python -m KnowledgeDigest add /path/to/documents` +- `python -m KnowledgeDigest scan` +- `python -m KnowledgeDigest search "machine learning" --limit 10` +- `python -m KnowledgeDigest summarize` +- `python -m KnowledgeDigest summarize --flash` -# Run optional LLM summarization on pending chunks -python -m KnowledgeDigest summarize --flash -``` - ---- +The default summarization provider is Anthropic. --flash selects Google GenAI. There is no --haiku option. Running summarize contacts the selected provider and can transmit selected document text. ## 12. Python API @@ -314,36 +238,27 @@ print(f"Total chunks: {status['documents']['total_chunks']}") ## 13. Configuration & Paths -KnowledgeDigest loads configuration from `knowledgedigest.json` using the following fallback order: - -1. Path specified via `--config ` CLI flag -2. Current working directory (`./knowledgedigest.json`) -3. Directory adjacent to the active database file -4. User application data directory: - - Windows: `%APPDATA%\KnowledgeDigest\knowledgedigest.json` - - Linux / macOS: `~/.config/knowledgedigest/knowledgedigest.json` -5. Built-in defaults - -### Key Configuration Settings: -| Setting | Type | Default | Description | -|---|---|---|---| -| `db_path` | `str` | `"data/knowledge.db"` | Relational database location. | -| `indexed_directories` | `list[str]` | `[]` | List of root paths to monitor and index. | -| `chunk_size` | `int` | `350` | Target word count per sentence-bounded chunk. | -| `web_port` | `int` | `8787` | Port for the stdlib Web Viewer. | -| `bach_enabled` | `bool` | `false` | Optional BACH agent system bridge. | +The program searches for knowledgedigest.json in this order: ---- +1. Current working directory. +2. Package data/ directory. +3. %APPDATA%/KnowledgeDigest/ on Windows, when APPDATA is set. +4. $XDG_CONFIG_HOME/knowledgedigest/, or ~/.config/knowledgedigest/. - -## 14. Optional Integrations & Ecosystem +If no file exists, built-in defaults use package data/ paths. An installed package directory may not be writable. Set db_path in the config to a user-writable database location. -- **Ecosystem Umbrella**: KnowledgeDigest is developed under the [`file-bricks`](https://github.com/file-bricks) organization and forms part of the broader [`open-bricks`](https://github.com/open-bricks) open-source software ecosystem. -- **Sister Project [ProFiler](https://github.com/file-bricks/ProFiler)**: For advanced file management, PDF redaction, OCR, and clipboard guarding, see ProFiler (AGPL-3.0). -- **Dataset Seed [WikiStub-Seed](https://github.com/dev-bricks/WikiStub-Seed)**: 630 multilingual stub articles across 12 domains, serving as an ideal corpus for testing KnowledgeDigest indexing pipelines. -- **Optional BACH Agent Bridge**: Can index skills and wiki articles from the [BACH](https://github.com/ellmos-ai/bach) agent framework when `bach_enabled: true`. +There is no --config CLI option. Python callers can explicitly choose a config file with get_config(Path(...)), for example get_config(Path("/path/to/knowledgedigest.json")). ---- +Relevant settings include db_path, indexed_directories, chunk_size, web_port, and bach_enabled. + + +## 14. Optional Integrations & Related Tools + +- **[BACH](https://github.com/ellmos-ai/bach)**: When enabled, its indexers read the configured BACH SQLite database read-only and copy selected skill/wiki content into the KnowledgeDigest database. +- **[SQLite Transit](https://github.com/ellmos-ai/sqlite-transit-sync)**: An optional adapter can synchronize configured snapshots between systems. It is not part of the default local indexing path. +- **[NoteSpaceLLM](https://github.com/file-bricks/NoteSpaceLLM)**: A related local SQLite/plain-text notebook for notes. It is a separate tool; no runtime integration is claimed. +- **[ProFiler](https://github.com/file-bricks/ProFiler)**: A separate file-management and PDF utility in the file-bricks ecosystem; no built-in integration is claimed. +- **Ecosystem**: KnowledgeDigest is hosted by [file-bricks](https://github.com/file-bricks) and is part of the broader [open-bricks](https://github.com/open-bricks) project family. ## 15. Setup & Installation @@ -364,54 +279,24 @@ pip install "knowledgedigest[gui] @ git+https://github.com/file-bricks/knowledge --- -## 16. Testing & Contract Verification +## 16. Testing & Verification -KnowledgeDigest includes a comprehensive automated test suite covering core chunking, SQLite FTS5 persistence, transit synchronization, zero-copyleft guarantees, and metadata contract compliance: +Run the test suite with python -m pytest tests. Optional SQLite Transit tests are skipped when that separately installed dependency is unavailable. The main suite covers indexing/search, web-viewer request checks, metadata contracts, and selected integrations. -```bash -# Run full test suite -pytest - -# Run tests with verbose output -pytest -v - -# Run zero-copyleft and AGPL compliance check -pytest tests/test_no_agpl.py - -# Run PEP 621 metadata, banner, and navigation contract tests -pytest tests/test_metadata.py -``` - ---- +The CI packaging job builds a wheel and source distribution, installs both into separate targets, and checks the packaged icon and CLI help. A passing test run is evidence for those tested paths, not a complete security, license, or dependency audit. -## 17. Level 1 SBOM & Third-Party Licenses - -All direct runtime dependencies are documented in our Level 1 Software Bill of Materials ([`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md)). +## 17. Direct Dependency Notes -- **100% Permissive Open Source**: MIT, Apache-2.0, BSD-3-Clause, PSFL-2.0, LGPL-3.0 (dynamically linked). -- **Zero-Copyleft Isolation**: In accordance with Decision E08 (2026-08-18), `pypdfium2` is utilized for PDF rendering to ensure complete isolation from AGPL copyleft licenses. -- **Canonical Attribution**: See [`NOTICE`](NOTICE) for author and copyright attribution. +[THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md) records a bounded snapshot of declared direct dependencies and license references. It is manually maintained, is not a generated SBOM, and does not enumerate every transitive dependency or installer-specific binary. Check the actual distributions and their included license files before redistributing an environment. ---- +The project source is MIT-licensed; this does not relicense dependencies. -## 18. Legal Disclaimer, § 521 BGB & Security SLA +## 18. Legal and Support Information -### ⚠️ Kein Rechts-, Steuer- oder Anlage-Rat / No Professional Advice -KnowledgeDigest is a **technical software tool** for document indexing and local full-text search. It does not provide professional legal, tax, financial, or compliance advice. Consult qualified professionals for specific advisory needs. +KnowledgeDigest is software, not legal, tax, financial, privacy, or compliance advice. The MIT license is the project’s license; this documentation makes no legal conclusion about liability or the legal role of a particular deployment. -### ⚖️ Haftungsausschluss (§ 521 BGB) / Statutory Disclaimer -Dieses Softwareprojekt wird als **unentgeltliche Open-Source-Schenkung** bereitgestellt. Gemäß **§ 521 BGB** (Gefälligkeitsrecht) ist die Haftung des Urhebers und der Mitwirkenden auf **Vorsatz und grobe Fahrlässigkeit** beschränkt. Ergänzend gelten die Bedingungen der [MIT-Lizenz](LICENSE). - -### 🛡️ Security Response SLA -Security vulnerabilities should be reported confidentially via [GitHub Private Vulnerability Reporting](https://github.com/file-bricks/knowledgedigest/security/advisories/new). -- **Initial Response**: Within **48 hours**. -- **Triage & Evaluation**: Within **5 business days**. -- Details in [`SECURITY.md`](SECURITY.md). - ---- +Security response times are maintainer goals, not a guaranteed service level. Check the repository’s Security tab to see whether GitHub Private Vulnerability Reporting is enabled. If it is unavailable, do not publish vulnerability details in a public issue; ask the maintainers for a private contact route. -### Author & Copyright -Copyright (c) 2026 Lukas Geiger ([github.com/lukisch](https://github.com/lukisch)).
-Part of the [`file-bricks`](https://github.com/file-bricks) organization and the [`open-bricks`](https://github.com/open-bricks) ecosystem. +Copyright (c) 2026 Lukas Geiger. See [LICENSE](LICENSE) and [NOTICE](NOTICE). diff --git a/README_de.md b/README_de.md index 40e1bfd..df2893d 100644 --- a/README_de.md +++ b/README_de.md @@ -7,21 +7,15 @@ [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-blue.svg)](https://www.python.org/) [![Lizenz: MIT](https://img.shields.io/badge/Lizenz-MIT-yellow.svg)](LICENSE) [![Attribution: NOTICE](https://img.shields.io/badge/Attribution-NOTICE-blue.svg)](NOTICE) -[![SBOM: Level 1 Auditiert](https://img.shields.io/badge/SBOM-Level%201%20Auditiert-blue.svg)](THIRD_PARTY_LICENSES.md) [![Version: 0.4.0](https://img.shields.io/badge/Version-0.4.0-informational.svg)](CHANGELOG.md) -[![Tests: 163 Bestanden](https://img.shields.io/badge/Tests-163%20bestanden%20%7C%20100%25%20gr%C3%BCn-brightgreen.svg)](#16-testing-contract-verification) [![Suche: SQLite FTS5](https://img.shields.io/badge/Suche-SQLite%20FTS5%20BM25-green.svg)](#3-architecture) -[![Datenschutz: Zero-Egress](https://img.shields.io/badge/Datenschutz-100%25%20Lokal%20%7C%20Zero--Egress-brightgreen.svg)](#7-governance-invariants) -[![Ausführung: RunAsInvoker](https://img.shields.io/badge/Ausf%C3%BChrung-RunAsInvoker-brightgreen.svg)](SECURITY.md) -[![Sicherheits-SLA: 48h](https://img.shields.io/badge/Sicherheits--SLA-48h%20Antwort-blue.svg)](SECURITY.md) [![GUI: PySide6](https://img.shields.io/badge/GUI-PySide6-41CD52.svg?logo=qt&logoColor=white)](#9-desktop-gui) [![Web: Stdlib](https://img.shields.io/badge/Web-Stdlib%20Zero--Dep-blue.svg)](#10-web-viewer) [![LLM-Ready](https://img.shields.io/badge/LLM-Ready%20%7C%20Opt--in-purple.svg)](#14-optional-integrations-ecosystem) -[![Geprüft: 2026-09-22](https://img.shields.io/badge/Gepr%C3%BCft-2026--09--22-informational.svg)](MARKETING-LOG.txt) [![Organisation: file-bricks](https://img.shields.io/badge/Organisation-file--bricks-purple.svg)](https://github.com/file-bricks) [![Dach: open-bricks](https://img.shields.io/badge/Dach-open--bricks-blue.svg)](https://github.com/open-bricks) -> Portable, in sich geschlossene Wissensdatenbank — indexiert lokale Dokumente, führt satzkonformes semantisches Chunking durch und ermöglicht blitzschnelle SQLite FTS5-Volltextsuche mit BM25-Relevanzranking. Enthält eine native PySide6 Desktop-GUI und einen abhängigkeitsfreien Web-Viewer. +> Ein lokales Python-Werkzeug zur Dokumentenindexierung und SQLite-FTS5-Suche. Bei einer ausdrücklich gestarteten optionalen Zusammenfassung werden ausgewählte Texte an den konfigurierten Anbieter gesendet; solche Anbieteranfragen können das Gerät verlassen. > [!NOTE] > **KI- / LLM-Integration & Maschinenlesbarer Kontext**
@@ -31,34 +25,30 @@ ## 🧭 Schnellnavigation -[1. Übersicht](#1-overview) • [2. Kernfunktionen](#2-key-features) • [3. Architektur](#3-architecture) • [4. Lebenszyklus](#4-lifecycle) • [5. Ziel-Personas](#5-target-personas) • [6. Vergleichsmatrix](#6-comparison-matrix) • [7. Governance-Invarianten](#7-governance-invariants) • [8. Begriffsklärung](#8-search-disambiguation) • [9. Desktop-GUI](#9-desktop-gui) • [10. Web-Viewer](#10-web-viewer) • [11. CLI-Werkzeuge](#11-multi-interface-cli) • [12. Python-API](#12-python-api) • [13. Konfiguration & Pfade](#13-configuration-paths) • [14. Ökosystem & Verwandtes](#14-integrations-ecosystem) • [15. Installation](#15-setup-installation) • [16. Tests & Vertragssicherheit](#16-testing-contract-verification) • [17. Level 1 SBOM](#17-level-1-sbom-third-party-licenses) • [18. Haftungsausschluss & SLA](#18-legal-disclaimer-521-bgb-security-sla) +[1. Übersicht](#1-overview) • [2. Kernfunktionen](#2-key-features) • [3. Architektur](#3-architecture) • [4. Lebenszyklus](#4-lifecycle) • [5. Ziel-Personas](#5-target-personas) • [6. Vergleichsmatrix](#6-comparison-matrix) • [7. Governance-Invarianten](#7-governance-invariants) • [8. Begriffsklärung](#8-search-disambiguation) • [9. Desktop-GUI](#9-desktop-gui) • [10. Web-Viewer](#10-web-viewer) • [11. CLI-Werkzeuge](#11-multi-interface-cli) • [12. Python-API](#12-python-api) • [13. Konfiguration & Pfade](#13-configuration-paths) • [14. Ökosystem & Verwandtes](#14-integrations-ecosystem) • [15. Installation](#15-setup-installation) • [16. Tests & Vertragssicherheit](#16-testing-contract-verification) • [17. Abhängigkeitshinweise](#17-level-1-sbom-third-party-licenses) • [18. Rechtliche Hinweise](#18-legal-disclaimer-521-bgb-security-sla) --- ## 1. Übersicht -**KnowledgeDigest** ist eine lokale, offline-fähige Wissensdatenbank und Dokumenten-Suchmaschine in Python. Sie wandelt unstrukturierte Verzeichnisse mit Dokumenten (PDF, Microsoft Word DOCX, HTML, Markdown und TXT) in eine relationale SQLite-Datenbank um, die mit einem FTS5-Volltextindex und BM25-Relevanzranking ausgestattet ist. +**KnowledgeDigest** indexiert vom Nutzer ausgewählte Dokumente in einer lokalen SQLite-Datenbank und bietet FTS5-Volltextsuche mit BM25-Ranking. Textextraktion, Chunking, Indexierung und normale Suchanfragen nutzen die lokale Datenbank und benötigen keinen LLM-Anbieter. -Im Gegensatz zu Cloud-Wissenssystemen, bei denen vertrauliche Unterlagen an externe Server übertragen werden, arbeitet KnowledgeDigest zu 100 % lokal auf Ihrer Arbeitsstation. Der gesamte Datenbestand wird in einer einzigen portablen SQLite-Datei (`data/knowledge.db`) gespeichert. Es werden weder Hintergrunddienste noch externe Datenbankserver oder Docker-Container benötigt. +Optionale Zusammenfassungen bilden eine eigene Datenflussgrenze. Beim ausdrücklichen Start werden ausgewählte Dokumentabschnitte und der Prompt an den konfigurierten Anbieter gesendet. Die CLI verwendet standardmäßig Anthropic; --flash wählt Google GenAI. Die Python-API Summarizer unterstützt außerdem Ollama oder einen benutzerdefinierten Endpunkt. Ein solcher Endpunkt kann extern liegen. Lokale Speicherung allein garantiert daher nicht, dass alle Daten auf dem Gerät bleiben. ---- +Desktop-GUI und Web-Viewer sind alternative Oberflächen für dieselbe konfigurierte Datenbank. ## 2. Kernfunktionen -- **Lokale Dokumentenextraktion**: Tiefgehende Text- und Metadaten-Extraktion aus PDF (`pdfplumber`), DOCX (`python-docx`), HTML (`beautifulsoup4`), Markdown und reinem Text. -- **Satzkonformes semantisches Chunking**: Unterteilt Texte in ~350 Wörter umfassende Abschnitte entlang natürlicher Satzzeichen und Absätze — verhindert sinnentstellende Schnitte mitten im Satz für LLM-Prompts. -- **SQLite FTS5 Volltextsuche**: Sofortige BM25-gerankte Volltextsuche mit Trigger-basiertem automatischem Indexabgleich und Snippet-Hervorhebung. -- **Zwei Bedienoberflächen**: - - **Native PySide6 Desktop-GUI**: 3-Spalten-Layout mit Verzeichnis-Explorer, sortierbarer Dokumententabelle und integrierter Dokumentenvorschau (inkl. nativer PDF-Anzeige via `pypdfium2`). - - **Stdlib Web-Viewer**: Abhängigkeitsfreie Browser-Oberfläche (`http://localhost:8787`), betrieben rein über das Python-Standardmodul `http.server`. -- **Optionale asynchrone LLM-Zusammenfassungen**: Optionale Batch-Verarbeitung für Chunks mittels Gemini Flash (`--flash`) oder Anthropic Claude Haiku (`--haiku`) zur Erzeugung strukturierter Kernaussagen und Tags. -- **Kryptografische Deduplizierung**: SHA-256 Hash-Erkennung von Duplikaten mit zerstörungsfreier physischer Quarantäne in einen dynamischen `_Papierkorb`-Ordner. -- **Permissive Zero-Copyleft-Architektur**: Unter der MIT-Lizenz stehend, frei von AGPL/GPL-Viren (Entscheidung E08: `pypdfium2` gewählt anstelle von PyMuPDF). -- **Nicht-privilegierte Ausführung (`RunAsInvoker`)**: Läuft vollständig im Standard-Benutzerkontext ohne Administratorrechte. - ---- +- **Lokale Dokumentenindexierung**: Extrahiert Text und Metadaten aus PDF, DOCX, HTML, Markdown und Textdateien; dafür werden optionale Formatpakete verwendet. +- **SQLite-FTS5-Suche**: Speichert indexierte Inhalte in SQLite und ordnet Volltexttreffer mit BM25. +- **Satzbezogenes Chunking**: Teilt Fließtext in einstellbare Abschnitte für Suche und optionale Zusammenfassungen. +- **Desktop-GUI**: PySide6-Oberfläche mit Verzeichnis-, Dokumenten- und Vorschau-Spalte. Die aktuelle Desktop-Oberfläche ist nur auf Deutsch verfügbar. +- **Lokaler Web-Viewer**: HTTP-Oberfläche aus der Python-Standardbibliothek, die laut aktueller Implementierung an Loopback gebunden ist; sie ist keine Authentifizierungs- oder Remote-Hosting-Grenze. +- **Optionale Anbieteranfragen**: summarize nutzt standardmäßig Anthropic; summarize --flash nutzt Google GenAI. Die Python-API bietet außerdem Ollama und benutzerdefinierte Endpunkte. Anbieteranfragen enthalten ausgewählte Dokumenttexte und Prompts. +- **Optionale Integrationen**: BACH-Import und SQLite-Transit-Synchronisierung sind getrennte, optionale Pfade. Sie werden für lokale Indexierung und Suche nicht benötigt. +- **MIT-Lizenz für den Projektquelltext**: Das beschreibt die Lizenz des eigenen Quelltexts, nicht sämtliche indirekten Abhängigkeiten oder Binärpakete. ## 3. Architektur & Systemtopologie @@ -76,7 +66,7 @@ flowchart TD CHUNK["Satzkonformes Chunking (~350 Wörter)"] DEDUPE["SHA-256 Hash & Deduplizierung"] FTS["SQLite FTS5 Volltextindex (BM25)"] - SUMM["Optionale LLM-Zusammenfassung (Flash / Haiku)"] + SUMM["Optionale LLM-Anfrage (ausgewählte Chunks + Prompt)"] end subgraph Storage["Lokaler Speicher"] @@ -101,6 +91,9 @@ flowchart TD DB --> WEB DB --> CLI DB --> API + PROVIDER["Konfigurierter Anbieter (optional, eventuell extern)"] + SUMM -->|"Anfrage bei Aufruf"| PROVIDER + PROVIDER -->|"Zusammenfassung"| SUMM ``` --- @@ -116,7 +109,7 @@ sequenceDiagram participant Core as "Digest Core" participant Ingest as "Ingestor & Chunker" participant DB as "SQLite (FTS5 & Triggers)" - participant LLM as "Optionale LLM-Zusammenfassung" + participant LLM as "Konfigurierter externer Anbieter (optional)" Note over User,DB: Phase 1 - Ingestion & Indexierung User->>CLI: "Verzeichnis indexieren (/pfad/zu/docs)" @@ -125,8 +118,9 @@ sequenceDiagram Ingest->>DB: "Metadaten, Chunks & Keywords speichern" DB-->>DB: "Auto-Sync des BM25 FTS5-Index via Trigger" opt "Optionale Zusammenfassung" - Core->>LLM: "Chunks in Warteschlange (Gemini Flash / Haiku)" - LLM-->>DB: "Strukturierte Summaries & Tags ablegen" + Core->>LLM: "Ausgewählte Chunks + Prompt beim Aufruf senden" + LLM-->>Core: "Zusammenfassung zurückgeben" + Core->>DB: "Zusammenfassung lokal speichern" end Core-->>CLI: "Indexierung erfolgreich abgeschlossen" @@ -140,145 +134,76 @@ sequenceDiagram --- -## 5. Ziel-Personas & Suchintention - -KnowledgeDigest richtet sich an vier zentrale Zielgruppen: +## 5. Typische Anwendungsfälle -| Persona-ID & Profil | Primärer Einsatzzweck & Bedarf | Suchphrasen (High-Intent) | KnowledgeDigest Lösung | -|---|---|---|---| -| **`[PERSONA-01]` KI-Ingenieure & Lokale LLM-Entwickler** | RAG-Vorverarbeitung, sauberes Satz-Chunking und lokale Kontextabfragen für autonome Agenten. | `local RAG document database python`, `sentence bounded text chunker sqlite`, `offline LLM context retrieval` | Satzkonformes Chunking (~350 Wörter), sofortiger FTS5 BM25-Index und optionale Gemini Flash / Haiku Pipelines. | -| **`[PERSONA-02]` Wissenschaftler & Wissensarbeiter** | Verwaltung und Recherche in umfangreichen Sammlungen von Fach-PDFs, Aufsätzen und Notizen. | `offline pdf full text search python`, `portable knowledge base sqlite`, `pyside6 document search desktop` | Integrierte PDF-Vorschau via `pypdfium2`, Unterstützung gängiger Formate, präzise Suche und Desktop-GUI mit Dark-Theme. | -| **`[PERSONA-03]` Datenschutzbeauftragte & Compliance-Teams** | Durchsuchung vertraulicher Verträge und Berichte bei vollständigem Verzicht auf Cloud-Dienste. | `zero egress document indexing`, `air gapped full text search desktop`, `privacy first document database` | 100 % lokale Ausführung; null Telemetrie; portable SQLite-Datei; unprivilegierter `RunAsInvoker`-Betrieb. | -| **`[PERSONA-04]` Python-Entwickler & Automatisierer** | Einbettung lokaler Dokumentensuche in Skripte, Desktop-Apps oder bestehende Workflows. | `python fts5 document search library`, `file-bricks knowledgedigest`, `lightweight local document search engine` | Keine externen DB-Server nötig; schlanke Python-API; vollständige CLI; standardmäßiger Web-Viewer. | +| Nutzergruppe | Einsatz | +|---|---| +| Forschende und Schreibende | Lokale Sammlungen aus PDF-, Markdown-, DOCX- und Textdateien durchsuchen. | +| Python-Entwickler | Lokale Indexierung und FTS5-Abfragen über die Python-API einbinden. | +| KI-Entwickler | Lokale Textabschnitte für eine optionale, ausdrücklich gestartete Zusammenfassung vorbereiten. | +| Kleine Teams | Eine lokale Datenbank nutzen und einen separaten Anbieter oder eine Synchronisierungsfunktion bewusst konfigurieren. | ---- +Für optionale Anbieter- oder Synchronisierungsabläufe wird kein Offline-Betrieb zugesagt. -## 6. Umfassende Vergleichsmatrix - -Architektonischer Vergleich mit etablierten Dokumenten- und Wissensmanagement-Ansätzen: - -| Kriterium / Invariante | KnowledgeDigest | Cloud-SaaS (Notion AI, Glean, NotebookLM) | Schwere Vektor-DBs (Pinecone, Chroma, Milvus) | OS-Desktopsuche (Everything, Spotlight) | Ad-hoc Grep / Bash-Skripte | -|---|---|---|---|---|---| -| **`INV-LOCAL-01` Local-First & Zero Egress** | ✅ **100% Lokale SQLite** | ❌ Vollständige Cloud-Übertragung | ⚠️ Oft Cloud-/Remote-Dienst | ✅ Lokale Arbeitsstation | ✅ Lokale Arbeitsstation | -| **`INV-SQLITE-02` SQLite FTS5 Volltext** | ✅ **ACID FTS5 + BM25** | ❌ Proprietärer Cloud-Index | ❌ Nur Vektor-Embeddings | ⚠️ Dateinamen / Basis-Inhalt | ❌ Kein Index / Linearer Scan | -| **`INV-CHUNK-03` Satzkonformes Chunking** | ✅ **~350 Wörter (Satzgrenzen)** | ⚠️ Intransparente Server-Logik | ⚠️ Manuelles Chunking nötig | ❌ Keine Chunks (Ganze Datei) | ❌ Rohe Zeilentreffer | -| **`INV-COPYLEFT-04` Zero-Copyleft MIT** | ✅ **MIT (pypdfium2 / BSD)** | ❌ Proprietäre geschlossene SaaS | ⚠️ Teils AGPL / SSPL Lizenzen | ❌ Proprietäre OS-Werkzeuge | ⚠️ Nicht lizenziert | -| **`INV-RUNAS-05` Unprivilegierter Betrieb** | ✅ **`RunAsInvoker` (Kein Root)** | ❌ Multi-Tenant Cloud | ⚠️ Benötigt Server / Docker | ⚠️ Oft System-Indexdienst | ✅ Benutzerkontext | -| **`INV-DUAL-06` Zwei Oberflächen (GUI + Web)** | ✅ **PySide6 + Stdlib Web** | ❌ Nur Webbrowser | ❌ Nur CLI / API | ⚠️ Nur Betriebssystem-Fenster | ❌ Nur Terminal | -| **`INV-OPTLLM-07` Optionale LLM-Grenze** | ✅ **Funktioniert 100% Offline** | ❌ LLM zwingend erforderlich | ⚠️ Benötigt Vektor-Modelle | ❌ Keine LLM-Funktionen | ❌ Keine LLM-Funktionen | -| **`INV-DEDUPE-08` Deduplizierung** | ✅ **SHA-256 + `_Papierkorb`** | ❌ Nur Cloud-Versionierung | ❌ Keine | ⚠️ Nur Dateinamenduplikate | ❌ Manuelle Skript-Pipeline | -| **`INV-DOCS-09` 100% Zweisprachige Parität** | ✅ **18-Punkte-Dual-Anker** | ⚠️ Teils lückenhafte Übersetzung | ❌ Nur Englisch | ⚠️ Nach Systemsprache | ❌ Keine | -| **`INV-SLA-10` 48h SLA & § 521 BGB** | ✅ **Garantierte 48h Antwort** | ⚠️ Standard Cloud-Ticket | ⚠️ Nur Community-Foren | ❌ Nur OS-Supportkanäle | ❌ Keine | +## 6. Komponenten und Grenzen ---- +| Bereich | Verhalten von KnowledgeDigest | +|---|---| +| Indexierung und Suche | Lokale SQLite-Datenbank und FTS5; kein Anbieter erforderlich. | +| Zusammenfassungen | Optional; beim Aufruf werden ausgewählte Textabschnitte und Prompts an den konfigurierten Anbieter gesendet. | +| Desktop | PySide6-GUI; die aktuellen sichtbaren Texte sind nur auf Deutsch verfügbar. | +| Web-Viewer | Lokale HTTP-Oberfläche; der aktuelle Quelltext bindet an Loopback und prüft schreibende Anfragen. | +| Synchronisierung | Optionale SQLite-Transit-Integration; Datenbewegung hängt von den konfigurierten Knoten ab und ist vom lokalen Kernpfad getrennt. | +| Lizenzierung | Der Projektquelltext steht unter MIT. Abhängigkeiten und Distributionen müssen anhand der tatsächlich aufgelösten Pakete und enthaltenen Lizenzdateien geprüft werden. -## 7. Governance- & Laufzeit-Invarianten - -KnowledgeDigest garantiert die Einhaltung von zehn architektonischen Invarianten: - -| Invariante | Kategorie | Prinzip & Technische Umsetzung | Verifikation | -|---|---|---|---| -| **`INV-LOCAL-01`** | Datenschutz | **Local-First & Zero Egress**: Sämtliche Parsings, Indexierungen und Suchanfragen laufen lokal ab. Null Telemetrie. | `SECURITY.md`, `tests/test_core.py` | -| **`INV-SQLITE-02`** | Datenbank | **SQLite FTS5 Volltext-Engine**: Robuste Persistenz in `data/knowledge.db` mit BM25-Ranking und Triggern. | `KnowledgeDigest/schema.py` | -| **`INV-CHUNK-03`** | NLP | **Satzkonformes semantisches Chunking**: Segmentierung in ~350 Wörter ohne Zerschneiden von Sätzen. | `KnowledgeDigest/chunker.py` | -| **`INV-COPYLEFT-04`** | Lizenzierung | **Zero-Copyleft-Garantie**: Freie MIT-Lizenz. `pypdfium2` anstelle von PyMuPDF (`fitz`) gemäß Beschluss E08. | `tests/test_no_agpl.py` | -| **`INV-RUNAS-05`** | Sicherheit | **Unprivilegierter Modus (`RunAsInvoker`)**: Arbeitet ausschließlich mit gewöhnlichen Benutzerrechten. | `SECURITY.md` | -| **`INV-DUAL-06`** | Schnittstelle | **Zwei Oberflächen**: PySide6 Desktop-GUI + Python-Stdlib Web-Viewer (`localhost:8787`). | `KnowledgeDigest/gui/`, `web_viewer.py` | -| **`INV-OPTLLM-07`** | Autonomie | **Optionale LLM-Grenze**: Vollständig offline nutzbar; optionale Gemini Flash / Haiku Queues. | `KnowledgeDigest/summarizer.py` | -| **`INV-DEDUPE-08`** | Datenintegrität | **Kryptografische Deduplizierung**: SHA-256 Hashprüfung mit sicherer `_Papierkorb`-Quarantäne. | `KnowledgeDigest/digest.py` | -| **`INV-DOCS-09`** | Dokumentation | **18-Punkte-Parität**: Identische Struktur und gegenseitige Ankerverweise zwischen Deutsch und Englisch. | `tests/test_metadata.py` | -| **`INV-SLA-10`** | Governance | **Haftungsausschluss & 48h-SLA**: Schenkungsrecht nach § 521 BGB mit garantierter 48-Stunden-Sicherheitsreaktion. | `SECURITY.md`, `README_de.md` | +## 7. Datenfluss und Laufzeit ---- +- **Lokaler Kernpfad**: Textextraktion, Chunking, SQLite-Schreibvorgänge und FTS5-Suche verwenden die konfigurierte lokale Datenbank. +- **Optionale Zusammenfassungen**: Die CLI sendet ausgewählte Textabschnitte und einen Prompt standardmäßig an Anthropic oder mit --flash an Google GenAI. Die Python-API unterstützt Ollama und benutzerdefinierte Basis-URLs; diese müssen nicht lokal sein. +- **Optionale Synchronisierung**: SQLite Transit kann konfigurierte Snapshots zwischen Knoten übertragen. Im standardmäßigen lokalen Suchpfad ist diese Funktion nicht aktiv. +- **Web-Viewer**: Der aktuelle Quelltext bindet den HTTP-Server an 127.0.0.1 und prüft Host/Origin/Referer für schreibende Routen. Das ersetzt weder Authentifizierung noch TLS oder Betriebssystem-Isolation. +- **Dateien unter Nutzerkontrolle**: Nutzer wählen Eingabeverzeichnisse und Datenbank-/Konfigurationspfade. Die Datenbank muss an einem beschreibbaren Ort liegen; vor einer Anbieteranfrage sollten die ausgewählten Inhalte geprüft werden. +- **Sprache**: Die Desktop-GUI hat keinen Sprachumschalter; ihre Oberflächentexte sind deutsch. Die englische und deutsche README teilen 18 Anker-IDs, keine vollständige zeilenweise Übersetzungsparität. -## 8. Begriffsklärung & Abgrenzung - -KnowledgeDigest ist eine **lokale, portable Wissensdatenbank und FTS5-Volltextsitzung**. Es grenzt sich klar ab von: +## 8. Umfang -- **Cloud-Team-Wikis**: Wir sind kein Notion, Confluence oder Google Workspace. Daten verlassen niemals Ihre Festplatte. -- **Gehostete Vektordatenbanken**: Wir erfordern keine Vektoreinbettungen, kein Cloud-Abo (Pinecone etc.) und keine GPU-Cluster. -- **Invasive OS-Hintergrund-Indexer**: Wir indexieren keine Systemverzeichnisse oder Registry-Schlüssel im Hintergrund. -- **Format-Konverter oder DRM-Entferner**: Der Fokus liegt rein auf Text- und Metadatenextraktion für Durchsuchbarkeit. - -### Relevante Suchphrasen: -``` -KnowledgeDigest file-bricks -portable Wissensdatenbank Python -lokale Dokumentensuche FTS5 SQLite -PySide6 Dokumentensuche Desktop App -satzkonformes Text Chunking Python -offline Dokumentensuche Werkzeug -Datenschutz Dokumentenindexierung -sqlite fts5 bm25 volltextsuche -``` +KnowledgeDigest indexiert lokale Dokumente und durchsucht sie mit FTS5. Dieser Pfad benötigt weder eine gehostete Datenbank noch einen LLM-Anbieter. Optionale Zusammenfassungen und Synchronisierung sind getrennte Abläufe und können Daten an konfigurierte externe Systeme senden. Prüfen Sie vor deren Nutzung Anbieter, Endpunkt, ausgewählte Dateien und Synchronisierungsziele. ---- +Suchbegriffe: lokale Dokumentensuche, SQLite FTS5, Python-Wissensdatenbank, Dokumentenindex, optionale LLM-Zusammenfassung. ## 9. Desktop-GUI -KnowledgeDigest verfügt über eine moderne, native **PySide6** Desktop-Oberfläche mit dunklem Farbschema und 3-Spalten-Layout: +Die PySide6-Desktopanwendung hat eine Verzeichnisleiste, eine Dokumententabelle und eine Vorschau. Ihre aktuellen Oberflächentexte sind deutsch; einen Sprachumschalter gibt es nicht. Das installierte Paket enthält das Anwendungssymbol; ein Paket-Smoke-Check prüft, ob es geladen werden kann. -| Spalte | Inhalte & Funktionen | -|---|---| -| **Linke Spalte** | Verzeichnis-Explorer mit Anzeige der indexierten Dokumente und Sofort-Scan-Schaltfläche. | -| **Mittlere Spalte** | Dokumententabelle mit sortierbaren Spalten (Dateiname, Format, Größe, Chunks, Indexdatum) und Schnellfilter. | -| **Rechte Spalte** | Dokumentenvorschau mit Unterstützung für Text, Markdown und nativer PDF-Darstellung via `pypdfium2`. | +Start: `python -m KnowledgeDigest --gui` -Desktop-GUI starten: -```bash -python -m KnowledgeDigest --gui -``` - ---- +Die GUI benötigt die optionale Gruppe gui und eine grafische Anzeige. ## 10. Web-Viewer -KnowledgeDigest bietet eine leichtgewichtige Browser-Oberfläche, die ausschließlich auf der Python-Standardbibliothek basiert (`http.server`): +Der HTTP-Viewer aus der Standardbibliothek zeigt lokale Indexdaten, Dokumente und FTS5-Suchergebnisse. Der aktuelle Quelltext bindet an 127.0.0.1; schreibende Routen verlangen POST und prüfen Request-Header. Er verwendet lokales HTTP ohne TLS und ist kein authentifizierter Remote-Dienst. -- **Dashboard**: Statistiken über Dokumente, Chunks und Indexierungsfortschritt. -- **Dokumentenübersicht**: Übersicht aller Dateien mit Paginierung und Verzeichnisfilter. -- **FTS5-Volltextsuche**: Schnelle Suche mit BM25-Relevanz und hervorgehobenen Textabschnitten. -- **Zusammenfassungen**: Katalog der optionalen LLM-Zusammenfassungen und Fachbegriffe. -- **Gehärtete Sicherheit**: POST-Zwang für schreibende Endpunkte, Origin-/Referer-Prüfung und Host-Header-Validierung. +Start: `python -m KnowledgeDigest --web` -Web-Viewer starten (`http://localhost:8787`): -```bash -python -m KnowledgeDigest --web -``` - ---- +Mit --db lässt sich ein Datenbankpfad angeben. Verwenden Sie einen beschreibbaren Speicherort und stellen Sie den Viewer nicht ohne zusätzliche Sicherheitsprüfung über einen Reverse-Proxy bereit. -## 11. Multi-Interface Zugriff & CLI - -KnowledgeDigest bringt ein vollständiges Kommandozeilen-Interface mit: - -```bash -# Status der Datenbank, Dokumentenzahl und Chunks anzeigen -python -m KnowledgeDigest status +## 11. CLI und Oberflächen -# Neues Verzeichnis zum Index hinzufügen -python -m KnowledgeDigest add /pfad/zu/dokumenten +Die CLI unterstützt lokale Indexierung und Suche, zum Beispiel: +- `python -m KnowledgeDigest status` +- `python -m KnowledgeDigest add /pfad/zu/dokumenten` +- `python -m KnowledgeDigest scan` +- `python -m KnowledgeDigest search "maschinelles Lernen" --limit 10` +- `python -m KnowledgeDigest summarize` +- `python -m KnowledgeDigest summarize --flash` -# Alle registrierten Verzeichnisse scannen und neu indexieren -python -m KnowledgeDigest scan - -# Volltextsuche über alle Dokumente durchführen -python -m KnowledgeDigest search "maschinelles lernen" --limit 10 - -# Nach kryptografischen Duplikaten suchen und in Quarantäne verschieben -python -m KnowledgeDigest deduplicate --quarantine - -# Optionale LLM-Zusammenfassung für offene Chunks starten -python -m KnowledgeDigest summarize --flash -``` - ---- +Der Standardanbieter für Zusammenfassungen ist Anthropic. --flash wählt Google GenAI. Eine Option --haiku gibt es nicht. summarize kontaktiert den ausgewählten Anbieter und kann ausgewählte Dokumenttexte übertragen. ## 12. Python-API @@ -311,38 +236,29 @@ print(f"Chunks: {status['documents']['total_chunks']}") --- -## 13. Konfiguration & Pfade - -Die Konfiguration erfolgt über die JSON-Datei `knowledgedigest.json`. Suchreihenfolge: - -1. CLI-Parameter `--config ` -2. Aktuelles Arbeitsverzeichnis (`./knowledgedigest.json`) -3. Neben der aktiven Datenbankdatei -4. Benutzerbezogener Konfigurationsordner: - - Windows: `%APPDATA%\KnowledgeDigest\knowledgedigest.json` - - Linux / macOS: `~/.config/knowledgedigest/knowledgedigest.json` -5. Eingebaute Standardwerte - -### Wichtige Einstellungen: -| Parameter | Typ | Standardwert | Beschreibung | -|---|---|---|---| -| `db_path` | `str` | `"data/knowledge.db"` | Speicherort der SQLite-Datenbank. | -| `indexed_directories` | `list[str]` | `[]` | Liste der überwachten Ordner. | -| `chunk_size` | `int` | `350` | Zielgröße in Wörtern pro Textsegment. | -| `web_port` | `int` | `8787` | Port für den Web-Viewer. | -| `bach_enabled` | `bool` | `false` | Optionale Anbindung an das BACH-Framework. | +## 13. Konfiguration und Pfade ---- +Das Programm sucht knowledgedigest.json in dieser Reihenfolge: - -## 14. Optionale Integrationen & Ökosystem +1. Aktuelles Arbeitsverzeichnis. +2. Paketverzeichnis data/. +3. Unter Windows APPDATA/KnowledgeDigest/, sofern APPDATA gesetzt ist. +4. XDG_CONFIG_HOME/knowledgedigest/ oder ~/.config/knowledgedigest/. -- **Ökosystem**: KnowledgeDigest wird von der Organisation [`file-bricks`](https://github.com/file-bricks) betreut und ist Teil des übergeordneten [`open-bricks`](https://github.com/open-bricks) Open-Source-Verbunds. -- **Schwesterprojekt [ProFiler](https://github.com/file-bricks/ProFiler)**: Für erweiterte Dateiverwaltung, PDF-Schwärzung, OCR und Zwischenablageschutz siehe ProFiler (AGPL-3.0). -- **Test-Korpus [WikiStub-Seed](https://github.com/dev-bricks/WikiStub-Seed)**: 630 mehrsprachige Kurzeinträge aus 12 Fachbereichen als strukturierter Test-Datensatz für Ingestion-Pipelines. -- **Optionale BACH-Brücke**: Bei aktiviertem `bach_enabled: true` können Skills und Wissensartikel aus dem [BACH](https://github.com/ellmos-ai/bach) Agenten-Framework mitindexiert werden. +Existiert keine Datei, verwendet das Programm eingebaute Standardwerte und Paketpfade unter data/. Ein installiertes Paketverzeichnis muss nicht beschreibbar sein. Setzen Sie db_path in der Konfiguration auf einen für Sie beschreibbaren Datenbankpfad. ---- +Eine CLI-Option --config gibt es nicht. Python-Aufrufer können eine Konfigurationsdatei ausdrücklich über get_config(Path(...)) auswählen, zum Beispiel get_config(Path("/pfad/zu/knowledgedigest.json")). + +Wichtige Einstellungen sind db_path, indexed_directories, chunk_size, web_port und bach_enabled. + + +## 14. Optionale Integrationen und verwandte Werkzeuge + +- **[BACH](https://github.com/ellmos-ai/bach)**: Wenn aktiviert, lesen die BACH-Indexer die konfigurierte BACH-SQLite-Datenbank schreibgeschützt und übernehmen ausgewählte Skill-/Wiki-Inhalte in die KnowledgeDigest-Datenbank. +- **[SQLite Transit](https://github.com/ellmos-ai/sqlite-transit-sync)**: Ein optionaler Adapter kann konfigurierte Snapshots zwischen Systemen synchronisieren. Er gehört nicht zum standardmäßigen lokalen Indexierungspfad. +- **[NoteSpaceLLM](https://github.com/file-bricks/NoteSpaceLLM)**: Ein verwandtes lokales SQLite-/Textnotizbuch. Es ist ein eigenes Werkzeug; eine Laufzeitintegration wird nicht behauptet. +- **[ProFiler](https://github.com/file-bricks/ProFiler)**: Ein separates Datei- und PDF-Werkzeug im file-bricks-Ökosystem; eine integrierte Verbindung wird nicht behauptet. +- **Ökosystem**: KnowledgeDigest wird von [file-bricks](https://github.com/file-bricks) gehostet und gehört zur Projektfamilie [open-bricks](https://github.com/open-bricks). ## 15. Setup & Installation @@ -363,54 +279,24 @@ pip install "knowledgedigest[gui] @ git+https://github.com/file-bricks/knowledge --- -## 16. Tests & Vertragssicherheit +## 16. Tests und Verifikation -KnowledgeDigest enthält eine umfassende Test-Suite für Chunking-Integrität, SQLite FTS5-Persistenz, Transit-Synchronisation, Zero-Copyleft-Schutz und PEP-621-Vertragstests: +Führen Sie die Tests mit python -m pytest tests aus. Optionale SQLite-Transit-Tests werden übersprungen, wenn die separat installierte Abhängigkeit fehlt. Die Hauptsuite prüft Indexierung und Suche, Request-Prüfungen des Web-Viewers, Metadatenverträge und ausgewählte Integrationen. -```bash -# Komplette Test-Suite ausführen -pytest - -# Detaillierte Testausgabe -pytest -v - -# Lizenz- und Copyleft-Vertragstest ausführen -pytest tests/test_no_agpl.py - -# Metadaten- und Dokumentationsverträge prüfen -pytest tests/test_metadata.py -``` - ---- +Der CI-Paketjob baut außerdem ein Wheel und eine Source-Distribution, installiert beide in getrennte Zielverzeichnisse und prüft das enthaltene Symbol sowie die CLI-Hilfe. Ein erfolgreicher Testlauf belegt nur die geprüften Pfade, keine vollständige Sicherheits-, Lizenz- oder Abhängigkeitsprüfung. -## 17. Level 1 SBOM & Drittanbieter-Lizenzen - -Alle direkten Laufzeit-Abhängigkeiten sind im Level 1 Software Bill of Materials ([`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md)) erfasst. +## 17. Hinweise zu direkten Abhängigkeiten -- **100 % Freie Open-Source-Lizenzen**: MIT, Apache-2.0, BSD-3-Clause, PSFL-2.0, LGPL-3.0 (dynamisch eingebunden). -- **Keine Copyleft-Kontamination**: Gemäß Entscheidung E08 (2026-08-18) wird für PDF-Vorschauen `pypdfium2` eingesetzt, um AGPL-Risiken auszuschließen. -- **Kanonische Urheber-Angaben**: Siehe [`NOTICE`](NOTICE) für Autoren und Copyright. +[THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md) enthält eine begrenzte, manuell gepflegte Momentaufnahme deklarierter direkter Abhängigkeiten und Lizenzverweise. Sie ist keine generierte SBOM und listet nicht jede indirekte Abhängigkeit oder jede distributionsspezifische Binärdatei auf. Prüfen Sie vor einer Weitergabe die tatsächlich installierten Pakete und deren Lizenzdateien. ---- +Der Projektquelltext steht unter MIT. Das ändert nicht die Lizenzen seiner Abhängigkeiten. -## 18. Haftungsausschluss, § 521 BGB & Sicherheits-SLA +## 18. Rechtliche Hinweise und Support -### ⚠️ Kein Rechts-, Steuer- oder Anlage-Rat -KnowledgeDigest ist ein **technisches Werkzeug** zur Dokumentenindexierung und Volltextsuche. Es stellt keine Rechts-, Steuer- oder Finanzberatung dar. Bei entsprechenden Fachfragen ziehen Sie bitte qualifizierte Experten heran. +KnowledgeDigest ist Software und keine Rechts-, Steuer-, Finanz-, Datenschutz- oder Compliance-Beratung. Die MIT-Lizenz ist die Projektlizenz; diese Dokumentation trifft keine rechtliche Aussage zur Haftung oder zur rechtlichen Rolle einer konkreten Nutzung. -### ⚖️ Gesetzlicher Haftungsausschluss (§ 521 BGB) -Dieses Projekt ist eine **unentgeltliche Open-Source-Schenkung** im Sinne der §§ 516 ff. BGB. Die Haftung des Urhebers ist gemäß **§ 521 BGB** (Gefälligkeitsrecht) auf **Vorsatz und grobe Fahrlässigkeit** beschränkt. Ergänzend gelten die Haftungsausschlüsse der [MIT-Lizenz](LICENSE). - -### 🛡️ Sicherheits-Reaktionszeiten (SLA) -Sicherheitsrelevante Schwachstellen melden Sie bitte vertraulich über [GitHub Private Vulnerability Reporting](https://github.com/file-bricks/knowledgedigest/security/advisories/new). -- **Erste Rückmeldung**: Innerhalb von **48 Stunden**. -- **Evaluierung & Einstufung**: Innerhalb von **5 Werktagen**. -- Weitere Details in [`SECURITY.md`](SECURITY.md). - ---- +Reaktionszeiten bei Sicherheitsmeldungen sind Ziele der Maintainer, keine garantierte Serviceleistung. Prüfen Sie im Security-Tab des Repositories, ob GitHub Private Vulnerability Reporting aktuell aktiviert ist. Falls es nicht verfügbar ist, veröffentlichen Sie keine Schwachstellendetails in einem öffentlichen Issue, sondern bitten Sie die Maintainer um einen privaten Kontaktweg. -### Urheber & Copyright -Copyright (c) 2026 Lukas Geiger ([github.com/lukisch](https://github.com/lukisch)).
-Teil der Organisation [`file-bricks`](https://github.com/file-bricks) und des [`open-bricks`](https://github.com/open-bricks) Ökosystems. +Copyright (c) 2026 Lukas Geiger. Siehe [LICENSE](LICENSE) und [NOTICE](NOTICE). diff --git a/SECURITY.md b/SECURITY.md index eab5ded..9f08280 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,38 +2,24 @@ ## Supported Versions -| Version | Supported | -| --- | --- | -| 0.4.x | :white_check_mark: Active security support | -| < 0.4.0 | :x: End of life (please upgrade) | +| Version | Status | +|---|---| +| 0.4.x | Current maintenance line | -## Security Invariants & Architecture +## Scope and Runtime Notes -KnowledgeDigest is engineered around local-first data integrity: +Document extraction, chunking, indexing, and FTS5 search operate on the configured local SQLite database. Optional summarization is a separate network boundary: the CLI defaults to Anthropic, --flash selects Google GenAI, and the Python API supports Ollama or a custom endpoint. Selected document text and prompts are sent to the configured provider when summarization is invoked. Custom endpoints may be remote. -1. **Zero Egress by Default**: All document parsing, text chunking, and SQLite FTS5 search indexing occur 100% locally on your machine. No telemetry, usage statistics, or automated background telemetry calls are ever made. -2. **Explicit LLM Boundary**: External network calls only happen when the user explicitly configures and invokes LLM summarization (`--flash` via Google GenAI or `--haiku` via Anthropic). -3. **Web Viewer Hardening**: - - State-changing endpoints (`/open/`, `/api/reset_doc/`, `/api/delete_file/`) strictly enforce HTTP POST (HTTP 405 on GET). - - Host header validation mitigates DNS rebinding attacks. - - Origin / Referer checks protect against Cross-Site Request Forgery (CSRF). - - Search snippet outputs are escaped prior to `` tag injection to prevent stored XSS. -4. **Unprivileged Execution**: KnowledgeDigest runs as a standard user process (`RunAsInvoker`) without requiring elevated or root permissions. +The standard-library web viewer currently binds to 127.0.0.1 and checks request headers for state-changing routes. It uses HTTP without TLS and is not an authenticated remote service or an operating-system sandbox. Do not expose it to other hosts without a separate review. + +These notes describe reviewed source paths; they do not certify a deployment, dependency set, or user configuration. ## Reporting a Vulnerability -If you discover a potential security vulnerability, please report it responsibly: +Check the repository’s Security tab to see whether GitHub Private Vulnerability Reporting is enabled. If enabled, use its private report form. If it is unavailable, do not publish vulnerability details in a public issue; ask the maintainers for a private contact route. -1. **Do NOT open a public issue.** -2. **Use GitHub Private Vulnerability Reporting**: - Navigate to [GitHub Advisory Submission](https://github.com/file-bricks/knowledgedigest/security/advisories/new). -3. Provide details: - - Component / module affected (e.g. `web_viewer.py`, `chunker.py`, `digest.py`) - - Steps to reproduce or proof-of-concept - - Potential impact and severity assessment +Include the affected version, relevant component, reproducible steps, and impact. Avoid attaching private documents, credentials, or unrelated personal data. -## Service Level Agreements (SLAs) +## Response Expectations -- **Initial Response**: Within 48 hours of report submission. -- **Triage & Assessment**: Within 5 business days. -- **Patch Deployment**: Security fixes will be released on `main` and tagged in a timely manner before coordinated disclosure. +Maintainers aim to acknowledge reports within 48 hours and complete initial triage within five business days. When a fix is appropriate, they aim to coordinate a release before public disclosure. These are maintainer targets, not guaranteed service levels; investigation and release timing depend on severity, reproducibility, and capacity. diff --git a/SMOKE-CHECKS.md b/SMOKE-CHECKS.md index 602073a..57b6e70 100644 --- a/SMOKE-CHECKS.md +++ b/SMOKE-CHECKS.md @@ -1,200 +1,35 @@ -# Smoke-Checks: Web-Viewer und Desktop-GUI +# Smoke checks: web viewer, desktop GUI, and installed package -Dieses Dokument beschreibt die Smoke-Checks für die beiden interaktiven -Frontends von KnowledgeDigest: den Web-Viewer und die Desktop-GUI. -Die Core-Unit-Tests (chunker, schema, config, utils) sind in `tests/test_core.py` -abgedeckt und laufen via `python -m pytest tests -q`. +These checks cover selected startup and packaging behavior. They do not exercise provider APIs, real user databases, or a full security boundary. ---- +## Web viewer -## 1. Web-Viewer-Smoke-Check +Install the core package, then run the local viewer with a test database in a writable temporary directory: -### Zweck + python -m KnowledgeDigest --web --db C:/Temp/knowledgedigest-smoke.db --no-browser -Sicherstellen, dass der Web-Viewer korrekt startet, einen HTTP-Server auf -dem konfigurierten Port bindet und eine gültige HTML-Seite (Dashboard) -ausliefert — ausschließlich mit Python-Stdlib, ohne externe Abhängigkeiten. +The current implementation binds to 127.0.0.1 and serves local HTTP without TLS. While it is running, request the dashboard from the same machine and confirm an HTTP 200 response. Stop it with Ctrl+C. Do not expose it through a reverse proxy without a separate security review. -- Modul: `web_viewer.py` -- Einstiegspunkt: `launch_web()` / `python -m KnowledgeDigest --web` -- Abhängigkeiten: **Python-Stdlib only** (kein Flask, kein Django) +The viewer can create or initialize the selected database. Use a disposable path for this check. -### Voraussetzungen +## Desktop GUI -```bash -python --version # Python 3.10+ erforderlich -pip install -e . # Paket installieren (kein weiteres pip-install nötig) -``` +Install the optional GUI dependencies: -### Manueller Smoke-Check (interaktiv) + python -m pip install -e ".[gui]" -```bash -# Windows (PowerShell oder Git Bash): -PYTHONIOENCODING=utf-8 python -m KnowledgeDigest --web --no-browser -``` +Then launch: -Option `--no-browser` verhindert das automatische Öffnen des Browsers. -Alternativer Port (falls 8787 belegt): + python -m KnowledgeDigest --gui -```bash -PYTHONIOENCODING=utf-8 python -m KnowledgeDigest --web --port 9000 --no-browser -``` +The current desktop UI strings are German-only. A graphical display is required. The application icon is expected to load from the installed KnowledgeDigest package; the packaging smoke script checks this in an offscreen Qt session. -Eigene Datenbankdatei angeben: +## Installed wheel and source distribution -```bash -PYTHONIOENCODING=utf-8 python -m KnowledgeDigest --web --db pfad/zur/knowledge.db --no-browser -``` +The CI packaging job builds both artifacts, checks that each contains KnowledgeDigest.ico, installs each into a separate target directory, and runs the CLI help and icon smoke checks from outside the source tree. It does not open a real profile database or call a provider. -### Erwartete Konsolenausgabe +## Scope limits -``` -KnowledgeDigest Web-Viewer: http://127.0.0.1:8787 -DB: data/knowledge.db -``` - -Der Prozess blockiert danach (HTTP-Server lauscht). Beenden mit **Ctrl+C**: - -``` -Viewer beendet. -``` - -### Erwartetes HTTP-Ergebnis - -`GET http://127.0.0.1:8787/` liefert HTTP 200 mit HTML-Dashboard. - -Prüfung via PowerShell (Windows, während der Server läuft): - -```powershell -(Invoke-WebRequest -Uri http://127.0.0.1:8787/ -UseBasicParsing).StatusCode -# Erwartet: 200 -``` - -Prüfung via Git Bash / curl (falls verfügbar): - -```bash -curl -s -w "%{http_code}" http://127.0.0.1:8787/ -o nul -# Erwartet: 200 -``` - -### Headless-Import-Check (CI-geeignet, ohne laufenden Server) - -Prüft nur, ob das Modul fehlerfrei importierbar ist — startet keinen Server: - -```bash -PYTHONIOENCODING=utf-8 python -c "from KnowledgeDigest.web_viewer import launch_web; print('OK')" -# Erwartet: OK -``` - -Dieser Check ist bereits indirekt im CI enthalten (`python -m compileall -q .` -und `python -m KnowledgeDigest --help`), testet aber keinen laufenden Server. - -### Typische Fehler - -| Fehler | Ursache | Lösung | -|--------|---------|--------| -| `OSError: [Errno 10048] / Address already in use` | Port 8787 belegt | `--port 9000` (oder freien Port wählen) | -| `sqlite3.OperationalError: no such table` | DB-Schema fehlt | `python -m KnowledgeDigest status` ausführen (initialisiert Schema) | -| `ModuleNotFoundError: No module named 'KnowledgeDigest'` | Paket nicht installiert | `pip install -e .` ausführen | -| `FileNotFoundError` (DB-Pfad) | Falsche DB-Konfiguration | `--db pfad/knowledge.db` explizit angeben | -| Leere Dokumentenliste im Browser | Normale Erstnutzung | `python -m KnowledgeDigest scan ` ausführen | - ---- - -## 2. Desktop-GUI-Smoke-Check - -### Zweck - -Sicherstellen, dass die PySide6-Anwendung korrekt startet, das Hauptfenster -öffnet und die 3-Panel-Ansicht (Verzeichnisse | Dokumente | Vorschau) mit -Dark-Theme und Toolbar anzeigt. - -- Modul: `gui/app.py` (Einstieg: `launch_gui()`) -- Einstiegspunkt: `python -m KnowledgeDigest --gui` -- Abhängigkeit: **PySide6** (nicht Stdlib — muss installiert sein) -- Voraussetzung: **Grafisches Display** muss verfügbar sein (kein reines Headless-CI) - -### Voraussetzungen - -```bash -python --version # Python 3.10+ erforderlich -pip install -e . # Paket + Kern-Abhängigkeiten installieren -pip install PySide6 # GUI-Abhängigkeit (LGPL) -``` - -### Manueller Smoke-Check (interaktiv) - -```bash -# Windows (PowerShell oder Git Bash): -PYTHONIOENCODING=utf-8 python -m KnowledgeDigest --gui -``` - -Alternativ über das mitgelieferte Windows-Startskript: - -```bat -start.bat -``` - -(`start.bat` liegt im Elternordner des Projektverzeichnisses und ruft -`launcher.py` auf, der seinerseits die GUI startet.) - -### Erwartetes Verhalten - -Nach dem Start (keine Konsolenausgabe erwartet): - -1. Anwendungsfenster öffnet sich (Mindestgröße 900 × 600 px). -2. Dark-Theme ist aktiv (Hintergrundfarbe `#0d1117`). -3. Toolbar sichtbar mit den Aktionen „+ Verzeichnis" und „Scannen", einem Suchfeld - (Platzhaltertext „Suche (FTS5)...") sowie den Aktionen „Web-Viewer" und „Einstellungen". -4. 3-Panel-Splitter: Links Verzeichnisliste, Mitte Dokumententabelle, Rechts Vorschau. -5. Statusleiste am unteren Rand zeigt eine Bereitschaftsmeldung. -6. Schließen des Fensters beendet die Anwendung sauber (Exit-Code 0). - -### Headless-Import-Check (CI-geeignet, ohne Display) - -Prüft den Import aller GUI-Module ohne einen QApplication-Start: - -```bash -PYTHONIOENCODING=utf-8 python -c "from KnowledgeDigest.gui.app import launch_gui; print('OK')" -# Erwartet: OK (schlägt fehl, wenn PySide6 nicht installiert ist) -``` - -**Hinweis:** Der vollständige GUI-Start (`launch_gui()`) erfordert einen -aktiven Display-Server. In headless CI-Umgebungen (z. B. GitHub Actions -Ubuntu-Runner ohne Virtual Display) schlägt `python -m KnowledgeDigest --gui` -mit einem Qt-Fehler fehl — das ist kein Anwendungsfehler: - -``` -qt.qpa.xcb: could not connect to display -``` - -Der CI-Workflow (`tests.yml`) enthält deshalb keinen vollständigen GUI-Start. -Der Import-Check oben ist der höchste CI-taugliche Prüfpunkt ohne Xvfb-Setup. - -### Typische Fehler - -| Fehler | Ursache | Lösung | -|--------|---------|--------| -| `ModuleNotFoundError: No module named 'PySide6'` | PySide6 nicht installiert | `pip install PySide6` | -| `qt.qpa.xcb: could not connect to display` | Kein grafisches Display (Linux CI) | Nur im interaktiven Kontext ausführen; kein CI-Fehler | -| `qt.qpa.plugin: Could not load the Qt platform plugin "xcb"` | Fehlende Qt-Plattform-Bibliotheken (Linux) | PySide6 neu installieren oder `libxcb`-Pakete via apt prüfen | -| `FileNotFoundError: KnowledgeDigest.ico` | App-Icon nicht vorhanden | Kein funktionaler Fehler — GUI startet trotzdem ohne Icon | -| `ModuleNotFoundError: No module named 'KnowledgeDigest'` | Paket nicht installiert | `pip install -e .` ausführen | -| `ModuleNotFoundError: No module named 'fitz'` | PyMuPDF fehlt (PDF-Vorschau) | `pip install PyMuPDF` (optional, nur für PDF-Vorschau im Preview-Panel) | -| Leere Dokumentenliste nach Start | Normale Erstnutzung | Verzeichnis über Toolbar-Schaltfläche „+" hinzufügen und scannen | - ---- - -## Abgrenzung: Was dieser Check NICHT testet - -- **Core-Logik** (Chunker, Schema, Config, Utils): Abgedeckt durch `tests/test_core.py` - (`python -m pytest tests -q`). -- **LLM-Summarization** (Haiku/Flash): Erfordert API-Schlüssel — kein Teil des Smoke-Checks. -- **BACH-Integration**: Optionales Modul, deaktiviert per Default (`bach_enabled: false`). -- **Vollständige End-to-End-Tests** (Ingest → Suche → Ergebnis): Nicht enthalten; - diese würden eigene Integrationstests erfordern. - ---- - -*Erstellt 2026-06-28. Basis: `web_viewer.py` (launch\_web), `gui/app.py` (launch\_gui), -`__main__.py`, `.github/workflows/tests.yml`.* +- Optional summarize commands are not part of this smoke check; they can send selected document text and prompts to the configured provider. +- Optional BACH import and SQLite Transit synchronization require their own configured data and are not exercised here. +- A successful startup check does not establish security, licensing, or privacy compliance. diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 6a1c056..ed6ea15 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -1,73 +1,37 @@ -# Third-Party Licenses & Level 1 SBOM Inventory +# Direct Dependency and License Notes -**Project:** `KnowledgeDigest` (Portable Local Knowledge Database & Full-Text Search Engine) -**License:** [MIT License](LICENSE) -**Audit Date:** 2026-09-22 -**Repository:** [file-bricks/KnowledgeDigest](https://github.com/file-bricks/knowledgedigest) -**Organization:** [file-bricks](https://github.com/file-bricks) -**Umbrella Ecosystem:** [open-bricks](https://github.com/open-bricks) -**Author:** Lukas Geiger ([github.com/lukisch](https://github.com/lukisch)) +**Project:** KnowledgeDigest +**Project-source license:** MIT (see LICENSE) +**Snapshot date:** 2026-10-12 +**Scope:** Declared direct packages in pyproject.toml extras and the optional SQLite Transit adapter. ---- +This is a manually maintained, bounded reference list. It is not a generated SBOM, a complete dependency inventory, or a legal compliance assessment. It does not enumerate transitive packages, platform-specific binary contents, or every license option offered by upstream projects. Before redistribution, inspect the license files and metadata of the exact distributions being shipped. -## 1. Runtime Architecture & Zero-Cloud Core +## Declared direct optional packages -`KnowledgeDigest` is an offline-first, local-first document indexing and retrieval application built with Python 3.10+, SQLite FTS5, and PySide6. The application runs entirely on the user's local workstation, persists indexed document chunks in a self-contained SQLite database (`data/knowledge.db`), and exposes both a native desktop GUI and a zero-dependency Python standard library Web Viewer (`web_viewer.py` on `http://localhost:8787`). +| Package | Declared use | Upstream license reference (bounded note) | +|---|---|---| +| pdfplumber | PDF text/layout extraction (extract) | MIT | +| PyPDF2 | PDF parsing fallback (extract) | BSD-3-Clause | +| python-docx | DOCX extraction (extract) | MIT | +| beautifulsoup4 | HTML parsing (extract) | MIT | +| [PySide6](https://doc.qt.io/qtforpython-6/licenses.html) | Desktop GUI (gui) | Qt for Python has LGPLv3/GPLv3 and commercial licensing options, plus components under original licenses; inspect the selected distribution's license files. | +| [pypdfium2](https://github.com/pypdfium2-team/pypdfium2) | GUI PDF preview (gui) | Upstream provides Apache-2.0 / BSD-3-Clause notices; inspect the selected distribution. | +| anthropic | Optional Anthropic summarization client (llm) | MIT | +| google-genai | Optional Google GenAI summarization client (llm) | Apache-2.0 | +| pytest | Tests (test) | MIT | -Under default configuration, zero network calls are performed. Optional LLM summarization (`--flash` via Google GenAI or `--haiku` via Anthropic) is strictly opt-in and operates only when the user explicitly provides API credentials. +The sqlite-transit-sync adapter is imported optionally by transit.py and is not on PyPI; its project and license metadata are maintained at https://github.com/ellmos-ai/sqlite-transit-sync. It is separate from the default indexing/search path. ---- +## Source and runtime boundaries -## 2. Direct Runtime Dependencies +- The repository source declares MIT in LICENSE and package metadata. +- The tests/test_no_agpl.py guard checks selected source files for explicit imports of fitz, pymupdf, and PyMuPDF. It does not inspect the dependency graph, downloaded wheels, native libraries, or transitive package licenses. +- Choosing pypdfium2 means the project does not declare PyMuPDF for PDF preview. This is not a guarantee that every possible environment is free of copyleft components. +- Optional summarization sends selected document chunks and prompts to the configured provider when invoked. Optional SQLite Transit can transfer configured snapshots between nodes. -All direct runtime dependencies are distributed under permissive open-source licenses (MIT, Apache-2.0, BSD-3-Clause, LGPL-3.0, PSFL). No viral copyleft (GPL, AGPL) components are bundled into the distribution: +For an actual release or bundled application, generate and review an inventory of the exact build artifacts and their included license files. This document alone is not that review. -| Component / Package | License | Project URL | Purpose | -|---|---|---|---| -| **Python Standard Library** | PSFL-2.0 | [python.org](https://www.python.org/) | Runtime execution, SQLite (`sqlite3`), HTTP Web Viewer (`http.server`), cryptographic hashing (`hashlib`). | -| **`pdfplumber`** | MIT | [jsvine/pdfplumber](https://github.com/jsvine/pdfplumber) | Deep text and layout extraction from PDF files. | -| **`PyPDF2`** | BSD-3-Clause | [py-pdf/pypdf](https://github.com/py-pdf/pypdf) | Fallback PDF stream extraction and structural parsing. | -| **`python-docx`** | MIT | [python-openxml/python-docx](https://github.com/python-openxml/python-docx) | Text and metadata extraction from Microsoft Word (`.docx`) files. | -| **`beautifulsoup4`** | MIT | [wention/BeautifulSoup4](https://git.launchpad.net/beautifulsoup) | HTML document parsing and boilerplate stripping. | -| **`PySide6` / Qt6** | LGPL-3.0 | [qt.io](https://www.qt.io/) | Native 3-panel desktop GUI interface with dark theme. Dynamically linked in compliance with LGPL-3.0 Section 4. | -| **`pypdfium2`** | Apache-2.0 / BSD-3-Clause | [pypdfium2-team/pypdfium2](https://github.com/pypdfium2-team/pypdfium2) | In-app GUI PDF preview rendering (Decision E08: explicitly selected over PyMuPDF / AGPL-3.0 to keep distribution 100% free of copyleft). | -| **`anthropic`** (optional) | MIT | [anthropics/anthropic-sdk-python](https://github.com/anthropics/anthropic-sdk-python) | Optional Claude Haiku batch summarization client. | -| **`google-genai`** (optional) | Apache-2.0 | [googleapis/python-genai](https://github.com/googleapis/python-genai) | Optional Gemini Flash batch summarization client. | +## Attribution ---- - -## 3. Development, Testing & Verification Dependencies - -The following tools are utilized strictly during development, automated testing, and CI verification pipelines: - -| Tool / Framework | License | Project URL | Purpose | -|---|---|---|---| -| **`pytest`** | MIT | [pytest-dev/pytest](https://github.com/pytest-dev/pytest) | Test execution and metadata contract test suite. | -| **`ruff`** | MIT / Apache-2.0 | [astral-sh/ruff](https://github.com/astral-sh/ruff) | High-performance Python linting and code formatting enforcement. | - ---- - -## 4. Invariant Cross-Reference Matrix - -KnowledgeDigest enforces ten core governance and runtime invariants across its architecture and codebase: - -| Invariant Code | Category | Description & Technical Implementation | Verification Method | -|---|---|---|---| -| **`INV-LOCAL-01`** | Data Privacy | **Local-First & Zero Egress**: All parsing, indexing, and SQLite FTS5 queries execute strictly on the local machine. Zero background telemetry or tracking. | `tests/test_core.py`, `SECURITY.md` | -| **`INV-SQLITE-02`** | Storage Engine | **ACID SQLite FTS5 Full-Text Engine**: Persistent indexed chunks, keywords, and metadata in `data/knowledge.db` with BM25 snippet ranking and auto-sync triggers. | `KnowledgeDigest/schema.py`, `tests/test_core.py` | -| **`INV-CHUNK-03`** | Natural Language | **Sentence-Bounded Semantic Chunking**: Text segmentation into ~350-word chunks respecting natural punctuation and paragraph boundaries without mid-sentence chops. | `KnowledgeDigest/chunker.py`, `tests/test_core.py` | -| **`INV-COPYLEFT-04`** | Licensing | **Zero-Copyleft Isolation Guarantee**: 100% Permissive MIT distribution. Decision E08 mandates `pypdfium2` over PyMuPDF (`fitz`), and PySide6 is dynamically linked. | `tests/test_no_agpl.py` | -| **`INV-RUNAS-05`** | Security | **Unprivileged Execution (`RunAsInvoker`)**: Operates exclusively in user space without administrator, root, or elevated privileges. | `SECURITY.md` | -| **`INV-DUAL-06`** | User Interface | **Dual Frontends**: PySide6 Desktop GUI (3-panel layout) + Python stdlib zero-dependency Web Viewer (`http://localhost:8787`). | `KnowledgeDigest/gui/`, `KnowledgeDigest/web_viewer.py` | -| **`INV-OPTLLM-07`** | Extensibility | **Optional LLM Boundary**: Complete search, indexing, and browsing functionality works 100% offline without any LLM; optional Gemini Flash / Haiku batch queues. | `KnowledgeDigest/summarizer.py`, `tests/test_flash_summarizer.py` | -| **`INV-DEDUPE-08`** | Data Integrity | **Cryptographic Deduplication & Quarantine**: SHA-256 hash calculation for all indexed documents with non-destructive `_Papierkorb` duplicate isolation. | `KnowledgeDigest/digest.py`, `tests/test_core.py` | -| **`INV-DOCS-09`** | Documentation | **100% Bilingual Documentation Parity**: 18-point dual-anchor navigation parity between English (`README.md`) and German (`README_de.md`). | `tests/test_metadata.py` | -| **`INV-SLA-10`** | Governance | **Statutory Disclaimer & 48h Security SLA**: German statutory disclaimer (§ 521 BGB Gefälligkeitsrecht) and guaranteed 48-hour response SLA. | `SECURITY.md`, `README.md`, `README_de.md` | - ---- - -## 5. Zero-Copyleft Guarantee & Unprivileged Execution - -- **Zero-Copyleft Guarantee:** All source code, interfaces, CLI scripts, and manifests in this repository are licensed under the permissive [MIT License](LICENSE). In adherence to Decision E08 (2026-08-18), no AGPL or viral copyleft libraries (such as `PyMuPDF`/`fitz`) are permitted in the distribution. Automated regression tests (`tests/test_no_agpl.py`) continuously enforce this invariant. -- **Unprivileged User Mode (`RunAsInvoker`):** `KnowledgeDigest` runs entirely within standard user permissions. It does not install kernel drivers, background daemons, root services, or modify system-wide registry keys. -- **Data Isolation:** All persistent runtime databases, indices, and configuration files reside in `data/` or user-specified local directories and are strictly excluded from Git tracking via `.gitignore`. +See NOTICE for project attribution. diff --git a/llms.txt b/llms.txt index f2f12c0..3c9cd03 100644 --- a/llms.txt +++ b/llms.txt @@ -1,76 +1,45 @@ -## Last-checked: 2026-09-22 - # KnowledgeDigest -KnowledgeDigest is a local-first Python tool for indexing documents into a portable SQLite/FTS5 knowledge database. It supports sentence-bounded semantic chunking (~350 words), full-text search with BM25 ranking, optional LLM summaries (Gemini Flash / Claude Haiku), a PySide6 desktop GUI, a stdlib web viewer, CLI commands, and a Python API. +KnowledgeDigest is a Python document-indexing and SQLite FTS5 search application. The local path extracts user-selected files, stores chunks and metadata in the configured SQLite database, and supports BM25-ranked full-text search through CLI, Python API, desktop GUI, and web viewer. Canonical repository: https://github.com/file-bricks/knowledgedigest -Parent Organization: https://github.com/file-bricks -Umbrella Ecosystem: https://github.com/open-bricks -Author: Lukas Geiger (https://github.com/lukisch) -License: MIT License (https://github.com/file-bricks/knowledgedigest/blob/main/LICENSE) -Attribution: NOTICE (https://github.com/file-bricks/knowledgedigest/blob/main/NOTICE) -Level 1 SBOM: THIRD_PARTY_LICENSES.md (https://github.com/file-bricks/knowledgedigest/blob/main/THIRD_PARTY_LICENSES.md) - -## Useful Entry Points +License of project source: MIT (LICENSE) +Version remains 0.4.0; no release is implied by this documentation update. -- `README.md`: user-facing overview, 18-point dual-anchor navigation, installation, commands, and feature summary. -- `README_de.md`: German documentation with reciprocal 18-point navigation parity. -- `ARCHITECTURE.md`: module map, data flow, schema overview, and design decisions. -- `THIRD_PARTY_LICENSES.md`: Level 1 SBOM inventory, runtime invariants (INV-LOCAL-01..INV-SLA-10), RunAsInvoker unprivileged execution, and Zero-Copyleft isolation guarantee. -- `SECURITY.md`: local-first invariants, vulnerability reporting, and 48-hour response SLA. -- `digest.py`: high-level API and CLI command implementation. -- `web_viewer.py`: local browser viewer without external web framework dependencies (`http://localhost:8787`). -- `gui/`: PySide6 desktop interface with dark theme and 3-panel layout. -- `tests/test_metadata.py`: automated contract tests for PEP 621, SBOM invariants, and documentation parity. -- `tests/test_no_agpl.py`: contract test enforcing zero-copyleft and prohibiting AGPL libraries (Decision E08). +## Data flow and boundaries -## Run And Test +- Local parsing, indexing, and ordinary FTS5 search use the configured local SQLite database; no LLM provider is required for them. +- CLI summarize uses Anthropic by default; summarize --flash selects Google GenAI. Selected chunks and prompts are sent to the configured provider when this command runs. +- The Python Summarizer API also supports Ollama or a custom base URL. A custom endpoint may be remote. +- Optional BACH import reads its configured SQLite database read-only and writes imported content to the KnowledgeDigest database. +- Optional SQLite Transit synchronization can transfer configured snapshots between nodes. +- The current web viewer binds to 127.0.0.1, uses HTTP without TLS, and is not an authenticated remote service. +- The desktop GUI currently has German-only visible strings and no language selector. -```bash -python -m pip install -e . -python -m pytest -python -m KnowledgeDigest status -``` +## Useful files -Runtime data is local and ignored by Git: `data/`, `*.db`, and `knowledgedigest.json`. +- README.md and README_de.md: user documentation and navigation. +- ARCHITECTURE.md: module, configuration, and data-flow notes. +- SECURITY.md: vulnerability reporting guidance and bounded source notes. +- THIRD_PARTY_LICENSES.md: manually maintained direct-dependency notes; not a generated SBOM or full transitive inventory. +- NOTICE and LICENSE: project attribution and project-source license. +- tests/test_metadata.py: metadata and navigation-anchor checks. +- tests/test_packaging.py: package-data contract check. +- tests/package_smoke.py: installed-artifact Qt icon smoke check; the packaging workflow separately runs the installed CLI with `--help`. +- tests/test_no_agpl.py: source guard against selected explicit PyMuPDF import names; not a distribution-license audit. +- .github/workflows/tests.yml: test matrix and wheel/sdist packaging smoke job. -## Governance & Runtime Invariants +## Configuration -- `INV-LOCAL-01`: Local-First & Zero Egress (all document parsing and SQLite queries run locally). -- `INV-SQLITE-02`: ACID SQLite FTS5 Full-Text Search Engine with BM25 snippet ranking. -- `INV-CHUNK-03`: Sentence-Bounded Semantic Chunking (~350 words, preserving grammatical clauses). -- `INV-COPYLEFT-04`: Zero-Copyleft MIT Guarantee (`pypdfium2` over PyMuPDF, dynamically linked PySide6). -- `INV-RUNAS-05`: Unprivileged User Mode (`RunAsInvoker`, no administrative elevation required). -- `INV-DUAL-06`: Dual Frontends (PySide6 Native Desktop GUI + Stdlib Web Viewer on localhost:8787). -- `INV-OPTLLM-07`: Optional Asynchronous LLM Integration (fully operational offline without LLM). -- `INV-DEDUPE-08`: Cryptographic SHA-256 Deduplication with non-destructive `_Papierkorb` quarantine. -- `INV-DOCS-09`: 100% Bilingual Documentation Parity (18-point reciprocal dual HTML anchors). -- `INV-SLA-10`: Statutory Disclaimer (§ 521 BGB Gefälligkeitsrecht) & 48-hour security response SLA. +Configuration filename is knowledgedigest.json. Lookup order is current working directory, package data/, Windows APPDATA/KnowledgeDigest/ when available, then XDG_CONFIG_HOME/knowledgedigest/ or ~/.config/knowledgedigest/. If none exists, built-in defaults are used with package data/ paths. An installed package directory may not be writable. There is no --config CLI option; Python callers can use get_config(Path(...)). -## Audience +## Related tools -- **Local-first users** who want a portable, self-contained document knowledge base without cloud dependencies -- **Python developers** building document-indexing, retrieval, or LLM-preprocessing pipelines -- **AI engineers** needing an offline, privacy-preserving search backend for local LLM workflows -- **Researchers and writers** managing large collections of PDFs, Markdown, DOCX, and text files -- **Privacy-conscious teams** who need FTS5 full-text search without any data leaving the local machine +- NoteSpaceLLM: separate local SQLite/plain-text notebook for notes; no runtime integration is claimed (https://github.com/file-bricks/NoteSpaceLLM). +- BACH: optional read-only SQLite import path when configured (https://github.com/ellmos-ai/bach). +- SQLite Transit Sync: optional snapshot synchronization adapter (https://github.com/ellmos-ai/sqlite-transit-sync). +- open-bricks: broader project family (https://github.com/open-bricks). -## Search Phrases +## Validation limits -``` -portable knowledge database Python -local document search FTS5 SQLite -PySide6 knowledge base app -local-first document indexing Python -LLM document summarization local -offline document search tool Python -KnowledgeDigest -file-bricks knowledgedigest -desktop document search offline-first -local-first AI RAG database sqlite -knowledge base desktop GUI Python -sentence bounded text chunking python -zero egress document indexing -sqlite fts5 bm25 full text search -``` +Test and package checks cover selected behavior only. They are not a complete security review, license audit, generated SBOM, or deployment assessment. Optional provider and sync behavior depends on user configuration. diff --git a/pyproject.toml b/pyproject.toml index 499f3fe..dcddecc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,13 +19,10 @@ keywords = [ "sqlite", "document-search", "local-first", - "offline-first", "document-indexing", "document-processing", "pdf-indexer", "summarization", - "privacy-first", - "zero-egress", "desktop-app", "pyside6", "python", @@ -112,6 +109,9 @@ packages = [ [tool.setuptools.package-dir] KnowledgeDigest = "." +[tool.setuptools.package-data] +KnowledgeDigest = ["KnowledgeDigest.ico"] + [tool.pytest.ini_options] minversion = "7.0" pythonpath = "." diff --git a/tests/package_smoke.py b/tests/package_smoke.py new file mode 100644 index 0000000..c55e409 --- /dev/null +++ b/tests/package_smoke.py @@ -0,0 +1,24 @@ +from importlib.resources import files +from pathlib import Path + +from PySide6.QtGui import QIcon +from PySide6.QtWidgets import QApplication + +from KnowledgeDigest.gui.app import _load_app_icon + + +def main() -> None: + resource = files("KnowledgeDigest").joinpath("KnowledgeDigest.ico") + assert resource.is_file(), "KnowledgeDigest.ico is missing from the installed package" + icon_path = Path(str(resource)) + assert icon_path.stat().st_size > 0, "KnowledgeDigest.ico is empty" + + app = QApplication.instance() or QApplication(["knowledgedigest-package-smoke"]) + icon = QIcon(str(icon_path)) + assert not icon.isNull(), "Qt could not load the installed package icon" + assert not _load_app_icon().isNull(), "the application icon loader returned a null icon" + app.quit() + + +if __name__ == "__main__": + main() diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 6abad86..a2855ec 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Contract and metadata tests for KnowledgeDigest (Pfad A). Validates PEP 621 compliance, version parity, manifest consistency, @@ -6,9 +5,9 @@ """ import json -from pathlib import Path import py_compile import re +from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent @@ -106,20 +105,6 @@ def test_all_python_files_compile(): raise AssertionError(f"Bytecode compilation failed for {py_file}: {exc}") from exc -def test_security_policy_structure(): - """Ensure SECURITY.md contains supported versions, SLA, and security invariants.""" - sec_file = REPO_ROOT / "SECURITY.md" - assert sec_file.is_file(), "SECURITY.md must exist" - sec_text = sec_file.read_text(encoding="utf-8") - - assert "Supported Versions" in sec_text - assert "0.4.x" in sec_text - assert "48 hours" in sec_text - assert "5 business days" in sec_text - assert "Zero Egress" in sec_text - assert "RunAsInvoker" in sec_text or "Unprivileged Execution" in sec_text - - def test_ci_workflow_integrity(): """Ensure .github/workflows/tests.yml specifies required guardrails.""" workflow_file = REPO_ROOT / ".github" / "workflows" / "tests.yml" @@ -162,25 +147,6 @@ def test_canonical_notice_attribution(): assert "MIT License" in content -def test_level1_sbom_and_invariants(): - """Verify THIRD_PARTY_LICENSES.md exists, lists Level 1 SBOM, RunAsInvoker, and all 10 invariants.""" - sbom_file = REPO_ROOT / "THIRD_PARTY_LICENSES.md" - assert sbom_file.is_file(), "THIRD_PARTY_LICENSES.md must exist in repo root" - content = sbom_file.read_text(encoding="utf-8") - assert "Level 1 SBOM Inventory" in content - assert "RunAsInvoker" in content - assert "Zero-Copyleft Guarantee" in content - assert "pypdfium2" in content - assert "PySide6" in content - expected_invariants = [ - "INV-LOCAL-01", "INV-SQLITE-02", "INV-CHUNK-03", "INV-COPYLEFT-04", - "INV-RUNAS-05", "INV-DUAL-06", "INV-OPTLLM-07", "INV-DEDUPE-08", - "INV-DOCS-09", "INV-SLA-10" - ] - for inv in expected_invariants: - assert inv in content, f"Expected invariant {inv} in THIRD_PARTY_LICENSES.md" - - def test_pyproject_version_freeze_and_license_files(): """Verify PEP 621 version is strictly frozen at 0.4.0 (T-20260920-167562623) and license-files configured.""" pyproject_file = REPO_ROOT / "pyproject.toml" @@ -195,7 +161,7 @@ def test_pyproject_version_freeze_and_license_files(): def test_bilingual_navigation_parity_18_points(): - """Verify README.md and README_de.md maintain exact 18-point dual-anchor navigation parity.""" + """Verify the 18 section anchor IDs used by the navigation remain present in both READMEs.""" en_readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") de_readme = (REPO_ROOT / "README_de.md").read_text(encoding="utf-8") @@ -203,38 +169,3 @@ def test_bilingual_navigation_parity_18_points(): anchor = f'' assert anchor in en_readme, f"Missing {anchor} in README.md" assert anchor in de_readme, f"Missing {anchor} in README_de.md" - - -def test_target_personas_and_comparison_matrix(): - """Verify both documentation files feature personas [PERSONA-01] to [PERSONA-04] and comparison matrix.""" - en_readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") - de_readme = (REPO_ROOT / "README_de.md").read_text(encoding="utf-8") - - for p in ["PERSONA-01", "PERSONA-02", "PERSONA-03", "PERSONA-04"]: - assert p in en_readme, f"Expected {p} in README.md" - assert p in de_readme, f"Expected {p} in README_de.md" - - assert "INV-LOCAL-01" in en_readme - assert "INV-LOCAL-01" in de_readme - - -def test_statutory_disclaimer_and_sla(): - """Verify § 521 BGB statutory disclaimer and 48-hour response SLA across documentation and security policy.""" - en_readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") - de_readme = (REPO_ROOT / "README_de.md").read_text(encoding="utf-8") - sec_policy = (REPO_ROOT / "SECURITY.md").read_text(encoding="utf-8") - - assert "521 BGB" in en_readme - assert "521 BGB" in de_readme - assert "48" in en_readme - assert "48" in de_readme - assert "48 hours" in sec_policy or "48" in sec_policy - - -def test_marketing_log_recency(): - """Verify MARKETING-LOG.txt contains a recent Pfad B entry.""" - log_file = REPO_ROOT / "MARKETING-LOG.txt" - assert log_file.is_file(), "MARKETING-LOG.txt must exist" - content = log_file.read_text(encoding="utf-8") - assert "2026-09-22" in content - assert "Pfad B" in content diff --git a/tests/test_no_agpl.py b/tests/test_no_agpl.py index db09687..4e1c231 100644 --- a/tests/test_no_agpl.py +++ b/tests/test_no_agpl.py @@ -25,7 +25,7 @@ # Verzeichnisse, in denen kein eigener Quelltext liegt (Assets, Caches, Tests # selbst duerfen theoretisch importieren, tun es hier aber ebenfalls nicht). -AUSGESCHLOSSEN = {"__pycache__", "mobile_icons", "assets", ".git"} +AUSGESCHLOSSEN = {"__pycache__", "mobile_icons", "assets", ".git", "build", "dist"} # Namen, die eine Copyleft-Bindung in ein ausgeliefertes MIT-Modul tragen wuerden. VERBOTEN = { @@ -35,15 +35,30 @@ } -def _modul_dateien() -> list[Path]: +def _modul_dateien(root: Path = REPO_ROOT) -> list[Path]: dateien = [] - for pfad in REPO_ROOT.rglob("*.py"): - if any(teil in AUSGESCHLOSSEN for teil in pfad.relative_to(REPO_ROOT).parts): + for pfad in root.rglob("*.py"): + teile = pfad.relative_to(root).parts + if any(teil in AUSGESCHLOSSEN or teil.endswith(".egg-info") for teil in teile): continue dateien.append(pfad) return sorted(dateien) +def test_generated_packaging_outputs_do_not_enter_source_scan(tmp_path: Path): + source_file = tmp_path / "src" / "module.py" + generated_files = [ + tmp_path / "build" / "module.py", + tmp_path / "dist" / "module.py", + tmp_path / "knowledgedigest.egg-info" / "metadata.py", + ] + for path in [source_file, *generated_files]: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("VALUE = 1\n", encoding="utf-8") + + assert _modul_dateien(tmp_path) == [source_file] + + def test_paket_hat_dateien(): assert _modul_dateien(), "Kein Quelltext gefunden -- Testpfad pruefen" diff --git a/tests/test_packaging.py b/tests/test_packaging.py new file mode 100644 index 0000000..36a4d1b --- /dev/null +++ b/tests/test_packaging.py @@ -0,0 +1,15 @@ +import re +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent + + +def test_application_icon_is_declared_as_package_data(): + pyproject = (REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8") + assert re.search( + r'(?ms)^\[tool\.setuptools\.package-data\]\s*KnowledgeDigest\s*=\s*\["KnowledgeDigest\.ico"\]', + pyproject, + ) + icon = REPO_ROOT / "KnowledgeDigest.ico" + assert icon.is_file() + assert icon.stat().st_size > 0