@gamaze/hicortex 0.3.14 → 0.3.16
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/dist/index.js +79 -0
- package/dist/init.js +32 -8
- package/dist/mcp-server.js +75 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -352,11 +352,88 @@ exports.default = {
|
|
|
352
352
|
}
|
|
353
353
|
},
|
|
354
354
|
}), { name: "hicortex_lessons" });
|
|
355
|
+
api.registerTool((_ctx) => ({
|
|
356
|
+
name: "hicortex_update",
|
|
357
|
+
description: "Update an existing memory. Use after searching to fix incorrect information. If content changes, the embedding is re-computed.",
|
|
358
|
+
parameters: {
|
|
359
|
+
type: "object",
|
|
360
|
+
properties: {
|
|
361
|
+
id: { type: "string", description: "Memory ID (from search results, first 8 chars or full UUID)" },
|
|
362
|
+
content: { type: "string", description: "New content text" },
|
|
363
|
+
project: { type: "string", description: "New project name" },
|
|
364
|
+
memory_type: { type: "string", enum: ["episode", "lesson", "fact", "decision"], description: "New memory type" },
|
|
365
|
+
},
|
|
366
|
+
required: ["id"],
|
|
367
|
+
},
|
|
368
|
+
async execute(_callId, args, _ctx) {
|
|
369
|
+
if (!db)
|
|
370
|
+
return { error: "Hicortex not initialized" };
|
|
371
|
+
try {
|
|
372
|
+
const fullId = resolveMemoryId(db, args.id);
|
|
373
|
+
if (!fullId)
|
|
374
|
+
return { error: `Memory not found: ${args.id}` };
|
|
375
|
+
const fields = {};
|
|
376
|
+
if (args.content !== undefined)
|
|
377
|
+
fields.content = args.content;
|
|
378
|
+
if (args.project !== undefined)
|
|
379
|
+
fields.project = args.project;
|
|
380
|
+
if (args.memory_type !== undefined)
|
|
381
|
+
fields.memory_type = args.memory_type;
|
|
382
|
+
if (Object.keys(fields).length === 0)
|
|
383
|
+
return { error: "No fields to update" };
|
|
384
|
+
storage.updateMemory(db, fullId, fields);
|
|
385
|
+
if (args.content !== undefined) {
|
|
386
|
+
const embedding = await (0, embedder_js_1.embed)(args.content);
|
|
387
|
+
db.prepare("DELETE FROM memory_vectors WHERE id = ?").run(fullId);
|
|
388
|
+
db.prepare("INSERT INTO memory_vectors (id, embedding) VALUES (?, ?)").run(fullId, Buffer.from(embedding.buffer));
|
|
389
|
+
}
|
|
390
|
+
return { content: [{ type: "text", text: `Memory updated (id: ${fullId.slice(0, 8)})` }] };
|
|
391
|
+
}
|
|
392
|
+
catch (err) {
|
|
393
|
+
return { error: `Update failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
}), { name: "hicortex_update" });
|
|
397
|
+
api.registerTool((_ctx) => ({
|
|
398
|
+
name: "hicortex_delete",
|
|
399
|
+
description: "Permanently delete a memory and its links. Use when a memory is incorrect and should be removed entirely.",
|
|
400
|
+
parameters: {
|
|
401
|
+
type: "object",
|
|
402
|
+
properties: {
|
|
403
|
+
id: { type: "string", description: "Memory ID (from search results, first 8 chars or full UUID)" },
|
|
404
|
+
},
|
|
405
|
+
required: ["id"],
|
|
406
|
+
},
|
|
407
|
+
execute(_callId, args, _ctx) {
|
|
408
|
+
if (!db)
|
|
409
|
+
return { error: "Hicortex not initialized" };
|
|
410
|
+
try {
|
|
411
|
+
const fullId = resolveMemoryId(db, args.id);
|
|
412
|
+
if (!fullId)
|
|
413
|
+
return { error: `Memory not found: ${args.id}` };
|
|
414
|
+
storage.deleteMemory(db, fullId);
|
|
415
|
+
return { content: [{ type: "text", text: `Memory deleted (id: ${fullId.slice(0, 8)})` }] };
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
return { error: `Delete failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
}), { name: "hicortex_delete" });
|
|
355
422
|
},
|
|
356
423
|
};
|
|
357
424
|
// ---------------------------------------------------------------------------
|
|
358
425
|
// Helpers
|
|
359
426
|
// ---------------------------------------------------------------------------
|
|
427
|
+
function resolveMemoryId(database, idPrefix) {
|
|
428
|
+
if (idPrefix.length >= 36) {
|
|
429
|
+
const row = database.prepare("SELECT id FROM memories WHERE id = ?").get(idPrefix);
|
|
430
|
+
return row?.id ?? null;
|
|
431
|
+
}
|
|
432
|
+
const rows = database.prepare("SELECT id FROM memories WHERE id LIKE ?").all(`${idPrefix}%`);
|
|
433
|
+
if (rows.length === 1)
|
|
434
|
+
return rows[0].id;
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
360
437
|
// ---------------------------------------------------------------------------
|
|
361
438
|
// Auto-configure LLM: resolve config → test connection → persist if new
|
|
362
439
|
// ---------------------------------------------------------------------------
|
|
@@ -477,6 +554,8 @@ const HICORTEX_TOOLS = [
|
|
|
477
554
|
"hicortex_context",
|
|
478
555
|
"hicortex_ingest",
|
|
479
556
|
"hicortex_lessons",
|
|
557
|
+
"hicortex_update",
|
|
558
|
+
"hicortex_delete",
|
|
480
559
|
];
|
|
481
560
|
/**
|
|
482
561
|
* Ensure hicortex tools are in tools.allow so they're visible to agents
|
package/dist/init.js
CHANGED
|
@@ -116,23 +116,45 @@ function registerCcMcp(serverUrl) {
|
|
|
116
116
|
console.log(` ✓ Registered MCP server via claude CLI`);
|
|
117
117
|
}
|
|
118
118
|
catch (err) {
|
|
119
|
-
// Fallback: write directly to
|
|
119
|
+
// Fallback: write directly to ~/.claude.json (where CC reads MCP servers)
|
|
120
120
|
const msg = err instanceof Error ? err.message : String(err);
|
|
121
|
-
console.log(` ⚠ claude CLI registration failed (${msg}), writing
|
|
122
|
-
|
|
121
|
+
console.log(` ⚠ claude CLI registration failed (${msg}), writing ~/.claude.json directly`);
|
|
122
|
+
const claudeJsonPath = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude.json");
|
|
123
|
+
let config = {};
|
|
123
124
|
try {
|
|
124
|
-
|
|
125
|
+
config = JSON.parse((0, node_fs_1.readFileSync)(claudeJsonPath, "utf-8"));
|
|
125
126
|
}
|
|
126
127
|
catch { /* create new */ }
|
|
127
|
-
if (!
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
if (!config.mcpServers)
|
|
129
|
+
config.mcpServers = {};
|
|
130
|
+
config.mcpServers.hicortex = {
|
|
130
131
|
type: "sse",
|
|
131
132
|
url: `${serverUrl}/sse`,
|
|
132
133
|
};
|
|
134
|
+
(0, node_fs_1.writeFileSync)(claudeJsonPath, JSON.stringify(config, null, 2));
|
|
135
|
+
console.log(` ✓ Registered MCP server in ${claudeJsonPath}`);
|
|
136
|
+
}
|
|
137
|
+
// Add MCP tool permissions to settings.json so users don't get prompted
|
|
138
|
+
allowHicortexTools();
|
|
139
|
+
}
|
|
140
|
+
function allowHicortexTools() {
|
|
141
|
+
let settings = {};
|
|
142
|
+
try {
|
|
143
|
+
settings = JSON.parse((0, node_fs_1.readFileSync)(CC_SETTINGS, "utf-8"));
|
|
144
|
+
}
|
|
145
|
+
catch { /* create new */ }
|
|
146
|
+
if (!settings.permissions)
|
|
147
|
+
settings.permissions = {};
|
|
148
|
+
const perms = settings.permissions;
|
|
149
|
+
if (!perms.allow)
|
|
150
|
+
perms.allow = [];
|
|
151
|
+
const allow = perms.allow;
|
|
152
|
+
const rule = "mcp__hicortex__*";
|
|
153
|
+
if (!allow.includes(rule)) {
|
|
154
|
+
allow.push(rule);
|
|
133
155
|
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(CC_SETTINGS), { recursive: true });
|
|
134
156
|
(0, node_fs_1.writeFileSync)(CC_SETTINGS, JSON.stringify(settings, null, 2));
|
|
135
|
-
console.log(` ✓
|
|
157
|
+
console.log(` ✓ Added Hicortex tool permissions to ${CC_SETTINGS}`);
|
|
136
158
|
}
|
|
137
159
|
}
|
|
138
160
|
function installCcCommands() {
|
|
@@ -587,6 +609,8 @@ async function runInit() {
|
|
|
587
609
|
if (!d.ccMcpRegistered) {
|
|
588
610
|
registerCcMcp(serverUrl);
|
|
589
611
|
}
|
|
612
|
+
// Ensure tool permissions are set (also needed for users upgrading from older versions)
|
|
613
|
+
allowHicortexTools();
|
|
590
614
|
// Install CC commands
|
|
591
615
|
installCcCommands();
|
|
592
616
|
// Inject CLAUDE.md (only if server has a DB we can read)
|
package/dist/mcp-server.js
CHANGED
|
@@ -147,6 +147,64 @@ function createMcpServer() {
|
|
|
147
147
|
return { content: [{ type: "text", text: `Ingest failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
|
+
// -- hicortex_update --
|
|
151
|
+
server.tool("hicortex_update", "Update an existing memory. Use after searching to fix incorrect information. If content changes, the embedding is re-computed.", {
|
|
152
|
+
id: zod_1.z.string().describe("Memory ID (from search results, first 8 chars or full UUID)"),
|
|
153
|
+
content: zod_1.z.string().optional().describe("New content text"),
|
|
154
|
+
project: zod_1.z.string().optional().describe("New project name"),
|
|
155
|
+
memory_type: zod_1.z.enum(["episode", "lesson", "fact", "decision"]).optional().describe("New memory type"),
|
|
156
|
+
}, async ({ id, content, project, memory_type }) => {
|
|
157
|
+
if (!db)
|
|
158
|
+
return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
|
|
159
|
+
try {
|
|
160
|
+
// Resolve short ID prefix to full ID
|
|
161
|
+
const fullId = resolveMemoryId(db, id);
|
|
162
|
+
if (!fullId)
|
|
163
|
+
return { content: [{ type: "text", text: `Memory not found: ${id}` }], isError: true };
|
|
164
|
+
const fields = {};
|
|
165
|
+
if (content !== undefined)
|
|
166
|
+
fields.content = content;
|
|
167
|
+
if (project !== undefined)
|
|
168
|
+
fields.project = project;
|
|
169
|
+
if (memory_type !== undefined)
|
|
170
|
+
fields.memory_type = memory_type;
|
|
171
|
+
if (Object.keys(fields).length === 0) {
|
|
172
|
+
return { content: [{ type: "text", text: "No fields to update" }], isError: true };
|
|
173
|
+
}
|
|
174
|
+
const before = storage.getMemory(db, fullId);
|
|
175
|
+
storage.updateMemory(db, fullId, fields);
|
|
176
|
+
// Re-embed if content changed
|
|
177
|
+
if (content !== undefined) {
|
|
178
|
+
const embedding = await (0, embedder_js_1.embed)(content);
|
|
179
|
+
db.prepare("DELETE FROM memory_vectors WHERE id = ?").run(fullId);
|
|
180
|
+
db.prepare("INSERT INTO memory_vectors (id, embedding) VALUES (?, ?)").run(fullId, Buffer.from(embedding.buffer));
|
|
181
|
+
}
|
|
182
|
+
const changed = Object.keys(fields).map(k => `${k}: "${String(before?.[k] ?? "").slice(0, 80)}" → "${String(fields[k]).slice(0, 80)}"`).join(", ");
|
|
183
|
+
return { content: [{ type: "text", text: `Memory updated (id: ${fullId.slice(0, 8)}). Changed: ${changed}` }] };
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
return { content: [{ type: "text", text: `Update failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
// -- hicortex_delete --
|
|
190
|
+
server.tool("hicortex_delete", "Permanently delete a memory and its links. Use when a memory is incorrect and should be removed entirely.", {
|
|
191
|
+
id: zod_1.z.string().describe("Memory ID (from search results, first 8 chars or full UUID)"),
|
|
192
|
+
}, async ({ id }) => {
|
|
193
|
+
if (!db)
|
|
194
|
+
return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
|
|
195
|
+
try {
|
|
196
|
+
const fullId = resolveMemoryId(db, id);
|
|
197
|
+
if (!fullId)
|
|
198
|
+
return { content: [{ type: "text", text: `Memory not found: ${id}` }], isError: true };
|
|
199
|
+
const memory = storage.getMemory(db, fullId);
|
|
200
|
+
storage.deleteMemory(db, fullId);
|
|
201
|
+
const preview = memory?.content?.slice(0, 200) ?? "(unknown)";
|
|
202
|
+
return { content: [{ type: "text", text: `Memory deleted (id: ${fullId.slice(0, 8)}). Content was: ${preview}` }] };
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
return { content: [{ type: "text", text: `Delete failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
206
|
+
}
|
|
207
|
+
});
|
|
150
208
|
// -- hicortex_lessons --
|
|
151
209
|
server.tool("hicortex_lessons", "Get actionable lessons learned from past sessions. Auto-generated insights about mistakes to avoid.", {
|
|
152
210
|
days: zod_1.z.coerce.number().optional().describe("Look back N days (default 7)"),
|
|
@@ -378,6 +436,23 @@ async function startServer(options = {}) {
|
|
|
378
436
|
// ---------------------------------------------------------------------------
|
|
379
437
|
// Helpers
|
|
380
438
|
// ---------------------------------------------------------------------------
|
|
439
|
+
/**
|
|
440
|
+
* Resolve a short ID prefix (e.g. "a1b2c3d4") to a full memory UUID.
|
|
441
|
+
*/
|
|
442
|
+
function resolveMemoryId(database, idPrefix) {
|
|
443
|
+
if (idPrefix.length >= 36) {
|
|
444
|
+
// Full UUID — check existence
|
|
445
|
+
const row = database.prepare("SELECT id FROM memories WHERE id = ?").get(idPrefix);
|
|
446
|
+
return row?.id ?? null;
|
|
447
|
+
}
|
|
448
|
+
// Short prefix — find matching memory
|
|
449
|
+
const rows = database.prepare("SELECT id FROM memories WHERE id LIKE ?").all(`${idPrefix}%`);
|
|
450
|
+
if (rows.length === 1)
|
|
451
|
+
return rows[0].id;
|
|
452
|
+
if (rows.length > 1)
|
|
453
|
+
return null; // Ambiguous
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
381
456
|
/**
|
|
382
457
|
* Read ~/.hicortex/config.json (persisted by init with LLM and license config).
|
|
383
458
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "Human-like memory for self-improving AI agents. Automatic capturing, nightly reflection, and cross-agent learning. Works with Claude Code and OpenClaw.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|