Extend command line and add db init.

This also removes obsolete schema files for clarity
This commit is contained in:
Χγφτ Kompanion 2025-10-15 22:35:19 +13:00
parent e881bc4998
commit a04506a081
7 changed files with 27 additions and 176 deletions

View File

@ -4,6 +4,8 @@ project(metal_kompanion_mcp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
option(KOM_ENABLE_PG "Enable Postgres-backed DAL support" ON) option(KOM_ENABLE_PG "Enable Postgres-backed DAL support" ON)
set(KOM_HAVE_PG OFF) set(KOM_HAVE_PG OFF)
@ -38,6 +40,9 @@ if (KOMPANION_KCONFIG_TARGET STREQUAL "")
message(WARNING "KConfig (KF6/KF5) not found; defaulting to environment-based configuration.") message(WARNING "KConfig (KF6/KF5) not found; defaulting to environment-based configuration.")
endif() endif()
set(KOMPANION_DB_INIT_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/kompanion/db/init")
install(DIRECTORY db/init/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/kompanion/db/init FILES_MATCHING PATTERN "*.sql")
option(BUILD_KOMPANION_CLI "Build Kompanion Qt command-line client" ON) option(BUILD_KOMPANION_CLI "Build Kompanion Qt command-line client" ON)
if (BUILD_KOMPANION_CLI) if (BUILD_KOMPANION_CLI)
find_package(Qt6 COMPONENTS Core QUIET) find_package(Qt6 COMPONENTS Core QUIET)
@ -58,7 +63,10 @@ add_executable(kom_mcp
) )
target_include_directories(kom_mcp PRIVATE src) target_include_directories(kom_mcp PRIVATE src)
target_link_libraries(kom_mcp PRIVATE kom_dal) target_link_libraries(kom_mcp PRIVATE kom_dal)
target_compile_definitions(kom_mcp PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}") target_compile_definitions(kom_mcp PRIVATE
PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
KOMPANION_DB_INIT_INSTALL_DIR="${KOMPANION_DB_INIT_INSTALL_DIR}"
)
if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "") if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "")
target_link_libraries(kom_mcp PRIVATE ${KOMPANION_KCONFIG_TARGET}) target_link_libraries(kom_mcp PRIVATE ${KOMPANION_KCONFIG_TARGET})
target_compile_definitions(kom_mcp PRIVATE HAVE_KCONFIG) target_compile_definitions(kom_mcp PRIVATE HAVE_KCONFIG)
@ -74,7 +82,10 @@ if (BUILD_KOMPANION_CLI)
) )
target_include_directories(kompanion PRIVATE src) target_include_directories(kompanion PRIVATE src)
target_link_libraries(kompanion PRIVATE Qt6::Core kom_dal) target_link_libraries(kompanion PRIVATE Qt6::Core kom_dal)
target_compile_definitions(kompanion PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}") target_compile_definitions(kompanion PRIVATE
PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
KOMPANION_DB_INIT_INSTALL_DIR="${KOMPANION_DB_INIT_INSTALL_DIR}"
)
if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "") if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "")
target_link_libraries(kompanion PRIVATE ${KOMPANION_KCONFIG_TARGET}) target_link_libraries(kompanion PRIVATE ${KOMPANION_KCONFIG_TARGET})
target_compile_definitions(kompanion PRIVATE HAVE_KCONFIG) target_compile_definitions(kompanion PRIVATE HAVE_KCONFIG)

View File

