WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
DROP TABLE IF EXISTS tenant_invitations;
DROP TABLE IF EXISTS tenant_api_keys;
DROP TABLE IF EXISTS wiki_page_revisions;
DROP TABLE IF EXISTS wiki_page_issues;
DROP TABLE IF EXISTS wiki_pages;
DROP TABLE IF EXISTS wiki_folders;
DROP TABLE IF EXISTS user_kb_pins;
DROP TABLE IF EXISTS user_resource_favorites;
DROP TABLE IF EXISTS tenant_disabled_shared_agents;
DROP TABLE IF EXISTS agent_shares;
DROP TABLE IF EXISTS organization_join_requests;
DROP TABLE IF EXISTS kb_shares;
DROP TABLE IF EXISTS organization_tenant_members;
DROP TABLE IF EXISTS organizations;
DROP TABLE IF EXISTS custom_agents;
DROP TABLE IF EXISTS mcp_tool_approvals;
DROP TABLE IF EXISTS mcp_services;
DROP TABLE IF EXISTS knowledge_tags;
DROP TABLE IF EXISTS auth_tokens;
DROP TABLE IF EXISTS audit_logs;
DROP TABLE IF EXISTS tenant_members;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS chunks;
DROP TABLE IF EXISTS messages;
DROP TABLE IF EXISTS temporary_documents;
DROP TABLE IF EXISTS sessions;
DROP TABLE IF EXISTS knowledges;
DROP TABLE IF EXISTS knowledge_bases;
DROP TABLE IF EXISTS storage_backends;
DROP TABLE IF EXISTS resource_access_grants;
DROP TABLE IF EXISTS resource_bindings;
DROP TABLE IF EXISTS resources;
DROP TABLE IF EXISTS models;
DROP TABLE IF EXISTS tenants;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS wiki_log_entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant_id INTEGER NOT NULL,
knowledge_base_id VARCHAR(36) NOT NULL,
action VARCHAR(32) NOT NULL,
knowledge_id VARCHAR(36) NOT NULL DEFAULT '',
doc_title TEXT NOT NULL DEFAULT '',
summary TEXT NOT NULL DEFAULT '',
pages_affected TEXT NOT NULL DEFAULT '[]',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_wiki_log_entries_kb_id_desc
ON wiki_log_entries (knowledge_base_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_wiki_log_entries_tenant_id
ON wiki_log_entries (tenant_id);
@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS wiki_log_entries;
DELETE FROM wiki_pages WHERE page_type = 'log';
@@ -0,0 +1,8 @@
-- Fold the relative directory back into file_name before dropping the column.
UPDATE knowledges
SET file_name = folder_path || '/' || file_name
WHERE folder_path <> '' AND file_name <> '';
DROP INDEX IF EXISTS idx_knowledges_folder_path;
ALTER TABLE knowledges DROP COLUMN folder_path;
@@ -0,0 +1,23 @@
-- Folder tree support for knowledge bases (SQLite / lite mode).
--
-- Mirrors migrations/versioned/000079_knowledge_folder_path.up.sql.
ALTER TABLE knowledges ADD COLUMN folder_path VARCHAR(1024) NOT NULL DEFAULT '';
-- Backfill legacy folder uploads, which encoded their relative directory in
-- file_name. SQLite has no regex, so the directory prefix is isolated with the
-- rtrim trick: trimming every non-slash character off the right leaves exactly
-- the prefix up to and including the last '/'.
UPDATE knowledges
SET folder_path = substr(
rtrim(file_name, replace(file_name, '/', '')),
1,
length(rtrim(file_name, replace(file_name, '/', ''))) - 1
),
file_name = substr(
file_name,
length(rtrim(file_name, replace(file_name, '/', ''))) + 1
)
WHERE file_name LIKE '%/%';
CREATE INDEX IF NOT EXISTS idx_knowledges_folder_path
ON knowledges (tenant_id, knowledge_base_id, folder_path);
@@ -0,0 +1 @@
ALTER TABLE knowledge_bases DROP COLUMN auto_tag_config;
@@ -0,0 +1 @@
ALTER TABLE knowledge_bases ADD COLUMN auto_tag_config TEXT;
+13
View File
@@ -0,0 +1,13 @@
DROP TABLE IF EXISTS memory_item_embeddings;
DROP INDEX IF EXISTS idx_mem_affinity_scope;
DROP TABLE IF EXISTS memory_doc_affinity;
DROP INDEX IF EXISTS idx_mem_topic_scope;
DROP TABLE IF EXISTS memory_topic_stats;
DROP INDEX IF EXISTS idx_memory_items_key;
DROP INDEX IF EXISTS idx_memory_items_scope;
DROP TABLE IF EXISTS memory_items;
DROP INDEX IF EXISTS idx_mem_tomb_fp;
DROP INDEX IF EXISTS idx_memory_tombstones_scope;
DROP TABLE IF EXISTS memory_tombstones;
DROP INDEX IF EXISTS idx_memory_subjects_scope;
DROP TABLE IF EXISTS memory_subjects;
+118
View File
@@ -0,0 +1,118 @@
-- Cross-session long-term memory (Lite). Mirrors migrations/versioned/000084.
-- Row ids are generated in Go, so there is no server-side default here.
CREATE TABLE IF NOT EXISTS memory_subjects (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT 1,
block_text TEXT NOT NULL DEFAULT '',
block_updated_at DATETIME,
item_count INTEGER NOT NULL DEFAULT 0,
last_extracted_at DATETIME,
extract_cursor DATETIME,
pending_sessions TEXT,
extract_scheduled_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_subjects_scope
ON memory_subjects (tenant_id, subject_id);
CREATE TABLE IF NOT EXISTS memory_items (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
kind VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
topic VARCHAR(255) NOT NULL DEFAULT '',
normalized_key VARCHAR(255) NOT NULL DEFAULT '',
importance INTEGER NOT NULL DEFAULT 3,
origin VARCHAR(16) NOT NULL DEFAULT 'extracted',
status VARCHAR(16) NOT NULL DEFAULT 'active',
source_session_id VARCHAR(36),
source_message_id VARCHAR(36),
valid_from DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
invalid_at DATETIME,
expires_at DATETIME,
superseded_by VARCHAR(36),
last_used_at DATETIME,
use_count INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_memory_items_scope
ON memory_items (tenant_id, subject_id, status);
CREATE INDEX IF NOT EXISTS idx_memory_items_key
ON memory_items (tenant_id, subject_id, normalized_key);
CREATE TABLE IF NOT EXISTS memory_tombstones (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
topic VARCHAR(255) NOT NULL DEFAULT '',
fingerprint VARCHAR(64) NOT NULL,
source_message_id VARCHAR(36),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_memory_tombstones_scope
ON memory_tombstones (tenant_id, subject_id);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mem_tomb_fp
ON memory_tombstones (tenant_id, subject_id, fingerprint);
CREATE TABLE IF NOT EXISTS memory_topic_stats (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
normalized_key VARCHAR(255) NOT NULL,
topic VARCHAR(255) NOT NULL DEFAULT '',
hits INTEGER NOT NULL DEFAULT 0,
last_seen_at DATETIME,
promoted_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mem_topic_scope
ON memory_topic_stats (tenant_id, subject_id, normalized_key);
CREATE TABLE IF NOT EXISTS memory_doc_affinity (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
knowledge_id VARCHAR(36) NOT NULL,
knowledge_base_id VARCHAR(36) NOT NULL DEFAULT '',
title VARCHAR(512) NOT NULL DEFAULT '',
hits INTEGER NOT NULL DEFAULT 0,
last_used_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mem_affinity_scope
ON memory_doc_affinity (tenant_id, subject_id, knowledge_id);
ALTER TABLE tenants ADD COLUMN memory_config TEXT;
ALTER TABLE messages ADD COLUMN used_memories TEXT;
ALTER TABLE memory_subjects ADD COLUMN consolidated_at DATETIME;
ALTER TABLE memory_subjects ADD COLUMN forced_consolidated_at DATETIME;
ALTER TABLE memory_topic_stats ADD COLUMN aliases TEXT NOT NULL DEFAULT '[]';
CREATE TABLE IF NOT EXISTS memory_item_embeddings (
item_id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
subject_id VARCHAR(512) NOT NULL,
model_id VARCHAR(64) NOT NULL DEFAULT '',
dims INTEGER NOT NULL DEFAULT 0,
vector BLOB,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_mem_emb_scope
ON memory_item_embeddings (tenant_id, subject_id);
@@ -0,0 +1,15 @@
DROP INDEX IF EXISTS idx_tenant_invitations_token;
DROP INDEX IF EXISTS idx_tenant_invitations_unique_pending;
-- Legacy unique index cannot coexist with multiple share-link rows.
DELETE FROM tenant_invitations
WHERE invitee_user_id = ''
AND deleted_at IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_tenant_invitations_unique_pending
ON tenant_invitations(tenant_id, invitee_user_id)
WHERE status = 'pending' AND deleted_at IS NULL;
ALTER TABLE tenant_invitations DROP COLUMN accepted_count;
ALTER TABLE tenant_invitations DROP COLUMN token;
ALTER TABLE messages DROP COLUMN attachments;
@@ -0,0 +1,21 @@
-- Mirrors versioned migrations:
-- 000034_add_attachments messages.attachments
-- 000054_invitation_tokens tenant_invitations.token / accepted_count
ALTER TABLE messages ADD COLUMN attachments TEXT NOT NULL DEFAULT '[]';
ALTER TABLE tenant_invitations ADD COLUMN token VARCHAR(64) NOT NULL DEFAULT '';
ALTER TABLE tenant_invitations ADD COLUMN accepted_count INTEGER NOT NULL DEFAULT 0;
-- Share-link rows use invitee_user_id=''; relax the pending uniqueness index
-- so multiple share links can coexist on one tenant (see versioned 000054).
DROP INDEX IF EXISTS idx_tenant_invitations_unique_pending;
CREATE UNIQUE INDEX IF NOT EXISTS idx_tenant_invitations_unique_pending
ON tenant_invitations(tenant_id, invitee_user_id)
WHERE status = 'pending'
AND deleted_at IS NULL
AND invitee_user_id <> '';
CREATE UNIQUE INDEX IF NOT EXISTS idx_tenant_invitations_token
ON tenant_invitations(token)
WHERE token <> '' AND deleted_at IS NULL;
@@ -0,0 +1,8 @@
DROP INDEX IF EXISTS idx_task_dead_letters_task_type;
DROP INDEX IF EXISTS idx_task_dead_letters_tenant;
DROP INDEX IF EXISTS idx_task_dead_letters_scope;
DROP INDEX IF EXISTS idx_task_pending_ops_tenant;
DROP INDEX IF EXISTS idx_task_pending_ops_scope;
DROP TABLE IF EXISTS task_dead_letters;
DROP TABLE IF EXISTS task_pending_ops;
@@ -0,0 +1,44 @@
-- Mirrors versioned migration 000041_task_queue_and_wiki_indexes:
-- durable pending-op queue and dead-letter archive for SQLite.
CREATE TABLE IF NOT EXISTS task_pending_ops (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant_id INTEGER NOT NULL,
task_type VARCHAR(64) NOT NULL,
scope VARCHAR(32) NOT NULL,
scope_id VARCHAR(64) NOT NULL,
op VARCHAR(32) NOT NULL,
dedup_key VARCHAR(128) NOT NULL DEFAULT '',
payload TEXT NOT NULL DEFAULT '{}',
fail_count INTEGER NOT NULL DEFAULT 0,
enqueued_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
claimed_at DATETIME
);
CREATE INDEX IF NOT EXISTS idx_task_pending_ops_scope
ON task_pending_ops (task_type, scope, scope_id, id);
CREATE INDEX IF NOT EXISTS idx_task_pending_ops_tenant
ON task_pending_ops (tenant_id);
CREATE TABLE IF NOT EXISTS task_dead_letters (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant_id INTEGER NOT NULL,
task_type VARCHAR(64) NOT NULL,
scope VARCHAR(32) NOT NULL,
scope_id VARCHAR(64) NOT NULL,
related_id VARCHAR(64) NOT NULL DEFAULT '',
payload TEXT NOT NULL,
last_error TEXT NOT NULL DEFAULT '',
fail_count INTEGER NOT NULL,
failed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_task_dead_letters_scope
ON task_dead_letters (scope, scope_id, failed_at DESC);
CREATE INDEX IF NOT EXISTS idx_task_dead_letters_tenant
ON task_dead_letters (tenant_id, failed_at DESC);
CREATE INDEX IF NOT EXISTS idx_task_dead_letters_task_type
ON task_dead_letters (task_type, failed_at DESC);
@@ -0,0 +1,4 @@
DROP INDEX IF EXISTS idx_system_settings_category;
DROP TABLE IF EXISTS system_settings;
DROP INDEX IF EXISTS idx_users_is_system_admin;
ALTER TABLE users DROP COLUMN is_system_admin;
@@ -0,0 +1,22 @@
-- Mirrors versioned migration 000053_system_admin_and_settings:
-- users.is_system_admin + system_settings table.
ALTER TABLE users ADD COLUMN is_system_admin BOOLEAN NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS idx_users_is_system_admin ON users (is_system_admin);
CREATE TABLE IF NOT EXISTS system_settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key VARCHAR(128) NOT NULL UNIQUE,
value TEXT NOT NULL,
value_type VARCHAR(16) NOT NULL,
category VARCHAR(32) NOT NULL,
description TEXT NOT NULL DEFAULT '',
is_secret BOOLEAN NOT NULL DEFAULT 0,
requires_restart BOOLEAN NOT NULL DEFAULT 0,
last_modified_by VARCHAR(36) NOT NULL DEFAULT '',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_system_settings_category
ON system_settings (category);
@@ -0,0 +1,6 @@
ALTER TABLE knowledges DROP COLUMN pending_subtasks_count;
DROP INDEX IF EXISTS idx_kpspan_parent;
DROP INDEX IF EXISTS idx_kpspan_status_started;
DROP INDEX IF EXISTS idx_kpspan_knowledge_attempt;
DROP TABLE IF EXISTS knowledge_processing_spans;
@@ -0,0 +1,39 @@
-- Mirrors versioned migrations:
-- 000055_knowledge_processing_spans knowledge_processing_spans table
-- 000056_knowledge_pending_subtasks knowledges.pending_subtasks_count
-- 000066_expand_knowledge_span_name name VARCHAR(255)
CREATE TABLE IF NOT EXISTS knowledge_processing_spans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
knowledge_id VARCHAR(64) NOT NULL,
attempt INTEGER NOT NULL DEFAULT 1,
span_id VARCHAR(64) NOT NULL,
parent_span_id VARCHAR(64),
name VARCHAR(255) NOT NULL,
kind VARCHAR(16) NOT NULL,
status VARCHAR(16) NOT NULL,
input TEXT,
output TEXT,
metadata TEXT,
error_code VARCHAR(64),
error_message TEXT,
error_detail TEXT,
started_at DATETIME,
finished_at DATETIME,
duration_ms INTEGER,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_kpspan_attempt_span UNIQUE (knowledge_id, attempt, span_id)
);
CREATE INDEX IF NOT EXISTS idx_kpspan_knowledge_attempt
ON knowledge_processing_spans (knowledge_id, attempt);
CREATE INDEX IF NOT EXISTS idx_kpspan_status_started
ON knowledge_processing_spans (status, started_at);
CREATE INDEX IF NOT EXISTS idx_kpspan_parent
ON knowledge_processing_spans (parent_span_id)
WHERE parent_span_id IS NOT NULL;
ALTER TABLE knowledges ADD COLUMN pending_subtasks_count INTEGER NOT NULL DEFAULT 0;
@@ -0,0 +1 @@
ALTER TABLE embed_channels DROP COLUMN allow_memory;
@@ -0,0 +1,3 @@
-- Mirrors versioned migration 000060_embed_channels: embed_channels.allow_memory.
ALTER TABLE embed_channels ADD COLUMN allow_memory BOOLEAN NOT NULL DEFAULT 0;
@@ -0,0 +1,18 @@
ALTER TABLE knowledges ADD COLUMN tag_id VARCHAR(36);
CREATE INDEX IF NOT EXISTS idx_knowledges_tag ON knowledges(tag_id);
UPDATE knowledges
SET tag_id = (
SELECT ktr.tag_id
FROM knowledge_tag_relations ktr
WHERE ktr.knowledge_id = knowledges.id
ORDER BY ktr.created_at ASC
LIMIT 1
)
WHERE EXISTS (
SELECT 1 FROM knowledge_tag_relations ktr WHERE ktr.knowledge_id = knowledges.id
);
DROP INDEX IF EXISTS idx_ktr_tag;
DROP INDEX IF EXISTS idx_ktr_knowledge;
DROP TABLE IF EXISTS knowledge_tag_relations;
@@ -0,0 +1,25 @@
-- Mirrors versioned migration 000063_knowledge_multi_tags:
-- many-to-many join table between knowledges and knowledge_tags.
CREATE TABLE IF NOT EXISTS knowledge_tag_relations (
knowledge_id VARCHAR(36) NOT NULL,
tag_id VARCHAR(36) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (knowledge_id, tag_id)
);
CREATE INDEX IF NOT EXISTS idx_ktr_knowledge
ON knowledge_tag_relations (knowledge_id);
CREATE INDEX IF NOT EXISTS idx_ktr_tag
ON knowledge_tag_relations (tag_id);
-- Migrate existing single-tag data into the join table.
INSERT INTO knowledge_tag_relations (knowledge_id, tag_id, created_at)
SELECT id, tag_id, updated_at
FROM knowledges
WHERE tag_id IS NOT NULL AND tag_id != ''
AND deleted_at IS NULL;
DROP INDEX IF EXISTS idx_knowledges_tag;
ALTER TABLE knowledges DROP COLUMN tag_id;
@@ -0,0 +1,9 @@
DROP INDEX IF EXISTS idx_mcp_oauth_tokens_principal;
DROP INDEX IF EXISTS idx_mcp_oauth_tokens_tenant_principal_svc;
CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_tenant_user_svc
ON mcp_oauth_tokens(tenant_id, user_id, service_id);
ALTER TABLE mcp_oauth_tokens DROP COLUMN principal_id;
ALTER TABLE mcp_oauth_tokens DROP COLUMN principal_type;
ALTER TABLE tenants DROP COLUMN api_principal_config;
@@ -0,0 +1,22 @@
-- Mirrors versioned migration 000064_principal_model:
-- principal identity for MCP OAuth tokens and tenant API config.
ALTER TABLE tenants ADD COLUMN api_principal_config TEXT;
ALTER TABLE mcp_oauth_tokens ADD COLUMN principal_type VARCHAR(32);
ALTER TABLE mcp_oauth_tokens ADD COLUMN principal_id VARCHAR(512);
UPDATE mcp_oauth_tokens
SET principal_type = 'web_user',
principal_id = user_id
WHERE (principal_type IS NULL OR principal_type = '')
AND user_id IS NOT NULL
AND user_id <> '';
DROP INDEX IF EXISTS idx_mcp_oauth_tokens_tenant_user_svc;
CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_tenant_principal_svc
ON mcp_oauth_tokens(tenant_id, principal_type, principal_id, service_id);
CREATE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_principal
ON mcp_oauth_tokens(principal_type, principal_id);
@@ -0,0 +1 @@
ALTER TABLE messages DROP COLUMN usage;
@@ -0,0 +1,4 @@
-- Mirrors versioned migration 000085_message_usage:
-- per-turn LLM token usage persisted with the assistant message.
ALTER TABLE messages ADD COLUMN usage TEXT;
@@ -0,0 +1,4 @@
DROP TABLE IF EXISTS workbench_events;
DROP TABLE IF EXISTS workbench_jobs;
DROP TABLE IF EXISTS workbench_revisions;
DROP TABLE IF EXISTS workbench_resources;
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS workbench_resources (id TEXT PRIMARY KEY, tenant_id INTEGER NOT NULL, owner_id TEXT NOT NULL, owner_name TEXT NOT NULL DEFAULT '', kind TEXT NOT NULL, name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'draft', version INTEGER NOT NULL DEFAULT 1, data TEXT NOT NULL DEFAULT '{}', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE INDEX IF NOT EXISTS wb_resource_scope ON workbench_resources(tenant_id,kind,owner_id);
CREATE TABLE IF NOT EXISTS workbench_revisions (id TEXT PRIMARY KEY, tenant_id INTEGER NOT NULL, resource_id TEXT NOT NULL, version INTEGER NOT NULL, actor_id TEXT NOT NULL, data TEXT NOT NULL DEFAULT '{}', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE(resource_id,version));
CREATE TABLE IF NOT EXISTS workbench_jobs (id TEXT PRIMARY KEY, tenant_id INTEGER NOT NULL, owner_id TEXT NOT NULL, resource_id TEXT NOT NULL, kind TEXT NOT NULL, action TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'queued', progress INTEGER NOT NULL DEFAULT 0, stage TEXT NOT NULL DEFAULT '', error TEXT NOT NULL DEFAULT '', request TEXT NOT NULL DEFAULT '{}', lease_token TEXT NOT NULL DEFAULT '', lease_until DATETIME, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE INDEX IF NOT EXISTS wb_job_queue ON workbench_jobs(status,created_at);
CREATE TABLE IF NOT EXISTS workbench_events (id TEXT PRIMARY KEY, tenant_id INTEGER NOT NULL, owner_id TEXT NOT NULL, resource_id TEXT NOT NULL DEFAULT '', action TEXT NOT NULL, message TEXT NOT NULL DEFAULT '', level TEXT NOT NULL DEFAULT 'info', read INTEGER NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE INDEX IF NOT EXISTS wb_event_inbox ON workbench_events(tenant_id,owner_id,read,created_at);
@@ -0,0 +1 @@
ALTER TABLE workbench_jobs DROP COLUMN generation;
@@ -0,0 +1 @@
ALTER TABLE workbench_jobs ADD COLUMN generation TEXT NOT NULL DEFAULT '{}';
@@ -0,0 +1,7 @@
CREATE UNIQUE INDEX uq_tenant_skill_catalog_legacy_check ON tenant_skill_catalog(tenant_id, name) WHERE deleted_at IS NULL;
DROP INDEX uq_tenant_instruction_skill_owner_name;
DROP INDEX uq_tenant_skill_catalog_name;
CREATE UNIQUE INDEX uq_tenant_skill_catalog_name ON tenant_skill_catalog(tenant_id, name) WHERE deleted_at IS NULL;
DROP INDEX uq_tenant_skill_catalog_legacy_check;
ALTER TABLE tenant_skill_catalog DROP COLUMN instruction_only;
ALTER TABLE tenant_skill_catalog DROP COLUMN created_by;
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS tenant_skill_catalog (
id TEXT PRIMARY KEY, tenant_id INTEGER NOT NULL, name TEXT NOT NULL,
version TEXT, description TEXT, instructions TEXT, bundle_ref TEXT, bundle_sha256 TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at DATETIME
);
ALTER TABLE tenant_skill_catalog ADD COLUMN instruction_only INTEGER NOT NULL DEFAULT 0;
ALTER TABLE tenant_skill_catalog ADD COLUMN created_by TEXT NOT NULL DEFAULT '';
DROP INDEX IF EXISTS uq_tenant_skill_catalog_name;
CREATE UNIQUE INDEX uq_tenant_skill_catalog_name ON tenant_skill_catalog(tenant_id, name) WHERE deleted_at IS NULL AND instruction_only = 0;
CREATE UNIQUE INDEX uq_tenant_instruction_skill_owner_name ON tenant_skill_catalog(tenant_id, created_by, name) WHERE deleted_at IS NULL AND instruction_only = 1;
@@ -0,0 +1 @@
DROP TABLE IF EXISTS wiki_ingest_checkpoints;
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS wiki_ingest_checkpoints (
tenant_id INTEGER NOT NULL,
knowledge_base_id TEXT NOT NULL,
knowledge_id TEXT NOT NULL,
fingerprint TEXT NOT NULL,
stage TEXT NOT NULL,
item_key TEXT NOT NULL,
payload TEXT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (tenant_id, knowledge_base_id, knowledge_id, fingerprint, stage, item_key)
);
@@ -0,0 +1 @@
DROP TABLE IF EXISTS wiki_recovery_budgets;
@@ -0,0 +1,26 @@
CREATE TABLE IF NOT EXISTS wiki_recovery_budgets (
tenant_id BIGINT NOT NULL,
dead_letter_id BIGINT NOT NULL,
attempt_number INTEGER NOT NULL,
pending_op_id BIGINT NOT NULL,
knowledge_base_id VARCHAR(36) NOT NULL,
knowledge_id VARCHAR(36) NOT NULL,
model_id VARCHAR(36) NOT NULL,
embedding_model_id VARCHAR(36) NOT NULL DEFAULT '',
source_fingerprint VARCHAR(64) NOT NULL,
model_fingerprint VARCHAR(64) NOT NULL,
reviewed_release VARCHAR(255) NOT NULL,
reviewed_api_image VARCHAR(255) NOT NULL,
max_provider_requests BIGINT NOT NULL CHECK (max_provider_requests > 0),
reserved_provider_requests BIGINT NOT NULL DEFAULT 0 CHECK (reserved_provider_requests >= 0 AND reserved_provider_requests <= max_provider_requests),
deadline_at DATETIME NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'active',
stop_reason VARCHAR(128) NOT NULL DEFAULT '',
last_phase VARCHAR(64) NOT NULL DEFAULT '',
paused_payload TEXT NOT NULL,
verified_progress TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (tenant_id, dead_letter_id, attempt_number, pending_op_id),
UNIQUE (tenant_id, pending_op_id)
);
@@ -0,0 +1 @@
ALTER TABLE workbench_access_roles DROP COLUMN permission_version;
@@ -0,0 +1,15 @@
-- The SQLite baseline predates the access-role table.
CREATE TABLE IF NOT EXISTS workbench_access_roles (
id TEXT PRIMARY KEY,
tenant_id INTEGER NOT NULL,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
permissions TEXT NOT NULL DEFAULT '[]',
version INTEGER NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (tenant_id, name)
);
-- Preserve legacy role expansion until the role is explicitly saved.
ALTER TABLE workbench_access_roles
ADD COLUMN permission_version INTEGER NOT NULL DEFAULT 0;
@@ -0,0 +1,9 @@
DROP INDEX IF EXISTS idx_memory_extraction_due;
ALTER TABLE memory_subjects DROP COLUMN extract_attempt_id;
ALTER TABLE memory_subjects DROP COLUMN extract_lease_until;
ALTER TABLE memory_subjects DROP COLUMN extract_started_at;
ALTER TABLE memory_subjects DROP COLUMN extract_next_at;
ALTER TABLE memory_subjects DROP COLUMN extract_failures;
ALTER TABLE memory_subjects DROP COLUMN extract_chat_model_id;
ALTER TABLE memory_subjects DROP COLUMN extract_language;
ALTER TABLE memory_subjects DROP COLUMN session_cursors;
@@ -0,0 +1,9 @@
ALTER TABLE memory_subjects ADD COLUMN session_cursors JSON;
ALTER TABLE memory_subjects ADD COLUMN extract_attempt_id VARCHAR(36) NOT NULL DEFAULT '';
ALTER TABLE memory_subjects ADD COLUMN extract_lease_until DATETIME;
ALTER TABLE memory_subjects ADD COLUMN extract_started_at DATETIME;
ALTER TABLE memory_subjects ADD COLUMN extract_next_at DATETIME;
ALTER TABLE memory_subjects ADD COLUMN extract_failures INTEGER NOT NULL DEFAULT 0;
ALTER TABLE memory_subjects ADD COLUMN extract_chat_model_id VARCHAR(64) NOT NULL DEFAULT '';
ALTER TABLE memory_subjects ADD COLUMN extract_language VARCHAR(64) NOT NULL DEFAULT '';
CREATE INDEX idx_memory_extraction_due ON memory_subjects(extract_next_at);