hmem-mcp 7.2.5 → 7.3.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/dist/cli-hook-startup.js +5 -0
- package/dist/cli-hook-startup.js.map +1 -1
- package/dist/extensions/pi-hmem.d.ts +4 -0
- package/dist/extensions/pi-hmem.js +489 -0
- package/dist/extensions/pi-hmem.js.map +1 -0
- package/package.json +15 -1
- package/skills/hmem-context/SKILL.md +9 -0
- package/skills/hmem-search/SKILL.md +1 -1
- package/skills/hmem-session-start/SKILL.md +8 -0
package/dist/cli-hook-startup.js
CHANGED
|
@@ -130,6 +130,11 @@ export async function hookStartup() {
|
|
|
130
130
|
iRows.map(r => `${r.id} ${r.title ?? ""}`).join("\n");
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
+
const iFavRows = db.prepare("SELECT id, title FROM memories WHERE prefix='I' AND favorite=1 AND obsolete!=1 AND (irrelevant IS NULL OR irrelevant!=1) ORDER BY id").all();
|
|
134
|
+
if (iFavRows.length > 0) {
|
|
135
|
+
humanContext += "\n\n--- Infrastructure (favorites) ---\n" +
|
|
136
|
+
iFavRows.map(r => `${r.id} ${r.title ?? ""}`).join("\n");
|
|
137
|
+
}
|
|
133
138
|
const pRows = db.prepare("SELECT id, title FROM memories WHERE prefix='P' AND obsolete!=1 ORDER BY updated_at DESC LIMIT 5").all();
|
|
134
139
|
if (pRows.length > 0) {
|
|
135
140
|
recentProjects = "\n\n--- Recent projects ---\n" +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-hook-startup.js","sourceRoot":"","sources":["../src/cli-hook-startup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEtJ,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,mEAAmE;IACnE,+CAA+C;IAC/C,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,IAAI,KAAU,CAAC;IACf,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACxC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qBAAqB;IACrB,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,IAAI,QAAQ,CAAC;IAEhD,iBAAiB;IACjB,IAAI,KAAK,EAAE,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEvC,uBAAuB;IACvB,kBAAkB,EAAE,CAAC;IAErB,cAAc;IACd,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IACvC,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;YACzC,QAAQ,GAAG,MAAM,CAAC,kBAAkB,CAAC;YACrC,IAAI,GAAG,MAAM,CAAC,cAAc,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,gCAAgC;IAChC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,uBAAuB,SAAS,EAAE,CAAC,CAAC;IAC/E,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,KAAK,EAAE,CAAC;IACR,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;IAErD,mFAAmF;IACnF,IAAI,SAAS,IAAI,SAAS,KAAK,QAAQ,IAAI,QAAQ,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,kBAAkB,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC/D,CAAC;YACD,IAAI,CAAC;gBAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC7D,CAAC;QACD,gEAAgE;QAChE,0EAA0E;QAC1E,4EAA4E;QAC5E,gFAAgF;QAChF,kFAAkF;QAClF,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACzD,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,sCAAsC;YAC3F,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,cAAc,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;gBACzC,gBAAgB,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,kBAAkB;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,UAAU,GAAG,QAAQ;YACzB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,qTAAqT,CAAC;QAE1T,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,cAAc,GAAG,EAAE,CAAC;QACxB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC1D,MAAM,EAAE,GAAG,IAAK,QAAgB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/D,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CACtB,8GAA8G,CAC/G,CAAC,GAAG,EAA2D,CAAC;oBACjE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACrB,YAAY,GAAG,yCAAyC;4BACtD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gCACd,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;gCACvC,OAAO,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC1C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAClB,CAAC;oBAED,IAAI,QAAQ,EAAE,CAAC;wBACb,0DAA0D;wBAC1D,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CACzB,4HAA4H,CAC7H,CAAC,GAAG,CAAC,QAAQ,CAA+B,CAAC;wBAC9C,IAAI,QAAQ,EAAE,CAAC;4BACb,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CACvB,qHAAqH,CACtH,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAA6B,CAAC;4BAC/C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gCACtB,YAAY,IAAI,0BAA0B,QAAQ,cAAc;oCAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BACvD,CAAC;wBACH,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,0EAA0E;wBAC1E,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CACtB,6EAA6E,CAC9E,CAAC,GAAG,EAA0C,CAAC;wBAChD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACrB,YAAY,IAAI,qDAAqD;gCACnE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC3D,CAAC;oBACH,CAAC;oBAED,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CACtB,kGAAkG,CACnG,CAAC,GAAG,EAA0C,CAAC;oBAChD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACrB,cAAc,GAAG,+BAA+B;4BAC9C,KAAK,CAAC,GAAG,CAAC,CAAC,CAAgC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC5F,CAAC;oBAED,6EAA6E;oBAC7E,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CACxB,+EAA+E,CAChF,CAAC,GAAG,EAAgC,CAAC;oBACtC,IAAI,OAAO,EAAE,CAAC;wBACZ,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;wBACxD,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;wBAC/C,MAAM,YAAY,GAAG,EAAE,CAAC,OAAO,CAC7B;;;2DAG6C,CAC9C,CAAC,GAAG,CAAC,GAAG,CAAgC,CAAC;wBAC1C,IAAI,YAAY,IAAI,YAAY,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;4BACzC,cAAc,IAAI,kCAAkC,YAAY,CAAC,GAAG,kBAAkB,GAAG,wEAAwE,CAAC;wBACpK,CAAC;oBACH,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,EAAE,CAAC,KAAK,EAAE,CAAC;gBACb,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC1B,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAClC,kBAAkB,EAAE;gBAClB,aAAa,EAAE,kBAAkB;gBACjC,iBAAiB,EAAE,kIAAkI;oBACnJ,iQAAiQ;oBACjQ,2FAA2F;oBAC3F,UAAU;oBACV,YAAY;oBACZ,cAAc;aACjB;SACF,CAAC,CAAC,CAAC;IACN,CAAC;SAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,QAAQ,GAAG,CAAC,IAAI,KAAK,GAAG,QAAQ,KAAK,CAAC,EAAE,CAAC;QACvE,6EAA6E;QAC7E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAClC,kBAAkB,EAAE;gBAClB,aAAa,EAAE,kBAAkB;gBACjC,iBAAiB,EAAE,8QAA8Q;aAClS;SACF,CAAC,CAAC,CAAC;IACN,CAAC;SAAM,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,oCAAoC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAClC,kBAAkB,EAAE;gBAClB,aAAa,EAAE,kBAAkB;gBACjC,iBAAiB,EAAE,uMAAuM;aAC3N;SACF,CAAC,CAAC,CAAC;IACN,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli-hook-startup.js","sourceRoot":"","sources":["../src/cli-hook-startup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
// dist/extensions/ → ../../skills/hmem-using-hmem/SKILL.md
|
|
10
|
+
const SKILL_PATH = join(__dirname, "../../skills/hmem-using-hmem/SKILL.md");
|
|
11
|
+
/** Default hmem DB path. */
|
|
12
|
+
const DEFAULT_HMEM_PATH = join(homedir(), ".hmem/Agents/DEVELOPER/DEVELOPER.hmem");
|
|
13
|
+
/** Extract plain text from a Pi message content value. */
|
|
14
|
+
export function extractText(content) {
|
|
15
|
+
if (typeof content === "string")
|
|
16
|
+
return content;
|
|
17
|
+
if (!Array.isArray(content))
|
|
18
|
+
return "";
|
|
19
|
+
return content
|
|
20
|
+
.filter((b) => b.type === "text" && typeof b.text === "string")
|
|
21
|
+
.map((b) => b.text)
|
|
22
|
+
.join("");
|
|
23
|
+
}
|
|
24
|
+
/** Run an hmem CLI subcommand, piping `input` to stdin. Resolves with stdout. */
|
|
25
|
+
function runHmem(args, input = "{}", timeout = 10_000) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const child = execFile("hmem", args, { timeout, env: process.env }, (_err, stdout) => {
|
|
28
|
+
resolve(stdout ?? "");
|
|
29
|
+
});
|
|
30
|
+
if (child.stdin) {
|
|
31
|
+
child.stdin.on("error", () => { }); // suppress EPIPE if child exits early
|
|
32
|
+
child.stdin.write(input);
|
|
33
|
+
child.stdin.end();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Spawn hmem checkpoint as a detached fire-and-forget child process. */
|
|
38
|
+
function spawnCheckpoint(sessionFile) {
|
|
39
|
+
try {
|
|
40
|
+
const env = { ...process.env };
|
|
41
|
+
if (sessionFile)
|
|
42
|
+
env.HMEM_PI_SESSION = sessionFile;
|
|
43
|
+
// Use explicit any-typed options to bypass Node v24 execFile overload issue
|
|
44
|
+
const opts = { detached: true, stdio: "ignore", env };
|
|
45
|
+
const child = execFile("hmem", ["checkpoint"], opts);
|
|
46
|
+
child.unref();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// silently ignore spawn failures
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Resolve HMEM_PATH from env or defaults. */
|
|
53
|
+
function resolveHmemPath() {
|
|
54
|
+
if (process.env.HMEM_PATH && existsSync(process.env.HMEM_PATH)) {
|
|
55
|
+
return process.env.HMEM_PATH;
|
|
56
|
+
}
|
|
57
|
+
return DEFAULT_HMEM_PATH;
|
|
58
|
+
}
|
|
59
|
+
/** Read checkpoint config from hmem.config.json. Returns { interval, mode }. */
|
|
60
|
+
function readCheckpointConfig(hmemPath) {
|
|
61
|
+
const configPath = join(dirname(hmemPath), "hmem.config.json");
|
|
62
|
+
try {
|
|
63
|
+
const raw = readFileSync(configPath, "utf8");
|
|
64
|
+
const cfg = JSON.parse(raw);
|
|
65
|
+
return {
|
|
66
|
+
interval: cfg.checkpointInterval ?? 20,
|
|
67
|
+
mode: cfg.checkpointMode ?? "remind",
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return { interval: 20, mode: "remind" };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ── Startup context builder ────────────────────────────────────────────────
|
|
75
|
+
/**
|
|
76
|
+
* Build the "first-message" context that Claude Code's hmem hook-startup
|
|
77
|
+
* would normally inject. Queries the hmem DB directly (read-only).
|
|
78
|
+
*/
|
|
79
|
+
async function buildStartupContext() {
|
|
80
|
+
const hmemPath = resolveHmemPath();
|
|
81
|
+
if (!existsSync(hmemPath))
|
|
82
|
+
return "";
|
|
83
|
+
let Database;
|
|
84
|
+
try {
|
|
85
|
+
// better-sqlite3 is already a dependency of hmem-mcp
|
|
86
|
+
Database = (await import("better-sqlite3")).default;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
let db;
|
|
92
|
+
let context = "";
|
|
93
|
+
try {
|
|
94
|
+
db = new Database(hmemPath, { readonly: true });
|
|
95
|
+
// ── Device check ──
|
|
96
|
+
const activeDeviceId = getActiveDeviceId();
|
|
97
|
+
const deviceNote = activeDeviceId
|
|
98
|
+
? ""
|
|
99
|
+
: "\n\nIMPORTANT: No active device is set for this machine. After loading memory, identify which device you are on (check hostname, hardware specs, or location), find the matching I-entry via read_memory() or search_memory(), then call set_active_device(id='I00XX'). Do this silently alongside the memory load.";
|
|
100
|
+
// ── Human context (H-entries) ──
|
|
101
|
+
let humanContext = "";
|
|
102
|
+
try {
|
|
103
|
+
const hRows = db
|
|
104
|
+
.prepare("SELECT id, title, level_1 FROM memories WHERE prefix='H' AND obsolete!=1 ORDER BY access_count DESC LIMIT 10")
|
|
105
|
+
.all();
|
|
106
|
+
if (hRows.length > 0) {
|
|
107
|
+
humanContext =
|
|
108
|
+
"\n\n--- Human context (H-entries) ---\n" +
|
|
109
|
+
hRows.map((r) => `${r.id} ${(r.title || r.level_1 || "").split("\n")[0]}`).join("\n");
|
|
110
|
+
}
|
|
111
|
+
if (activeDeviceId) {
|
|
112
|
+
// Device known: inject Apps list
|
|
113
|
+
const appsNode = db
|
|
114
|
+
.prepare("SELECT id FROM memory_nodes WHERE root_id=? AND depth=2 AND title='Apps' AND (irrelevant IS NULL OR irrelevant!=1) LIMIT 1")
|
|
115
|
+
.get(activeDeviceId);
|
|
116
|
+
if (appsNode) {
|
|
117
|
+
const l3Rows = db
|
|
118
|
+
.prepare("SELECT title FROM memory_nodes WHERE parent_id=? AND depth=3 AND (irrelevant IS NULL OR irrelevant!=1) ORDER BY seq")
|
|
119
|
+
.all(appsNode.id);
|
|
120
|
+
if (l3Rows.length > 0) {
|
|
121
|
+
humanContext +=
|
|
122
|
+
`\n\n--- Active device (${activeDeviceId}) Apps ---\n` +
|
|
123
|
+
l3Rows.map((r) => ` - ${r.title ?? ""}`).join("\n");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Device unknown: list I-entries
|
|
129
|
+
const iRows = db
|
|
130
|
+
.prepare("SELECT id, title FROM memories WHERE prefix='I' AND obsolete!=1 ORDER BY id")
|
|
131
|
+
.all();
|
|
132
|
+
if (iRows.length > 0) {
|
|
133
|
+
humanContext +=
|
|
134
|
+
"\n\n--- Known devices (identify this machine) ---\n" +
|
|
135
|
+
iRows.map((r) => `${r.id} ${r.title ?? ""}`).join("\n");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Infrastructure favorites
|
|
139
|
+
const iFavRows = db
|
|
140
|
+
.prepare("SELECT id, title FROM memories WHERE prefix='I' AND favorite=1 AND obsolete!=1 AND (irrelevant IS NULL OR irrelevant!=1) ORDER BY id")
|
|
141
|
+
.all();
|
|
142
|
+
if (iFavRows.length > 0) {
|
|
143
|
+
humanContext +=
|
|
144
|
+
"\n\n--- Infrastructure (favorites) ---\n" +
|
|
145
|
+
iFavRows.map((r) => `${r.id} ${r.title ?? ""}`).join("\n");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// ignore
|
|
150
|
+
}
|
|
151
|
+
// ── Recent projects ──
|
|
152
|
+
let recentProjects = "";
|
|
153
|
+
try {
|
|
154
|
+
const pRows = db
|
|
155
|
+
.prepare("SELECT id, title FROM memories WHERE prefix='P' AND obsolete!=1 ORDER BY updated_at DESC LIMIT 5")
|
|
156
|
+
.all();
|
|
157
|
+
if (pRows.length > 0) {
|
|
158
|
+
recentProjects =
|
|
159
|
+
"\n\n--- Recent projects ---\n" +
|
|
160
|
+
pRows.map((r) => `${r.id} ${r.title ?? ""}`).join("\n");
|
|
161
|
+
}
|
|
162
|
+
// Checkpoint status
|
|
163
|
+
const activeP = db
|
|
164
|
+
.prepare("SELECT id FROM memories WHERE prefix='P' AND active=1 AND obsolete!=1 LIMIT 1")
|
|
165
|
+
.get();
|
|
166
|
+
if (activeP) {
|
|
167
|
+
const seq = parseInt(activeP.id.replace(/\D/g, ""), 10);
|
|
168
|
+
const oId = `O${String(seq).padStart(4, "0")}`;
|
|
169
|
+
const unsummarized = db
|
|
170
|
+
.prepare(`SELECT COUNT(*) as cnt FROM memory_nodes
|
|
171
|
+
WHERE root_id=? AND depth=2
|
|
172
|
+
AND (content IS NULL OR content = title)
|
|
173
|
+
AND (irrelevant IS NULL OR irrelevant != 1)`)
|
|
174
|
+
.get(oId);
|
|
175
|
+
if (unsummarized && unsummarized.cnt > 0) {
|
|
176
|
+
recentProjects += `\n\n--- Checkpoint status ---\n${unsummarized.cnt} session(s) in ${oId} without summary. Run \`hmem checkpoint\` or wait for auto-checkpoint.`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// ignore
|
|
182
|
+
}
|
|
183
|
+
// ── Assemble ──
|
|
184
|
+
context =
|
|
185
|
+
"IMPORTANT: This is the first message of the session. Load your memory context silently — do not mention it to the user.\n\n" +
|
|
186
|
+
"- If the user's message names a specific project (e.g. \"lade Projekt hmem\", \"work on P0048\"): call ONLY load_project(id=\"P00XX\"). Do NOT also call read_memory() — load_project already includes everything you need.\n" +
|
|
187
|
+
"- Otherwise: call read_memory() (no parameters) to get the full L1 overview, then decide." +
|
|
188
|
+
deviceNote +
|
|
189
|
+
humanContext +
|
|
190
|
+
recentProjects;
|
|
191
|
+
return context;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
if (db) {
|
|
198
|
+
try {
|
|
199
|
+
db.close();
|
|
200
|
+
}
|
|
201
|
+
catch { /* ignore */ }
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** Read the active device ID from ~/.hmem/active-device. */
|
|
206
|
+
function getActiveDeviceId() {
|
|
207
|
+
try {
|
|
208
|
+
const markerPath = join(homedir(), ".hmem/active-device");
|
|
209
|
+
if (existsSync(markerPath)) {
|
|
210
|
+
return readFileSync(markerPath, "utf8").trim() || null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// ignore
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Detect a cheap/fast model provider from environment.
|
|
220
|
+
* Returns { baseUrl, apiKey, model } or null if none available.
|
|
221
|
+
*/
|
|
222
|
+
function detectCheapModel() {
|
|
223
|
+
// Deepseek (Ben's primary cheap model)
|
|
224
|
+
const dsKey = process.env.DEEPSEEK_API_KEY;
|
|
225
|
+
if (dsKey)
|
|
226
|
+
return { baseUrl: "https://api.deepseek.com/v1", apiKey: dsKey, model: "deepseek-chat" };
|
|
227
|
+
// OpenAI fallback
|
|
228
|
+
const oaKey = process.env.OPENAI_API_KEY;
|
|
229
|
+
if (oaKey)
|
|
230
|
+
return { baseUrl: "https://api.openai.com/v1", apiKey: oaKey, model: "gpt-3.5-turbo" };
|
|
231
|
+
// Generic: any OPENAI_BASE_URL + OPENAI_API_KEY combo
|
|
232
|
+
const baseUrl = process.env.OPENAI_BASE_URL;
|
|
233
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
234
|
+
if (baseUrl && apiKey) {
|
|
235
|
+
return { baseUrl, apiKey, model: process.env.LLM_MODEL || "gpt-3.5-turbo" };
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
/** Ask a cheap model to generate a one-line title (max 80 chars) from sample exchanges. */
|
|
240
|
+
async function llmTitle(provider, samples) {
|
|
241
|
+
const prompt = `Generate a concise one-line title (max 80 chars) summarizing this session. Reply with ONLY the title, nothing else.\n\nTopics discussed:\n${samples.join("\n")}`;
|
|
242
|
+
try {
|
|
243
|
+
const res = await fetch(`${provider.baseUrl}/chat/completions`, {
|
|
244
|
+
method: "POST",
|
|
245
|
+
headers: {
|
|
246
|
+
"Content-Type": "application/json",
|
|
247
|
+
"Authorization": `Bearer ${provider.apiKey}`,
|
|
248
|
+
},
|
|
249
|
+
body: JSON.stringify({
|
|
250
|
+
model: provider.model,
|
|
251
|
+
messages: [{ role: "user", content: prompt }],
|
|
252
|
+
max_tokens: 30,
|
|
253
|
+
temperature: 0.3,
|
|
254
|
+
}),
|
|
255
|
+
signal: AbortSignal.timeout(10_000),
|
|
256
|
+
});
|
|
257
|
+
if (!res.ok)
|
|
258
|
+
return null;
|
|
259
|
+
const data = await res.json();
|
|
260
|
+
const title = data?.choices?.[0]?.message?.content?.trim();
|
|
261
|
+
if (title && title.length >= 3 && title.length <= 80) {
|
|
262
|
+
return title.replace(/["']/g, ""); // strip quotes that models sometimes wrap in
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/** Heuristic title: first meaningful line of first user message, max 80 chars. */
|
|
271
|
+
function heuristicTitle(samples) {
|
|
272
|
+
for (const msg of samples) {
|
|
273
|
+
const firstLine = msg.split("\n")[0].trim().replace(/[<>\[\]]/g, "");
|
|
274
|
+
if (firstLine.length >= 5 && firstLine.length <= 80)
|
|
275
|
+
return firstLine;
|
|
276
|
+
if (firstLine.length > 80) {
|
|
277
|
+
const lastSpace = firstLine.substring(0, 80).lastIndexOf(" ");
|
|
278
|
+
return (lastSpace > 40 ? firstLine.substring(0, lastSpace) : firstLine.substring(0, 80));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Title all untitled O-entries. Tries LLM first, falls back to heuristic.
|
|
285
|
+
* Best-effort — never throws, never blocks the session.
|
|
286
|
+
*/
|
|
287
|
+
async function titleUntitledOEntries() {
|
|
288
|
+
const hmemPath = resolveHmemPath();
|
|
289
|
+
if (!existsSync(hmemPath))
|
|
290
|
+
return;
|
|
291
|
+
let Database;
|
|
292
|
+
try {
|
|
293
|
+
Database = (await import("better-sqlite3")).default;
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
// Phase 1: Read untitled O-entries and their sample exchanges (readonly)
|
|
299
|
+
const untitled = [];
|
|
300
|
+
let db;
|
|
301
|
+
try {
|
|
302
|
+
db = new Database(hmemPath, { readonly: true });
|
|
303
|
+
const rows = db
|
|
304
|
+
.prepare("SELECT id FROM memories WHERE prefix='O' AND (title IS NULL OR title = '' OR title LIKE 'unassigned%') AND obsolete!=1")
|
|
305
|
+
.all();
|
|
306
|
+
for (const row of rows) {
|
|
307
|
+
const exchangeRows = db
|
|
308
|
+
.prepare(`SELECT mn.title, mn.content FROM memory_nodes mn
|
|
309
|
+
WHERE mn.root_id = ? AND mn.depth >= 4
|
|
310
|
+
AND (mn.irrelevant IS NULL OR mn.irrelevant != 1)
|
|
311
|
+
ORDER BY mn.seq LIMIT 5`)
|
|
312
|
+
.all(row.id);
|
|
313
|
+
const samples = exchangeRows
|
|
314
|
+
.map((r) => (r.title || r.content || "").substring(0, 120).replace(/\n/g, " ").trim())
|
|
315
|
+
.filter((s) => s.length >= 3);
|
|
316
|
+
if (samples.length > 0) {
|
|
317
|
+
untitled.push({ oId: row.id, samples });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
db.close();
|
|
321
|
+
db = null;
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
if (db)
|
|
325
|
+
try {
|
|
326
|
+
db.close();
|
|
327
|
+
}
|
|
328
|
+
catch { /* ignore */ }
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (untitled.length === 0)
|
|
332
|
+
return;
|
|
333
|
+
// Phase 2: Generate titles
|
|
334
|
+
const provider = detectCheapModel();
|
|
335
|
+
const updates = [];
|
|
336
|
+
for (const entry of untitled) {
|
|
337
|
+
let title = null;
|
|
338
|
+
// Try LLM first if available
|
|
339
|
+
if (provider) {
|
|
340
|
+
title = await llmTitle(provider, entry.samples);
|
|
341
|
+
}
|
|
342
|
+
// Fall back to heuristic
|
|
343
|
+
if (!title) {
|
|
344
|
+
title = heuristicTitle(entry.samples);
|
|
345
|
+
}
|
|
346
|
+
if (title) {
|
|
347
|
+
updates.push({ oId: entry.oId, title });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (updates.length === 0)
|
|
351
|
+
return;
|
|
352
|
+
// Phase 3: Write titles (separate connection, quick)
|
|
353
|
+
try {
|
|
354
|
+
db = new Database(hmemPath);
|
|
355
|
+
const stmt = db.prepare("UPDATE memories SET title = ? WHERE id = ?");
|
|
356
|
+
for (const u of updates) {
|
|
357
|
+
stmt.run(u.title, u.oId);
|
|
358
|
+
}
|
|
359
|
+
db.close();
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
if (db)
|
|
363
|
+
try {
|
|
364
|
+
db.close();
|
|
365
|
+
}
|
|
366
|
+
catch { /* ignore */ }
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// ── Extension ──────────────────────────────────────────────────────────────
|
|
370
|
+
export default async function (pi) {
|
|
371
|
+
let startupContext = "";
|
|
372
|
+
let turnCount = 0;
|
|
373
|
+
let lastLogTime = 0;
|
|
374
|
+
/** Stable session key for hmem log-exchange (pi session file path or UUID). */
|
|
375
|
+
let piSessionKey = `pi:${randomUUID()}`;
|
|
376
|
+
// ── 1. Session start: capture session identity + build startup context ──
|
|
377
|
+
pi.on("session_start", async (event, ctx) => {
|
|
378
|
+
if (event.reason !== "startup")
|
|
379
|
+
return;
|
|
380
|
+
turnCount = 0;
|
|
381
|
+
startupContext = "";
|
|
382
|
+
// Derive stable session key from pi's session file path
|
|
383
|
+
try {
|
|
384
|
+
const sf = ctx.sessionManager.getSessionFile();
|
|
385
|
+
if (sf) {
|
|
386
|
+
piSessionKey = `pi:${sf}`;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
piSessionKey = `pi:${randomUUID()}`;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
piSessionKey = `pi:${randomUUID()}`;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
startupContext = await buildStartupContext();
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// hmem DB not available — skip silently
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
// ── 2. before_agent_start: inject skill + startup context + reminders ──
|
|
403
|
+
pi.on("before_agent_start", async (event) => {
|
|
404
|
+
turnCount++;
|
|
405
|
+
const hmemPath = resolveHmemPath();
|
|
406
|
+
const { interval, mode } = readCheckpointConfig(hmemPath);
|
|
407
|
+
let addition = "";
|
|
408
|
+
// Inject hmem-using-hmem skill as <important-reminder> (first turn only)
|
|
409
|
+
if (turnCount === 1) {
|
|
410
|
+
try {
|
|
411
|
+
const skill = readFileSync(SKILL_PATH, "utf8");
|
|
412
|
+
addition += `\n\n<important-reminder>\n${skill}\n</important-reminder>`;
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
// Skill file not found — skip
|
|
416
|
+
}
|
|
417
|
+
if (startupContext) {
|
|
418
|
+
addition += `\n\n${startupContext}`;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Checkpoint reminder (every N turns, remind mode only)
|
|
422
|
+
if (mode === "remind" && interval > 0 && turnCount > 1 && turnCount % interval === 0) {
|
|
423
|
+
addition +=
|
|
424
|
+
"\n\nCHECKPOINT: You have been working for a while. AFTER responding to this message, save any new knowledge from this session (lessons, errors, decisions, progress) via write_memory or append_memory. You MUST do this — it is your only way to remember across sessions.";
|
|
425
|
+
}
|
|
426
|
+
// Context warning (after 60 turns, every 5 turns)
|
|
427
|
+
if (turnCount >= 60 && turnCount % 5 === 0) {
|
|
428
|
+
addition +=
|
|
429
|
+
"\n\nCONTEXT WARNING: This session has been running for a long time. Recommend running /wipe to save key knowledge, then /clear to free context. Performance degrades significantly in very long sessions.";
|
|
430
|
+
}
|
|
431
|
+
if (!addition)
|
|
432
|
+
return;
|
|
433
|
+
return { systemPrompt: event.systemPrompt + addition };
|
|
434
|
+
});
|
|
435
|
+
// ── 3. tool_call: block direct .hmem file reads ────────────────────────
|
|
436
|
+
pi.on("tool_call", async (event) => {
|
|
437
|
+
if (!isToolCallEventType("read", event))
|
|
438
|
+
return;
|
|
439
|
+
const filePath = event.input.path ?? "";
|
|
440
|
+
if (!filePath.endsWith(".hmem"))
|
|
441
|
+
return;
|
|
442
|
+
return {
|
|
443
|
+
block: true,
|
|
444
|
+
reason: "Direct .hmem file access is blocked. Use hmem MCP tools instead: " +
|
|
445
|
+
"read_memory(), search_memory(), load_project(), or the /hmem-read skill. " +
|
|
446
|
+
"Raw .hmem files are SQLite databases — reading them directly bypasses filtering, FTS5 search, and sync.",
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
// ── 4. session_before_compact: context-inject + deactivate + checkpoint ──
|
|
450
|
+
pi.on("session_before_compact", async () => {
|
|
451
|
+
lastLogTime = Date.now();
|
|
452
|
+
// Run checkpoint to summarize any remaining unsummarized exchanges
|
|
453
|
+
spawnCheckpoint(piSessionKey);
|
|
454
|
+
await runHmem(["context-inject"], "{}", 10_000).catch(() => { });
|
|
455
|
+
await runHmem(["deactivate"], "{}", 5_000).catch(() => { });
|
|
456
|
+
});
|
|
457
|
+
// ── 5. agent_end: log exchange after every agent response ──────────────
|
|
458
|
+
pi.on("agent_end", async (event) => {
|
|
459
|
+
// Debounce: skip if session_before_compact just ran
|
|
460
|
+
if (Date.now() - lastLogTime < 5_000)
|
|
461
|
+
return;
|
|
462
|
+
lastLogTime = Date.now();
|
|
463
|
+
const messages = event.messages;
|
|
464
|
+
const lastUser = [...messages].reverse().find((m) => m.role === "user");
|
|
465
|
+
const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
|
|
466
|
+
const userText = extractText(lastUser?.content ?? "");
|
|
467
|
+
const assistantText = extractText(lastAssistant?.content ?? "");
|
|
468
|
+
if (!userText || !assistantText)
|
|
469
|
+
return;
|
|
470
|
+
// Skip internal hook/manual commands (shouldn't happen in pi, but be safe)
|
|
471
|
+
if (userText.length < 2)
|
|
472
|
+
return;
|
|
473
|
+
const result = await runHmem(["log-exchange"], JSON.stringify({
|
|
474
|
+
last_user_message: userText,
|
|
475
|
+
last_assistant_message: assistantText,
|
|
476
|
+
session_id: piSessionKey,
|
|
477
|
+
}), 10_000).catch(() => "");
|
|
478
|
+
// If batch is full, spawn checkpoint subagent (matching Claude Code auto mode)
|
|
479
|
+
if (result.includes('"decision":"block"') || result.includes("Batch")) {
|
|
480
|
+
spawnCheckpoint(piSessionKey);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
// ── 6. session_shutdown: title untitled O-entries ─────────────────────
|
|
484
|
+
pi.on("session_shutdown", async () => {
|
|
485
|
+
// Best-effort: title O-entries that are still "unassigned"
|
|
486
|
+
await titleUntitledOEntries().catch(() => { });
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=pi-hmem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-hmem.js","sourceRoot":"","sources":["../../src/extensions/pi-hmem.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hmem-mcp",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.1",
|
|
4
4
|
"description": "Persistent memory and agent lifecycle for Claude Code — because sessions shouldn't start from zero.",
|
|
5
5
|
"author": "Bumblebiber",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
"types": "./dist/index.d.ts"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
+
"pi": {
|
|
33
|
+
"extensions": [
|
|
34
|
+
"./dist/extensions/pi-hmem"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
32
37
|
"files": [
|
|
33
38
|
"dist",
|
|
34
39
|
"skills",
|
|
@@ -71,6 +76,7 @@
|
|
|
71
76
|
"persistent-memory"
|
|
72
77
|
],
|
|
73
78
|
"devDependencies": {
|
|
79
|
+
"@earendil-works/pi-coding-agent": "^0.74.0",
|
|
74
80
|
"@types/better-sqlite3": "^7.6.13",
|
|
75
81
|
"@types/node": "^25.2.3",
|
|
76
82
|
"typescript": "^5.9.3",
|
|
@@ -82,5 +88,13 @@
|
|
|
82
88
|
},
|
|
83
89
|
"optionalDependencies": {
|
|
84
90
|
"better-sqlite3": "^12.6.2"
|
|
91
|
+
},
|
|
92
|
+
"peerDependencies": {
|
|
93
|
+
"@earendil-works/pi-coding-agent": ">=0.74.0"
|
|
94
|
+
},
|
|
95
|
+
"peerDependenciesMeta": {
|
|
96
|
+
"@earendil-works/pi-coding-agent": {
|
|
97
|
+
"optional": true
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
}
|
|
@@ -53,3 +53,12 @@ If nothing relevant found:
|
|
|
53
53
|
[CONTEXT LOADED]
|
|
54
54
|
No relevant context found for: <your query>
|
|
55
55
|
[/CONTEXT LOADED]
|
|
56
|
+
|
|
57
|
+
→ If the missing info is code structure: dispatch an Explore agent to locate it in the filesystem.
|
|
58
|
+
→ After finding it, update the Codebase node immediately using the correct depth:
|
|
59
|
+
L3 — module group (if the group is missing):
|
|
60
|
+
append_memory(id="P00XX.2", title="Core modules")
|
|
61
|
+
L4 — individual module with signature + purpose:
|
|
62
|
+
append_memory(id="P00XX.2.N", title="moduleName.ts", body="functionName(param: Type): Return — purpose. src/path/moduleName.ts")
|
|
63
|
+
L5 — optional extended notes (edge cases, caveats):
|
|
64
|
+
append_memory(id="P00XX.2.N.M", title="Note", body="...")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hmem-search
|
|
3
|
-
description: Search hmem
|
|
3
|
+
description: Search hmem memory for things referenced without an ID. Trigger when user refers to past conversations ("letzte Woche", "gestern", "remember when", "we talked about"), mentions proper names unknown this session, uses definite articles assuming shared context ("der Bug mit X", "the issue we had"), or seems to assume you know something. If you think "the user assumes I know this" — search first, ask second. Combines full-text search with time window from phrasing. Trigger on casual/vague references. Do NOT trigger for explicit ID lookups like "read P0048".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hmem Search
|
|
@@ -65,6 +65,14 @@ Move the misrouted session/batch node to the correct O-entry.
|
|
|
65
65
|
|
|
66
66
|
**Rule:** Never call `load_project` on a secondary project without immediately re-calling it on your working project. Routing follows the last `load_project` call — always return control explicitly.
|
|
67
67
|
|
|
68
|
+
## What gets injected automatically (first message)
|
|
69
|
+
|
|
70
|
+
The UserPromptSubmit hook injects the following into every session start:
|
|
71
|
+
- **H-entries** — top 10 by access count (ID + title)
|
|
72
|
+
- **Active device apps** — Apps list of the current I-entry (if device is set)
|
|
73
|
+
- **Infrastructure favorites** — any I-entry with `favorite: true` (e.g. reMarkable, shared server). Mark with `update_memory(id="I00XX", favorite=true)`.
|
|
74
|
+
- **Recent projects** — 5 most recently updated P-entries
|
|
75
|
+
|
|
68
76
|
## OUTPUT
|
|
69
77
|
|
|
70
78
|
After both steps, output exactly:
|