limbo-ai 1.13.0 → 1.14.1
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/cli.js +17 -5
- package/mcp-server/index.js +5 -1
- package/mcp-server/tools/write.js +6 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ const SECRETS_DIR = path.join(LIMBO_DIR, 'secrets');
|
|
|
18
18
|
const ENV_FILE = path.join(LIMBO_DIR, '.env');
|
|
19
19
|
const COMPOSE_FILE = path.join(LIMBO_DIR, 'docker-compose.yml');
|
|
20
20
|
const GHCR_IMAGE = 'ghcr.io/tomasward1/limbo';
|
|
21
|
-
const DEFAULT_TAG =
|
|
21
|
+
const DEFAULT_TAG = 'latest';
|
|
22
22
|
const DEFAULT_PORT = 18789;
|
|
23
23
|
const COEXIST_PORT = 18900;
|
|
24
24
|
let PORT = DEFAULT_PORT;
|
|
@@ -373,7 +373,7 @@ const TEXT = {
|
|
|
373
373
|
nonTelegramHintTitle: 'No Telegram? You can still talk to Limbo through another agent.',
|
|
374
374
|
nonTelegramPromptIntro: 'Suggested prompt:',
|
|
375
375
|
nonTelegramPrompt: (token) => `Connect to my Limbo gateway at ws://127.0.0.1:${PORT} using token ${token}. Use Limbo as my memory layer: save notes, recall context, and update maps of content when I ask.`,
|
|
376
|
-
dockerMissing: 'Docker is not installed or
|
|
376
|
+
dockerMissing: 'Docker is not installed or the Compose plugin is missing.\n Docker Engine: https://docs.docker.com/engine/install/\n Compose plugin: sudo apt-get install docker-compose-plugin',
|
|
377
377
|
installMissing: 'Limbo is not installed. Run: npx limbo start',
|
|
378
378
|
helpTitle: 'limbo - personal AI memory agent',
|
|
379
379
|
usage: 'Usage',
|
|
@@ -487,7 +487,7 @@ const TEXT = {
|
|
|
487
487
|
nonTelegramHintTitle: 'Sin Telegram? Igual puedes hablar con Limbo desde otro agente.',
|
|
488
488
|
nonTelegramPromptIntro: 'Prompt sugerido:',
|
|
489
489
|
nonTelegramPrompt: (token) => `Conectate a mi gateway de Limbo en ws://127.0.0.1:${PORT} usando el token ${token}. Usa Limbo como mi capa de memoria: guarda notas, recupera contexto y actualiza maps of content cuando yo lo pida.`,
|
|
490
|
-
dockerMissing: 'Docker no esta instalado o
|
|
490
|
+
dockerMissing: 'Docker no esta instalado o falta el plugin Compose.\n Docker Engine: https://docs.docker.com/engine/install/\n Plugin Compose: sudo apt-get install docker-compose-plugin',
|
|
491
491
|
installMissing: 'Limbo no esta instalado. Corre: npx limbo start',
|
|
492
492
|
helpTitle: 'limbo - agente personal de memoria con AI',
|
|
493
493
|
usage: 'Uso',
|
|
@@ -1450,10 +1450,22 @@ function cmdLogs() {
|
|
|
1450
1450
|
|
|
1451
1451
|
function cmdUpdate() {
|
|
1452
1452
|
if (!fs.existsSync(COMPOSE_FILE)) die(t('en', 'installMissing'));
|
|
1453
|
+
|
|
1454
|
+
// Patch image tag to :latest in existing compose files (handles upgrades from pinned tags)
|
|
1455
|
+
const compose = fs.readFileSync(COMPOSE_FILE, 'utf8');
|
|
1456
|
+
const patched = compose.replace(
|
|
1457
|
+
/image:\s*ghcr\.io\/tomasward1\/limbo:\S+/g,
|
|
1458
|
+
`image: ${GHCR_IMAGE}:${DEFAULT_TAG}`
|
|
1459
|
+
);
|
|
1460
|
+
if (patched !== compose) {
|
|
1461
|
+
fs.writeFileSync(COMPOSE_FILE, patched);
|
|
1462
|
+
log('Patched compose image tag to :latest');
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1453
1465
|
log('Pulling latest image...');
|
|
1454
|
-
run(
|
|
1466
|
+
run(`docker compose -f "${COMPOSE_FILE}" pull -q`);
|
|
1455
1467
|
log('Restarting...');
|
|
1456
|
-
run(
|
|
1468
|
+
run(`docker compose -f "${COMPOSE_FILE}" up -d --remove-orphans`);
|
|
1457
1469
|
ok('Updated and restarted.');
|
|
1458
1470
|
}
|
|
1459
1471
|
|
package/mcp-server/index.js
CHANGED
|
@@ -65,7 +65,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
65
65
|
properties: {
|
|
66
66
|
id: { type: "string", description: "Unique note identifier (alphanumeric, dashes, underscores)" },
|
|
67
67
|
title: { type: "string", description: "Human-readable note title" },
|
|
68
|
-
type: {
|
|
68
|
+
type: {
|
|
69
|
+
type: "string",
|
|
70
|
+
enum: ["fact", "preference", "person", "event", "project", "decision", "idea", "question", "source", "insight"],
|
|
71
|
+
description: "Note type: fact, preference, person, event, project, decision, idea, question, source, insight",
|
|
72
|
+
},
|
|
69
73
|
description: { type: "string", description: "One-sentence falsifiable description of the note's claim" },
|
|
70
74
|
content: { type: "string", description: "Full markdown body of the note" },
|
|
71
75
|
subdirectory: { type: "string", description: "Optional subdirectory under notes/ (e.g. 'openclaw', 'research', 'aios/infrastructure'). Created if it doesn't exist." },
|
|
@@ -5,6 +5,7 @@ const VAULT_PATH = process.env.VAULT_PATH || "/data/vault";
|
|
|
5
5
|
const NOTES_DIR = join(VAULT_PATH, "notes");
|
|
6
6
|
|
|
7
7
|
const REQUIRED_FIELDS = ["id", "title", "type", "description", "content"];
|
|
8
|
+
const VALID_TYPES = ['fact', 'preference', 'person', 'event', 'project', 'decision', 'idea', 'question', 'source', 'insight'];
|
|
8
9
|
|
|
9
10
|
function escapeYaml(str) {
|
|
10
11
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
@@ -21,6 +22,7 @@ function buildFrontmatter(note) {
|
|
|
21
22
|
lines.push(`title: "${escapeYaml(note.title)}"`);
|
|
22
23
|
lines.push(`description: "${escapeYaml(note.description)}"`);
|
|
23
24
|
lines.push(`type: ${note.type}`);
|
|
25
|
+
lines.push(`schema_version: 1`);
|
|
24
26
|
if (note.status) {
|
|
25
27
|
lines.push(`status: ${note.status}`);
|
|
26
28
|
}
|
|
@@ -54,6 +56,10 @@ export async function vaultWriteNote(note) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
if (!VALID_TYPES.includes(note.type)) {
|
|
60
|
+
throw new Error(`Invalid note type: "${note.type}". Valid types: ${VALID_TYPES.join(', ')}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
// Sanitize id
|
|
58
64
|
const safe = note.id.replace(/[^a-zA-Z0-9_\-]/g, "");
|
|
59
65
|
if (safe !== note.id) {
|