fix: MCP servers — broken INSERT into dropped type column, stale content refs
The previous schema sync (86f43c9) was incomplete — it renamed variables
but left the SQL statements writing to `type` and `content` columns that
no longer exist in the schema. Fresh installs crash on first node create.
nodeService.js:
- Remove `type` from INSERT/UPDATE, replace with `event_date`
- Fix `content` → `notes` in INSERT values and UPDATE SET clauses
- Add `sanitizeTitle()` and chunk fallback logic
sqlite-client.js:
- Remove `is_pinned` from CREATE TABLE
- Add `description` and `icon` to dimensions table
index.js:
- Add temporal filter fields to search schema
- Improved description prompts
- Dynamic date injection in instructions
server.js + stdio-server.js:
- Add content→notes mapping in update handlers
- Fix output returning `notes` instead of `content`
- Add extraction tool schemas and handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
2f6518207d
commit
7c6197fc0d
@@ -90,38 +90,61 @@ function getNodeById(id) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize title — strip extraction artifacts.
|
||||
*/
|
||||
function sanitizeTitle(title) {
|
||||
let clean = title.trim();
|
||||
if (clean.startsWith('Title: ')) clean = clean.slice(7);
|
||||
if (clean.endsWith(' / X')) clean = clean.slice(0, -4);
|
||||
clean = clean.replace(/\s+/g, ' ');
|
||||
return clean.slice(0, 160);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new node.
|
||||
*/
|
||||
function createNode(nodeData) {
|
||||
const {
|
||||
title,
|
||||
title: rawTitle,
|
||||
description,
|
||||
notes,
|
||||
link,
|
||||
type,
|
||||
event_date,
|
||||
dimensions = [],
|
||||
chunk,
|
||||
metadata = {}
|
||||
} = nodeData;
|
||||
|
||||
const title = sanitizeTitle(rawTitle);
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const db = getDb();
|
||||
|
||||
// Build chunk fallback from available fields when no explicit chunk provided
|
||||
let chunkToStore = chunk ?? null;
|
||||
if (!chunkToStore || !chunkToStore.trim()) {
|
||||
const fallbackParts = [title, description, notes].filter(Boolean);
|
||||
const fallback = fallbackParts.join('\n\n').trim();
|
||||
if (fallback) {
|
||||
chunkToStore = fallback;
|
||||
}
|
||||
}
|
||||
|
||||
const nodeId = transaction(() => {
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO nodes (title, description, notes, link, type, metadata, chunk, created_at, updated_at)
|
||||
INSERT INTO nodes (title, description, notes, link, event_date, metadata, chunk, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`);
|
||||
|
||||
const result = stmt.run(
|
||||
title,
|
||||
description ?? null,
|
||||
content ?? null,
|
||||
notes ?? null,
|
||||
link ?? null,
|
||||
type ?? null,
|
||||
event_date ?? null,
|
||||
JSON.stringify(metadata),
|
||||
chunk ?? null,
|
||||
chunkToStore,
|
||||
now,
|
||||
now
|
||||
);
|
||||
@@ -146,11 +169,11 @@ function createNode(nodeData) {
|
||||
|
||||
/**
|
||||
* Update an existing node.
|
||||
* Note: content is APPENDED by default (MCP tool behavior), not replaced.
|
||||
* Note: notes is APPENDED by default (MCP tool behavior), not replaced.
|
||||
*/
|
||||
function updateNode(id, updates, options = {}) {
|
||||
const { appendNotes = true } = options;
|
||||
const { title, description, notes, link, type, dimensions, chunk, metadata } = updates;
|
||||
const { title, description, notes, link, event_date, dimensions, chunk, metadata } = updates;
|
||||
const now = new Date().toISOString();
|
||||
const db = getDb();
|
||||
|
||||
@@ -172,23 +195,23 @@ function updateNode(id, updates, options = {}) {
|
||||
setFields.push('description = ?');
|
||||
params.push(description);
|
||||
}
|
||||
if (content !== undefined) {
|
||||
if (notes !== undefined) {
|
||||
if (appendNotes && existing.notes) {
|
||||
// Append to existing content
|
||||
setFields.push('content = ?');
|
||||
params.push(existing.notes + '\n\n' + content);
|
||||
// Append to existing notes
|
||||
setFields.push('notes = ?');
|
||||
params.push(existing.notes + '\n\n' + notes);
|
||||
} else {
|
||||
setFields.push('content = ?');
|
||||
params.push(content);
|
||||
setFields.push('notes = ?');
|
||||
params.push(notes);
|
||||
}
|
||||
}
|
||||
if (link !== undefined) {
|
||||
setFields.push('link = ?');
|
||||
params.push(link);
|
||||
}
|
||||
if (type !== undefined) {
|
||||
setFields.push('type = ?');
|
||||
params.push(type);
|
||||
if (event_date !== undefined) {
|
||||
setFields.push('event_date = ?');
|
||||
params.push(event_date);
|
||||
}
|
||||
if (chunk !== undefined) {
|
||||
setFields.push('chunk = ?');
|
||||
|
||||
@@ -60,8 +60,7 @@ function initDatabase() {
|
||||
embedding BLOB,
|
||||
embedding_updated_at TEXT,
|
||||
embedding_text TEXT,
|
||||
chunk_status TEXT DEFAULT 'not_chunked',
|
||||
is_pinned INTEGER DEFAULT 0
|
||||
chunk_status TEXT DEFAULT 'not_chunked'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS edges (
|
||||
@@ -71,7 +70,6 @@ function initDatabase() {
|
||||
source TEXT,
|
||||
created_at TEXT,
|
||||
context TEXT,
|
||||
|
||||
FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (to_node_id) REFERENCES nodes(id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -89,6 +87,8 @@ function initDatabase() {
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dimensions (
|
||||
name TEXT PRIMARY KEY,
|
||||
description TEXT,
|
||||
icon TEXT,
|
||||
is_priority INTEGER DEFAULT 0,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user