dbrain 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +205 -0
- package/dist/cli/connect.d.ts +2 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +108 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +46 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +177 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/start.d.ts +2 -0
- package/dist/cli/start.d.ts.map +1 -0
- package/dist/cli/start.js +33 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/status.d.ts +2 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +30 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +24 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/db.d.ts +4 -0
- package/dist/core/db.d.ts.map +1 -0
- package/dist/core/db.js +90 -0
- package/dist/core/db.js.map +1 -0
- package/dist/core/memory.d.ts +4 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +9 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/models.d.ts +67 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +29 -0
- package/dist/core/models.js.map +1 -0
- package/dist/dashboard/index.html +676 -0
- package/dist/dashboard/server.d.ts +2 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +20 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +386 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +41 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/conversations.d.ts +3 -0
- package/dist/server/routes/conversations.d.ts.map +1 -0
- package/dist/server/routes/conversations.js +86 -0
- package/dist/server/routes/conversations.js.map +1 -0
- package/dist/server/routes/entities.d.ts +3 -0
- package/dist/server/routes/entities.d.ts.map +1 -0
- package/dist/server/routes/entities.js +51 -0
- package/dist/server/routes/entities.js.map +1 -0
- package/dist/server/routes/facts.d.ts +3 -0
- package/dist/server/routes/facts.d.ts.map +1 -0
- package/dist/server/routes/facts.js +41 -0
- package/dist/server/routes/facts.js.map +1 -0
- package/dist/server/routes/health.d.ts +3 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +72 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/search.d.ts +3 -0
- package/dist/server/routes/search.d.ts.map +1 -0
- package/dist/server/routes/search.js +60 -0
- package/dist/server/routes/search.js.map +1 -0
- package/dist/server/routes/workspace.d.ts +3 -0
- package/dist/server/routes/workspace.d.ts.map +1 -0
- package/dist/server/routes/workspace.js +34 -0
- package/dist/server/routes/workspace.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export async function entityRoutes(app) {
|
|
2
|
+
const db = app.db;
|
|
3
|
+
app.get('/entities', async (request) => {
|
|
4
|
+
const { category, type } = request.query;
|
|
5
|
+
let sql = "SELECT * FROM entities WHERE status = 'active'";
|
|
6
|
+
const params = [];
|
|
7
|
+
if (category) {
|
|
8
|
+
sql += ' AND category = ?';
|
|
9
|
+
params.push(category);
|
|
10
|
+
}
|
|
11
|
+
if (type) {
|
|
12
|
+
sql += ' AND type = ?';
|
|
13
|
+
params.push(type);
|
|
14
|
+
}
|
|
15
|
+
sql += ' ORDER BY updated_at DESC';
|
|
16
|
+
return db.prepare(sql).all(...params).map((e) => ({
|
|
17
|
+
...e,
|
|
18
|
+
metadata: e.metadata ? JSON.parse(e.metadata) : null,
|
|
19
|
+
}));
|
|
20
|
+
});
|
|
21
|
+
app.get('/entities/:id', async (request, reply) => {
|
|
22
|
+
const { id } = request.params;
|
|
23
|
+
const entity = db.prepare('SELECT * FROM entities WHERE id = ?').get(id);
|
|
24
|
+
if (!entity)
|
|
25
|
+
return reply.code(404).send({ error: 'Entity not found' });
|
|
26
|
+
const facts = db
|
|
27
|
+
.prepare('SELECT * FROM facts WHERE entity_id = ? ORDER BY tier ASC, access_count DESC')
|
|
28
|
+
.all(id);
|
|
29
|
+
return {
|
|
30
|
+
...entity,
|
|
31
|
+
metadata: entity.metadata ? JSON.parse(entity.metadata) : null,
|
|
32
|
+
facts: facts.map((f) => ({ ...f, related_entities: JSON.parse(f.related_entities) })),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
app.post('/entities', async (request, reply) => {
|
|
36
|
+
const { id, name, type, category, metadata } = request.body;
|
|
37
|
+
const now = new Date().toISOString();
|
|
38
|
+
db.prepare('INSERT INTO entities (id, name, type, category, created_at, updated_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)').run(id, name, type, category, now, now, metadata ? JSON.stringify(metadata) : null);
|
|
39
|
+
return reply.code(201).send({ id, name, type, category });
|
|
40
|
+
});
|
|
41
|
+
app.delete('/entities/:id', async (request, reply) => {
|
|
42
|
+
const { id } = request.params;
|
|
43
|
+
const result = db
|
|
44
|
+
.prepare("UPDATE entities SET status = 'archived', updated_at = ? WHERE id = ?")
|
|
45
|
+
.run(new Date().toISOString(), id);
|
|
46
|
+
if (result.changes === 0)
|
|
47
|
+
return reply.code(404).send({ error: 'Entity not found' });
|
|
48
|
+
return { id, status: 'archived' };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../../../src/server/routes/entities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts.d.ts","sourceRoot":"","sources":["../../../src/server/routes/facts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAO/C,wBAAsB,UAAU,CAAC,GAAG,EAAE,eAAe,iBAiEpD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export async function factRoutes(app) {
|
|
2
|
+
const db = app.db;
|
|
3
|
+
app.get('/entities/:entityId/facts', async (request, reply) => {
|
|
4
|
+
const { entityId } = request.params;
|
|
5
|
+
const { tier } = request.query;
|
|
6
|
+
if (!db.prepare('SELECT id FROM entities WHERE id = ?').get(entityId))
|
|
7
|
+
return reply.code(404).send({ error: 'Entity not found' });
|
|
8
|
+
let sql = 'SELECT * FROM facts WHERE entity_id = ?';
|
|
9
|
+
const params = [entityId];
|
|
10
|
+
if (tier) {
|
|
11
|
+
sql += ' AND tier = ?';
|
|
12
|
+
params.push(tier);
|
|
13
|
+
}
|
|
14
|
+
sql += ' ORDER BY access_count DESC, last_accessed DESC';
|
|
15
|
+
return db.prepare(sql).all(...params).map((f) => ({
|
|
16
|
+
...f,
|
|
17
|
+
related_entities: JSON.parse(f.related_entities),
|
|
18
|
+
}));
|
|
19
|
+
});
|
|
20
|
+
app.post('/entities/:entityId/facts', async (request, reply) => {
|
|
21
|
+
const { entityId } = request.params;
|
|
22
|
+
const { id, fact, category, timestamp, source, relatedEntities } = request.body;
|
|
23
|
+
if (!db.prepare('SELECT id FROM entities WHERE id = ?').get(entityId))
|
|
24
|
+
return reply.code(404).send({ error: 'Entity not found' });
|
|
25
|
+
const now = new Date().toISOString().split('T')[0];
|
|
26
|
+
db.prepare("INSERT INTO facts (id, entity_id, fact, category, timestamp, last_accessed, access_count, tier, source, related_entities) VALUES (?, ?, ?, ?, ?, ?, 1, 'hot', ?, ?)").run(id, entityId, fact, category || 'context', timestamp || now, now, source || 'api', JSON.stringify(relatedEntities || []));
|
|
27
|
+
db.prepare('UPDATE entities SET updated_at = ? WHERE id = ?').run(now, entityId);
|
|
28
|
+
return reply.code(201).send({ id, entityId, fact });
|
|
29
|
+
});
|
|
30
|
+
app.patch('/facts/:id/access', async (request, reply) => {
|
|
31
|
+
const { id } = request.params;
|
|
32
|
+
const now = new Date().toISOString().split('T')[0];
|
|
33
|
+
const result = db
|
|
34
|
+
.prepare("UPDATE facts SET last_accessed = ?, access_count = access_count + 1, tier = 'hot' WHERE id = ?")
|
|
35
|
+
.run(now, id);
|
|
36
|
+
if (result.changes === 0)
|
|
37
|
+
return reply.code(404).send({ error: 'Fact not found' });
|
|
38
|
+
return { id, bumped: true };
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts.js","sourceRoot":"","sources":["../../../src/server/routes/facts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../src/server/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA+B/C,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,iBAoDtD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const CLAUDE_MD_CONTENT = `# dbrain
|
|
2
|
+
|
|
3
|
+
You have an AI brain connected via MCP (dbrain). This is your persistent memory across all conversations and machines.
|
|
4
|
+
|
|
5
|
+
## What's in the brain
|
|
6
|
+
|
|
7
|
+
- **Documents**: Identity (who you are), User (who the user is), Soul (how to behave), Memory (narrative reflections). These are returned automatically with every \`recall\` call.
|
|
8
|
+
- **Entities + Facts**: Structured knowledge organized by PARA (Projects, Areas, Resources, Archives). Each entity (person, project, system, event) has facts attached. Facts have tiers: hot (recent/frequent), warm, cold.
|
|
9
|
+
- **Conversations**: Raw chat history from every AI session. Stored with source (e.g. 'claude-code-home', 'gemini-mobile').
|
|
10
|
+
|
|
11
|
+
## When to use each tool
|
|
12
|
+
|
|
13
|
+
- \`recall\` — Search before answering. Use this BEFORE responding to any question about the user, their preferences, projects, people they know, or past conversations. Also returns your identity docs. When in doubt, search first.
|
|
14
|
+
- \`remember\` — Save important facts. Use when the user shares preferences, makes decisions, mentions personal details, or says "remember this". One clear atomic fact per call.
|
|
15
|
+
- \`log\` — Store conversation messages. Use periodically to log what's happening in the conversation. Send both user and assistant messages.
|
|
16
|
+
- \`get_entity\` — Deep dive. When you need full context about a specific project, person, or system.
|
|
17
|
+
- \`list_entities\` — Discover. When you need to see what entities exist, filter by category or type.
|
|
18
|
+
- \`create_entity\` — New knowledge. When the user mentions a new project, person, or system worth tracking. Create the entity first, then \`remember\` facts about it.
|
|
19
|
+
- \`bump\` — Keep memories alive. When you use a fact to answer a question, bump it so it stays hot.
|
|
20
|
+
- \`overview\` — Brain stats. When the user asks "what do you know?" or you need a high-level picture.
|
|
21
|
+
- \`wake_up\` — Full identity load. Only needed if you want the complete identity documents outside of a recall.
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
- At the start of every conversation, call \`recall\` with the user's first question or topic. This gives you both search results AND your identity.
|
|
26
|
+
- Never say "I don't know" about the user without searching first.
|
|
27
|
+
- When storing facts, be specific and atomic. "Favorite ice cream is pistachio" not "We talked about food preferences".
|
|
28
|
+
`;
|
|
29
|
+
export async function healthRoutes(app) {
|
|
30
|
+
app.get('/health', async () => {
|
|
31
|
+
const db = app.db;
|
|
32
|
+
const { entities } = db.prepare('SELECT COUNT(*) as entities FROM entities').get();
|
|
33
|
+
const { facts } = db.prepare('SELECT COUNT(*) as facts FROM facts').get();
|
|
34
|
+
const { documents } = db.prepare('SELECT COUNT(*) as documents FROM documents').get();
|
|
35
|
+
const { conversations } = db
|
|
36
|
+
.prepare('SELECT COUNT(*) as conversations FROM conversations')
|
|
37
|
+
.get();
|
|
38
|
+
const { unprocessed } = db
|
|
39
|
+
.prepare('SELECT COUNT(*) as unprocessed FROM messages WHERE processed = 0')
|
|
40
|
+
.get();
|
|
41
|
+
const identity = db.prepare("SELECT content FROM documents WHERE key = 'identity'").get();
|
|
42
|
+
const name = identity?.content?.match(/\*\*Name:\*\* (.+)/)?.[1] || 'dbrain';
|
|
43
|
+
return {
|
|
44
|
+
status: 'awake',
|
|
45
|
+
name,
|
|
46
|
+
version: '0.1.0',
|
|
47
|
+
entities,
|
|
48
|
+
facts,
|
|
49
|
+
documents,
|
|
50
|
+
conversations,
|
|
51
|
+
unprocessed,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
app.get('/connect', async (request) => {
|
|
55
|
+
const config = app.config;
|
|
56
|
+
const host = request.headers.host || `localhost:${config.port}`;
|
|
57
|
+
const protocol = request.headers['x-forwarded-proto'] || 'http';
|
|
58
|
+
const baseUrl = `${protocol}://${host}`;
|
|
59
|
+
return {
|
|
60
|
+
mcp: {
|
|
61
|
+
dbrain: {
|
|
62
|
+
type: 'http',
|
|
63
|
+
url: `${baseUrl}/mcp`,
|
|
64
|
+
headers: { Authorization: `Bearer ${config.token}` },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
permissions: ['mcp__dbrain__*'],
|
|
68
|
+
claudeMd: CLAUDE_MD_CONTENT,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/server/routes/health.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BzB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB;IACrD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC5B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC,GAAG,EAE/E,CAAC;QACF,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,EAEtE,CAAC;QACF,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC,GAAG,EAElF,CAAC;QACF,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE;aACzB,OAAO,CAAC,qDAAqD,CAAC;aAC9D,GAAG,EAA+B,CAAC;QACtC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE;aACvB,OAAO,CAAC,kEAAkE,CAAC;aAC3E,GAAG,EAA6B,CAAC;QACpC,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAC,GAAG,EAE1E,CAAC;QACd,MAAM,IAAI,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;QAC7E,OAAO;YACL,MAAM,EAAE,OAAO;YACf,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,QAAQ;YACR,KAAK;YACL,SAAS;YACT,aAAa;YACb,WAAW;SACZ,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC;QAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,MAAM,CAAC;QAChE,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC;QAExC,OAAO;YACL,GAAG,EAAE;gBACH,MAAM,EAAE;oBACN,IAAI,EAAE,MAAM;oBACZ,GAAG,EAAE,GAAG,OAAO,MAAM;oBACrB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,KAAK,EAAE,EAAE;iBACrD;aACF;YACD,WAAW,EAAE,CAAC,gBAAgB,CAAC;YAC/B,QAAQ,EAAE,iBAAiB;SAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/server/routes/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAmB/C,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,iBAyEtD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export async function searchRoutes(app) {
|
|
2
|
+
const db = app.db;
|
|
3
|
+
app.post('/search', async (request) => {
|
|
4
|
+
const { query, limit = 10, entityId, tier, } = request.body;
|
|
5
|
+
const ftsQuery = query.split(/\s+/).filter(Boolean).join(' OR ');
|
|
6
|
+
let sql = `
|
|
7
|
+
SELECT f.*, e.name as entity_name, e.type as entity_type, e.category as entity_category, rank
|
|
8
|
+
FROM facts_fts fts
|
|
9
|
+
JOIN facts f ON f.rowid = fts.rowid
|
|
10
|
+
JOIN entities e ON e.id = f.entity_id
|
|
11
|
+
WHERE facts_fts MATCH ?
|
|
12
|
+
`;
|
|
13
|
+
const params = [ftsQuery];
|
|
14
|
+
if (entityId) {
|
|
15
|
+
sql += ' AND f.entity_id = ?';
|
|
16
|
+
params.push(entityId);
|
|
17
|
+
}
|
|
18
|
+
if (tier) {
|
|
19
|
+
sql += ' AND f.tier = ?';
|
|
20
|
+
params.push(tier);
|
|
21
|
+
}
|
|
22
|
+
sql += ' ORDER BY rank LIMIT ?';
|
|
23
|
+
params.push(limit);
|
|
24
|
+
return db.prepare(sql).all(...params).map((r) => ({
|
|
25
|
+
fact: {
|
|
26
|
+
id: r.id,
|
|
27
|
+
entityId: r.entity_id,
|
|
28
|
+
fact: r.fact,
|
|
29
|
+
category: r.category,
|
|
30
|
+
timestamp: r.timestamp,
|
|
31
|
+
status: r.status,
|
|
32
|
+
lastAccessed: r.last_accessed,
|
|
33
|
+
accessCount: r.access_count,
|
|
34
|
+
tier: r.tier,
|
|
35
|
+
source: r.source,
|
|
36
|
+
},
|
|
37
|
+
entity: {
|
|
38
|
+
id: r.entity_id,
|
|
39
|
+
name: r.entity_name,
|
|
40
|
+
type: r.entity_type,
|
|
41
|
+
category: r.entity_category,
|
|
42
|
+
},
|
|
43
|
+
score: -r.rank,
|
|
44
|
+
}));
|
|
45
|
+
});
|
|
46
|
+
app.get('/memory/summary', async () => {
|
|
47
|
+
return db
|
|
48
|
+
.prepare(`
|
|
49
|
+
SELECT e.id, e.name, e.type, e.category,
|
|
50
|
+
COUNT(CASE WHEN f.tier = 'hot' THEN 1 END) as hot,
|
|
51
|
+
COUNT(CASE WHEN f.tier = 'warm' THEN 1 END) as warm,
|
|
52
|
+
COUNT(CASE WHEN f.tier = 'cold' THEN 1 END) as cold,
|
|
53
|
+
COUNT(f.id) as total
|
|
54
|
+
FROM entities e LEFT JOIN facts f ON f.entity_id = e.id
|
|
55
|
+
WHERE e.status = 'active' GROUP BY e.id ORDER BY total DESC
|
|
56
|
+
`)
|
|
57
|
+
.all();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/server/routes/search.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB;IACrD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;IAElB,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpC,MAAM,EACJ,KAAK,EACL,KAAK,GAAG,EAAE,EACV,QAAQ,EACR,IAAI,GACL,GAAG,OAAO,CAAC,IAKX,CAAC;QACF,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjE,IAAI,GAAG,GAAG;;;;;;KAMT,CAAC;QACF,MAAM,MAAM,GAAwB,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE,CAAC;YACb,GAAG,IAAI,sBAAsB,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACT,GAAG,IAAI,iBAAiB,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,GAAG,IAAI,wBAAwB,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEnB,OAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvE,IAAI,EAAE;gBACJ,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,QAAQ,EAAE,CAAC,CAAC,SAAS;gBACrB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,YAAY,EAAE,CAAC,CAAC,aAAa;gBAC7B,WAAW,EAAE,CAAC,CAAC,YAAY;gBAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB;YACD,MAAM,EAAE;gBACN,EAAE,EAAE,CAAC,CAAC,SAAS;gBACf,IAAI,EAAE,CAAC,CAAC,WAAW;gBACnB,IAAI,EAAE,CAAC,CAAC,WAAW;gBACnB,QAAQ,EAAE,CAAC,CAAC,eAAe;aAC5B;YACD,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI;SACf,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QACpC,OAAO,EAAE;aACN,OAAO,CACN;;;;;;;;KAQH,CACE;aACA,GAAG,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/server/routes/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAsB,eAAe,CAAC,GAAG,EAAE,eAAe,iBA6CzD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export async function workspaceRoutes(app) {
|
|
2
|
+
const db = app.db;
|
|
3
|
+
app.get('/workspace', async () => {
|
|
4
|
+
return db.prepare('SELECT key, title, updated_at FROM documents ORDER BY key').all();
|
|
5
|
+
});
|
|
6
|
+
app.get('/workspace/:key', async (request, reply) => {
|
|
7
|
+
const { key } = request.params;
|
|
8
|
+
const doc = db.prepare('SELECT * FROM documents WHERE key = ?').get(key);
|
|
9
|
+
if (!doc)
|
|
10
|
+
return reply.code(404).send({ error: 'Document not found' });
|
|
11
|
+
return doc;
|
|
12
|
+
});
|
|
13
|
+
app.put('/workspace/:key', async (request, reply) => {
|
|
14
|
+
const { key } = request.params;
|
|
15
|
+
const { title, content } = request.body;
|
|
16
|
+
const now = new Date().toISOString();
|
|
17
|
+
const existing = db.prepare('SELECT key FROM documents WHERE key = ?').get(key);
|
|
18
|
+
if (existing) {
|
|
19
|
+
db.prepare('UPDATE documents SET title = ?, content = ?, updated_at = ? WHERE key = ?').run(title, content, now, key);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
db.prepare('INSERT INTO documents (key, title, content, updated_at) VALUES (?, ?, ?, ?)').run(key, title, content, now);
|
|
23
|
+
}
|
|
24
|
+
return reply.code(existing ? 200 : 201).send({ key, title, updated_at: now });
|
|
25
|
+
});
|
|
26
|
+
app.delete('/workspace/:key', async (request, reply) => {
|
|
27
|
+
const { key } = request.params;
|
|
28
|
+
const result = db.prepare('DELETE FROM documents WHERE key = ?').run(key);
|
|
29
|
+
if (result.changes === 0)
|
|
30
|
+
return reply.code(404).send({ error: 'Document not found' });
|
|
31
|
+
return { key, deleted: true };
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/server/routes/workspace.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAoB;IACxD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;IAElB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QAC/B,OAAO,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,EAAE,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAClD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAyB,CAAC;QAClD,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACvE,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAClD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAyB,CAAC;QAClD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAA0C,CAAC;QAC9E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChF,IAAI,QAAQ,EAAE,CAAC;YACb,EAAE,CAAC,OAAO,CAAC,2EAA2E,CAAC,CAAC,GAAG,CACzF,KAAK,EACL,OAAO,EACP,GAAG,EACH,GAAG,CACJ,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,OAAO,CAAC,6EAA6E,CAAC,CAAC,GAAG,CAC3F,GAAG,EACH,KAAK,EACL,OAAO,EACP,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACrD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAyB,CAAC;QAClD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dbrain",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Your distributed mind. Persistent knowledge across all your AIs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dbrain": "./dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsx watch src/cli/index.ts start",
|
|
11
|
+
"cli": "tsx src/cli/index.ts",
|
|
12
|
+
"build": "tsc && cp src/dashboard/index.html dist/dashboard/index.html && chmod +x dist/cli/index.js",
|
|
13
|
+
"prepare": "husky",
|
|
14
|
+
"start": "node dist/cli/index.js start",
|
|
15
|
+
"test": "vitest",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"lint:fix": "eslint . --fix",
|
|
18
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
19
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
20
|
+
"check": "npm run lint:fix && npm run format && npm run build"
|
|
21
|
+
},
|
|
22
|
+
"lint-staged": {
|
|
23
|
+
"*.{ts,js}": [
|
|
24
|
+
"eslint --fix",
|
|
25
|
+
"prettier --write"
|
|
26
|
+
],
|
|
27
|
+
"*.json": [
|
|
28
|
+
"prettier --write"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/ivncmp/dbrain.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/ivncmp/dbrain",
|
|
41
|
+
"bugs": "https://github.com/ivncmp/dbrain/issues",
|
|
42
|
+
"author": "Iván Campillo <ivncmp@gmail.com>",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"keywords": [
|
|
45
|
+
"ai",
|
|
46
|
+
"memory",
|
|
47
|
+
"mcp",
|
|
48
|
+
"brain",
|
|
49
|
+
"knowledge",
|
|
50
|
+
"claude",
|
|
51
|
+
"llm",
|
|
52
|
+
"sqlite"
|
|
53
|
+
],
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@clack/prompts": "^1.3.0",
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
60
|
+
"better-sqlite3": "^12.9.0",
|
|
61
|
+
"dotenv": "^17.4.2",
|
|
62
|
+
"fastify": "^5.8.5",
|
|
63
|
+
"picocolors": "^1.1.1",
|
|
64
|
+
"zod": "^4.4.2"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@eslint/js": "^9.25.0",
|
|
68
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
69
|
+
"@types/node": "^25.6.0",
|
|
70
|
+
"eslint": "^9.25.0",
|
|
71
|
+
"eslint-config-prettier": "^10.1.8",
|
|
72
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
73
|
+
"globals": "^16.0.0",
|
|
74
|
+
"husky": "^9.1.7",
|
|
75
|
+
"lint-staged": "^16.1.5",
|
|
76
|
+
"prettier": "^3.8.1",
|
|
77
|
+
"tsx": "^4.21.0",
|
|
78
|
+
"typescript": "^6.0.3",
|
|
79
|
+
"typescript-eslint": "^8.30.1",
|
|
80
|
+
"vitest": "^4.1.5"
|
|
81
|
+
}
|
|
82
|
+
}
|