Extend command line and add db init.
This also removes obsolete schema files for clarity
This commit is contained in:
parent
e881bc4998
commit
a04506a081
|
|
@ -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)
|
||||||
|
|
|
||||||
59
db/core.sql
59
db/core.sql
|
|
@ -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)
|
|
||||||
);
|
|
||||||
|
|
@ -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;
|
|
||||||
105
db/schema.sql
105
db/schema.sql
|
|
@ -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;
|
|
||||||
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -9,6 +9,19 @@ Kompanion adheres to KDE’s 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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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`.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue