hmem-mcp 1.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 +384 -0
- package/dist/cli-init.d.ts +7 -0
- package/dist/cli-init.js +291 -0
- package/dist/cli-init.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +42 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +88 -0
- package/dist/hmem-config.d.ts +87 -0
- package/dist/hmem-config.js +120 -0
- package/dist/hmem-config.js.map +1 -0
- package/dist/hmem-store.d.ts +175 -0
- package/dist/hmem-store.js +596 -0
- package/dist/hmem-store.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/json-parser.js +63 -0
- package/dist/logger.d.ts +21 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-server.d.ts +17 -0
- package/dist/mcp-server.js +546 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/memory-search.d.ts +18 -0
- package/dist/memory-search.js +294 -0
- package/dist/memory-search.js.map +1 -0
- package/dist/types.js +53 -0
- package/hmem.config.example.json +13 -0
- package/package.json +68 -0
- package/skills/hmem-read/SKILL.md +66 -0
- package/skills/hmem-setup/SKILL.md +200 -0
- package/skills/hmem-write/SKILL.md +94 -0
- package/skills/memory-curate/SKILL.md +76 -0
- package/skills/save/SKILL.md +65 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export function parseRequestFile(filePath, log) {
|
|
4
|
+
try {
|
|
5
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
6
|
+
const req = JSON.parse(raw);
|
|
7
|
+
// Extract Request_ID from filename if not in JSON
|
|
8
|
+
if (!req.Request_ID) {
|
|
9
|
+
const basename = path.basename(filePath, ".json");
|
|
10
|
+
// REQ_CODER_1 → CODER_1
|
|
11
|
+
req.Request_ID = basename.replace(/^REQ_/, "");
|
|
12
|
+
}
|
|
13
|
+
// Set defaults
|
|
14
|
+
req.Type = req.Type || "LAUNCH_AGENT";
|
|
15
|
+
req.Depth = req.Depth ?? 0;
|
|
16
|
+
// Terminate_After: Only set if explicitly specified in JSON.
|
|
17
|
+
// Template merger and agent-manager set the default later.
|
|
18
|
+
// An early default here would override template values (e.g. Terminate_After: false).
|
|
19
|
+
req._RequestFile = filePath;
|
|
20
|
+
return req;
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
log.error(`JSON parse failed: ${filePath}: ${e}`);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const VALID_TOOLS = new Set(["opencode", "opencode-run", "gemini-cli", "claude"]);
|
|
28
|
+
const SAFE_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
29
|
+
const MAX_COMMAND_LENGTH = 50_000; // 50KB max
|
|
30
|
+
export function validateRequest(req, maxDepth, log) {
|
|
31
|
+
const id = req.Agent_ID || "?";
|
|
32
|
+
if (req.Type === "LAUNCH_AGENT") {
|
|
33
|
+
if (!req.Command) {
|
|
34
|
+
log.error(`${id}: No command specified`);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if ((req.Depth ?? 0) > maxDepth) {
|
|
38
|
+
log.error(`${id}: Spawn-Depth ${req.Depth} > Max ${maxDepth}`);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Agent_ID: only safe characters
|
|
43
|
+
if (req.Agent_ID && !SAFE_ID_PATTERN.test(req.Agent_ID)) {
|
|
44
|
+
log.error(`${id}: Agent_ID contains invalid characters (allowed: A-Z, 0-9, _, -)`);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// Tool: must be known
|
|
48
|
+
if (req.Tool && !VALID_TOOLS.has(req.Tool)) {
|
|
49
|
+
log.error(`${id}: Unknown tool '${req.Tool}' (allowed: ${[...VALID_TOOLS].join(", ")})`);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Command: length limit
|
|
53
|
+
if (req.Command && req.Command.length > MAX_COMMAND_LENGTH) {
|
|
54
|
+
log.error(`${id}: Command too long (${req.Command.length} > ${MAX_COMMAND_LENGTH} bytes)`);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
// Depth: must be non-negative
|
|
58
|
+
if (req.Depth !== undefined && (req.Depth < 0 || !Number.isInteger(req.Depth))) {
|
|
59
|
+
log.error(`${id}: Invalid depth ${req.Depth} (must be >= 0 and an integer)`);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface LogContext {
|
|
2
|
+
agent_id?: string;
|
|
3
|
+
pid?: number;
|
|
4
|
+
tool?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
[key: string]: string | number | boolean | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare class Logger {
|
|
9
|
+
private logFile;
|
|
10
|
+
private maxBytes;
|
|
11
|
+
private jsonMode;
|
|
12
|
+
private minLevel;
|
|
13
|
+
constructor(logDir: string, maxBytes: number, jsonMode?: boolean, minLevelStr?: string);
|
|
14
|
+
info(msg: string, ctx?: LogContext): void;
|
|
15
|
+
warn(msg: string, ctx?: LogContext): void;
|
|
16
|
+
error(msg: string, ctx?: LogContext): void;
|
|
17
|
+
action(msg: string, ctx?: LogContext): void;
|
|
18
|
+
debug(msg: string, ctx?: LogContext): void;
|
|
19
|
+
private write;
|
|
20
|
+
private rotate;
|
|
21
|
+
}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const LEVEL_PRIORITY = {
|
|
4
|
+
DEBUG: 0,
|
|
5
|
+
INFO: 1,
|
|
6
|
+
ACTION: 1,
|
|
7
|
+
WARN: 2,
|
|
8
|
+
ERROR: 3,
|
|
9
|
+
};
|
|
10
|
+
export class Logger {
|
|
11
|
+
logFile;
|
|
12
|
+
maxBytes;
|
|
13
|
+
jsonMode;
|
|
14
|
+
minLevel;
|
|
15
|
+
constructor(logDir, maxBytes, jsonMode = false, minLevelStr = "info") {
|
|
16
|
+
if (!fs.existsSync(logDir)) {
|
|
17
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
this.logFile = path.join(logDir, "council_log.txt");
|
|
20
|
+
this.maxBytes = maxBytes;
|
|
21
|
+
this.jsonMode = jsonMode;
|
|
22
|
+
this.minLevel = LEVEL_PRIORITY[minLevelStr.toUpperCase()] ?? 1;
|
|
23
|
+
}
|
|
24
|
+
info(msg, ctx) { this.write("INFO", msg, ctx); }
|
|
25
|
+
warn(msg, ctx) { this.write("WARN", msg, ctx); }
|
|
26
|
+
error(msg, ctx) { this.write("ERROR", msg, ctx); }
|
|
27
|
+
action(msg, ctx) { this.write("ACTION", msg, ctx); }
|
|
28
|
+
debug(msg, ctx) { this.write("DEBUG", msg, ctx); }
|
|
29
|
+
write(level, msg, ctx) {
|
|
30
|
+
const priority = LEVEL_PRIORITY[level] ?? 1;
|
|
31
|
+
if (priority < this.minLevel)
|
|
32
|
+
return;
|
|
33
|
+
let line;
|
|
34
|
+
if (this.jsonMode) {
|
|
35
|
+
const entry = {
|
|
36
|
+
ts: new Date().toISOString(),
|
|
37
|
+
level,
|
|
38
|
+
msg,
|
|
39
|
+
};
|
|
40
|
+
// Agent-Kontext als separate Felder
|
|
41
|
+
if (ctx) {
|
|
42
|
+
for (const [k, v] of Object.entries(ctx)) {
|
|
43
|
+
if (v !== undefined)
|
|
44
|
+
entry[k] = v;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
line = JSON.stringify(entry) + "\n";
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const ts = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
51
|
+
const ctxStr = ctx?.agent_id ? ` [${ctx.agent_id}]` : "";
|
|
52
|
+
line = `[${ts}] [${level}]${ctxStr} ${msg}\n`;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
this.rotate();
|
|
56
|
+
fs.appendFileSync(this.logFile, line, "utf-8");
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
process.stderr.write(`Logger error: ${e}\n`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
rotate() {
|
|
63
|
+
try {
|
|
64
|
+
if (!fs.existsSync(this.logFile))
|
|
65
|
+
return;
|
|
66
|
+
const stat = fs.statSync(this.logFile);
|
|
67
|
+
if (stat.size < this.maxBytes)
|
|
68
|
+
return;
|
|
69
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
70
|
+
const archive = this.logFile.replace(".txt", `_${ts}.txt`);
|
|
71
|
+
fs.renameSync(this.logFile, archive);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Rotation fehlgeschlagen — weiter loggen
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* hmem — Humanlike Memory MCP Server.
|
|
4
|
+
*
|
|
5
|
+
* Provides persistent, hierarchical memory for AI agents via MCP.
|
|
6
|
+
* SQLite-backed, 5-level lazy loading, role-based access control.
|
|
7
|
+
*
|
|
8
|
+
* Environment variables:
|
|
9
|
+
* HMEM_PROJECT_DIR — Root directory where .hmem files are stored (required)
|
|
10
|
+
* HMEM_AGENT_ID — Agent identifier (optional; defaults to memory.hmem)
|
|
11
|
+
* HMEM_AGENT_ROLE — Role: worker | al | pl | ceo (default: worker)
|
|
12
|
+
* HMEM_AUDIT_STATE_PATH — Path to audit_state.json (default: {PROJECT_DIR}/audit_state.json)
|
|
13
|
+
*
|
|
14
|
+
* Legacy fallbacks (Das Althing):
|
|
15
|
+
* COUNCIL_PROJECT_DIR, COUNCIL_AGENT_ID, COUNCIL_AGENT_ROLE
|
|
16
|
+
*/
|
|
17
|
+
export {};
|