@ -1,59 +0,0 @@
-- metal-kompanion core schema (pgvector)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE IF NOT EXISTS knowledge (
id BIGSERIAL PRIMARY KEY,
source TEXT,
path TEXT,
sha256 TEXT,
lineno INT,
text TEXT NOT NULL,
tags TEXT[],
created_at TIMESTAMPTZ DEFAULT now()
);
-- embeddings: 1024-dim space (extend with more tables if needed)
CREATE TABLE IF NOT EXISTS embeddings_1024 (
id BIGSERIAL PRIMARY KEY,
knowledge_id BIGINT REFERENCES knowledge(id) ON DELETE CASCADE,
model TEXT NOT NULL,
embedding vector(1024) NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS embeddings_1024_l2 ON embeddings_1024 USING ivfflat (embedding vector_l2_ops) WITH (lists=100);
-- memory branches (git-like)
CREATE TABLE IF NOT EXISTS mem_branch (
id BIGSERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
purpose TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS mem_commit (
id BIGSERIAL PRIMARY KEY,
branch_id BIGINT REFERENCES mem_branch(id) ON DELETE CASCADE,
parent_id BIGINT,
author_did TEXT,
message TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS mem_commit_branch ON mem_commit(branch_id);
-- commit deltas referencing knowledge rows
CREATE TABLE IF NOT EXISTS mem_delta (
id BIGSERIAL PRIMARY KEY,
commit_id BIGINT REFERENCES mem_commit(id) ON DELETE CASCADE,
knowledge_id BIGINT REFERENCES knowledge(id) ON DELETE CASCADE,
action SMALLINT NOT NULL CHECK (action IN (0,1,2)) -- 0:add,1:update,2:delete
);
CREATE INDEX IF NOT EXISTS mem_delta_commit ON mem_delta(commit_id);
-- per-branch centroid for fast routing
CREATE TABLE IF NOT EXISTS branch_embedding_1024 (
branch_id BIGINT REFERENCES mem_branch(id) ON DELETE CASCADE,
model TEXT NOT NULL,
embedding vector(1024) NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY(branch_id, model)
);

View File

@ -1,5 +0,0 @@
INSERT INTO komp.space(name, model, dim) VALUES
('dev_knowledge','mxbai-embed-large',1024),
('pattern_exchange','mxbai-embed-large',1024),
('runtime_memory','mxbai-embed-large',1024)
ON CONFLICT (name) DO NOTHING;

View File

@ -1,105 +0,0 @@
-- Requires: CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS ltree;
CREATE SCHEMA IF NOT EXISTS komp;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS ltree;
CREATE TABLE IF NOT EXISTS komp.source (
id BIGSERIAL PRIMARY KEY,
kind TEXT NOT NULL, -- filesystem|repo|url|note
uri TEXT NOT NULL, -- path or URL
repo TEXT,
ref TEXT,
meta JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS komp.chunk (
id BIGSERIAL PRIMARY KEY,
source_id BIGINT REFERENCES komp.source(id) ON DELETE CASCADE,
lineno INT,
text TEXT NOT NULL,
sha256 TEXT NOT NULL,
tokens INT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_chunk_source ON komp.chunk(source_id);
-- A space is a distinct memory with its own model+dim & policy
CREATE TABLE IF NOT EXISTS komp.space (
id SERIAL PRIMARY KEY,
name TEXT UNIQUE, -- dev_knowledge | pattern_exchange | runtime_memory
model TEXT NOT NULL,
dim INT NOT NULL,
metric TEXT NOT NULL DEFAULT 'cosine'
);
-- Embedding tables per common dimension (add more as needed)
CREATE TABLE IF NOT EXISTS komp.embedding_768 (
id BIGSERIAL PRIMARY KEY,
chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
space_id INT REFERENCES komp.space(id) ON DELETE CASCADE,
embedding VECTOR(768) NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(chunk_id, space_id)
);
CREATE INDEX IF NOT EXISTS idx_embed768_space ON komp.embedding_768(space_id);
CREATE INDEX IF NOT EXISTS ivf_embed768 ON komp.embedding_768 USING ivfflat (embedding vector_cosine_ops) WITH (lists=100);
CREATE TABLE IF NOT EXISTS komp.embedding_1024 (
id BIGSERIAL PRIMARY KEY,
chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
space_id INT REFERENCES komp.space(id) ON DELETE CASCADE,
embedding VECTOR(1024) NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(chunk_id, space_id)
);
CREATE INDEX IF NOT EXISTS idx_embed1024_space ON komp.embedding_1024(space_id);
CREATE INDEX IF NOT EXISTS ivf_embed1024 ON komp.embedding_1024 USING ivfflat (embedding vector_cosine_ops) WITH (lists=100);
-- Branch hierarchy (Branch Embeddings): path encodes the cluster tree (e.g., physics.quantum.tunneling)
CREATE TABLE IF NOT EXISTS komp.branch (
id BIGSERIAL PRIMARY KEY,
space_id INT REFERENCES komp.space(id) ON DELETE CASCADE,
path LTREE NOT NULL,
label TEXT,
meta JSONB DEFAULT '{}'::jsonb,
UNIQUE(space_id, path)
);
CREATE INDEX IF NOT EXISTS gist_branch_path ON komp.branch USING GIST (path);
-- Centroids per dimension (store only the dim matching the space)
CREATE TABLE IF NOT EXISTS komp.branch_centroid_768 (
branch_id BIGINT PRIMARY KEY REFERENCES komp.branch(id) ON DELETE CASCADE,
embedding VECTOR(768) NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS komp.branch_centroid_1024 (
branch_id BIGINT PRIMARY KEY REFERENCES komp.branch(id) ON DELETE CASCADE,
embedding VECTOR(1024) NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now()
);
-- Soft membership of chunks to branches
CREATE TABLE IF NOT EXISTS komp.chunk_branch (
chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
branch_id BIGINT REFERENCES komp.branch(id) ON DELETE CASCADE,
weight REAL NOT NULL CHECK (weight >= 0 AND weight <= 1),
PRIMARY KEY(chunk_id, branch_id)
);
-- Relations between chunks (similarity / cites / derives / contradicts / …)
CREATE TABLE IF NOT EXISTS komp.chunk_edge (
src_chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
dst_chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
relation TEXT NOT NULL,
weight REAL,
meta JSONB DEFAULT '{}'::jsonb,
PRIMARY KEY(src_chunk_id, dst_chunk_id, relation)
);
CREATE OR REPLACE VIEW komp.latest_sources AS
SELECT s.*, max(c.created_at) AS last_chunk_at
FROM komp.source s LEFT JOIN komp.chunk c ON c.source_id = s.id
GROUP BY s.id;

View File

@ -1,5 +0,0 @@
-- pgvector knowledge schema (v0.2, branch embeddings)nCREATE EXTENSION IF NOT EXISTS vector;nn-- Documents tracked by content hash; multiple logical paths may point to same blobnCREATE TABLE IF NOT EXISTS doc_blob (n blob_sha256 text PRIMARY KEY,n bytes bigint NOT NULL,n created_at timestamptz DEFAULT now()n);nn-- Logical document identity and branch/commit lineagenCREATE TABLE IF NOT EXISTS doc (n id bigserial PRIMARY KEY,n origin text, -- e.g., filesystem, forgejo, exportn root_path text, -- repo root or base dirn rel_path text, -- path relative to rootn blob_sha256 text REFERENCES doc_blob(blob_sha256)n);nCREATE TABLE IF NOT EXISTS branch (n id bigserial PRIMARY KEY,n name text UNIQUE,n created_at timestamptz DEFAULT now()n);nCREATE TABLE IF NOT EXISTS revision (n id bigserial PRIMARY KEY,n branch_id bigint REFERENCES branch(id) ON DELETE CASCADE,n parent_id bigint REFERENCES revision(id),n commit_sha text, -- optional link to VCSn message text,n created_at timestamptz DEFAULT now()n);nn-- Chunked text with provenance; each revision can re-chunk same docnCREATE TABLE IF NOT EXISTS chunk (n id bigserial PRIMARY KEY,n revision_id bigint REFERENCES revision(id) ON DELETE CASCADE,n doc_id bigint REFERENCES doc(id) ON DELETE CASCADE,n lineno int,n text text NOT NULL,n tags text[],n sha256 text,n created_at timestamptz DEFAULT now()n);nCREATE INDEX IF NOT EXISTS idx_chunk_doc ON chunk(doc_id);nCREATE INDEX IF NOT EXISTS idx_chunk_rev ON chunk(revision_id);nn-- Embedding models registrynCREATE TABLE IF NOT EXISTS embed_model (n id bigserial PRIMARY KEY,n name text UNIQUE NOT NULL, -- e.g., mxbai-embed-largen dims int NOT NULL,n tokenizer text,n notes textn);nn-- Branch embeddings: per revision, per chunk, per model (dims parametrized by table)nCREATE TABLE IF NOT EXISTS embedding_1024 (n id bigserial PRIMARY KEY,n chunk_id bigint REFERENCES chunk(id) ON DELETE CASCADE,n model_id bigint REFERENCES embed_model(id),n embedding vector(1024) NOT NULL,n created_at timestamptz DEFAULT now()n);nCREATE INDEX IF NOT EXISTS idx_emb1024_chunk ON embedding_1024(chunk_id);nCREATE INDEX IF NOT EXISTS idx_emb1024_vec ON embedding_1024 USING ivfflat (embedding vector_l2_ops) WITH (lists=100);nn-- Views: latest chunks per branchnCREATE OR REPLACE VIEW v_latest_chunks AS
SELECT c.* FROM chunk c
JOIN (SELECT revision_id, max(id) over (partition by doc_id, branch_id) as maxid, doc_id
FROM revision r JOIN chunk c2 ON c2.revision_id=r.id) t
ON c.id=t.maxid;nn-- Ledger mirror (optional)nCREATE TABLE IF NOT EXISTS ledger_mirror (n id bigserial PRIMARY KEY,n ts timestamptz NOT NULL,n actor text,n action text,n body jsonbn);n

View File

@ -9,6 +9,19 @@ Kompanion adheres to KDEs KConfig conventions so deployments are kioskable an
The CLI (`kompanion`) and MCP runner (`kom_mcp`) fall back to this entry when the `PG_DSN` environment variable is not set. If neither are present the in-memory DAL stub is used. The CLI (`kompanion`) and MCP runner (`kom_mcp`) fall back to this entry when the `PG_DSN` environment variable is not set. If neither are present the in-memory DAL stub is used.
## Initialization Wizard
- Run `kompanion --init` to launch an interactive wizard.
- Autodetects reachable Postgres instances (tries `postgresql://kompanion:komup@localhost/kompanion_test`).
- Prompts for host, port, database, user, password, or Unix socket path with sensible defaults.
- Writes the resulting DSN to `kompanionrc` and exports `PG_DSN` for the current session.
- If the target database is empty, it applies the SQL migrations shipped under `share/kompanion/db/init/*.sql`.
- The wizard is also triggered automatically the first time you run `kompanion` without a configured DSN.
## CLI Modes
- Standard invocation: `kompanion <tool> --request payload.json`
- Interactive prompt: `kompanion -I <tool>` keeps a REPL open; enter JSON payloads or `!prompt text` to wrap plain text. Use `-V/--verbose` to echo request/response JSON streams.
- Use `kompanion --list` to enumerate available tools, including `kom.meta.v1.project_snapshot` for quick project context dumps.
## Future HTTP Streaming ## Future HTTP Streaming
While current tooling focuses on stdio dispatch (for editor and agent integration), the roadmap includes an HTTP/2 or WebSocket streaming surface so MCP clients can maintain persistent conversations without leaving CLI compatibility behind. The same configuration keys will apply for both transports. While current tooling focuses on stdio dispatch (for editor and agent integration), the roadmap includes an HTTP/2 or WebSocket streaming surface so MCP clients can maintain persistent conversations without leaving CLI compatibility behind. The same configuration keys will apply for both transports.

View File

@ -73,6 +73,7 @@
- **Observability**: CLI should read the `jobs/semantic_sync` state block to display cursors, pending counts, and last error logs; dry-run mode estimates embeddings without committing. - **Observability**: CLI should read the `jobs/semantic_sync` state block to display cursors, pending counts, and last error logs; dry-run mode estimates embeddings without committing.
- **Activation parity**: Long term, mirror the KDE `akonadiclient`/`akonadi-console` pattern—Kompanion CLI doubles as an MCP surface today and later as a DBus-activated helper so tools can be socket-triggered into the memory service. - **Activation parity**: Long term, mirror the KDE `akonadiclient`/`akonadi-console` pattern—Kompanion CLI doubles as an MCP surface today and later as a DBus-activated helper so tools can be socket-triggered into the memory service.
- **KConfig defaults**: `kom_mcp` and `kompanion` load `Database/PgDsn` from `~/.config/kompanionrc` (see `docs/configuration.md`) when `PG_DSN` is unset, keeping deployments kioskable. - **KConfig defaults**: `kom_mcp` and `kompanion` load `Database/PgDsn` from `~/.config/kompanionrc` (see `docs/configuration.md`) when `PG_DSN` is unset, keeping deployments kioskable.
- **CLI UX**: `kompanion --init` guides first-run setup (auto-detects databases, applies schemas); `-I/--interactive` keeps a JSON REPL open, and `-V/--verbose` echoes request/response streams for future HTTP transport parity.
## Next-Step Checklist ## Next-Step Checklist
- [x] Detect pqxx via CMake and plumb `HAVE_PG`. - [x] Detect pqxx via CMake and plumb `HAVE_PG`.