hmem-mcp 7.4.0 → 8.0.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/README.md +266 -54
- package/dist/cli-checkpoint-agent.d.ts +27 -0
- package/dist/cli-checkpoint-agent.js +320 -0
- package/dist/cli-checkpoint-agent.js.map +1 -0
- package/dist/cli-checkpoint.js +165 -78
- package/dist/cli-checkpoint.js.map +1 -1
- package/dist/cli-context-inject.d.ts +7 -7
- package/dist/cli-context-inject.js +54 -41
- package/dist/cli-context-inject.js.map +1 -1
- package/dist/cli-doctor.d.ts +7 -0
- package/dist/cli-doctor.js +156 -0
- package/dist/cli-doctor.js.map +1 -0
- package/dist/cli-hook-startup.d.ts +1 -0
- package/dist/cli-hook-startup.js +97 -10
- package/dist/cli-hook-startup.js.map +1 -1
- package/dist/cli-init.d.ts +0 -4
- package/dist/cli-init.js +48 -6
- package/dist/cli-init.js.map +1 -1
- package/dist/cli-log-exchange.js +10 -2
- package/dist/cli-log-exchange.js.map +1 -1
- package/dist/cli-mcp-add-curate.d.ts +7 -0
- package/dist/cli-mcp-add-curate.js +40 -0
- package/dist/cli-mcp-add-curate.js.map +1 -0
- package/dist/cli-migrate.d.ts +57 -0
- package/dist/cli-migrate.js +394 -0
- package/dist/cli-migrate.js.map +1 -0
- package/dist/cli-session-summary.d.ts +1 -1
- package/dist/cli-session-summary.js +9 -54
- package/dist/cli-session-summary.js.map +1 -1
- package/dist/cli-statusline.js +15 -11
- package/dist/cli-statusline.js.map +1 -1
- package/dist/cli-sync-pull.d.ts +3 -0
- package/dist/cli-sync-pull.js +79 -0
- package/dist/cli-sync-pull.js.map +1 -0
- package/dist/cli-sync-push.d.ts +4 -0
- package/dist/cli-sync-push.js +85 -0
- package/dist/cli-sync-push.js.map +1 -0
- package/dist/cli-sync-setup.d.ts +18 -0
- package/dist/cli-sync-setup.js +308 -0
- package/dist/cli-sync-setup.js.map +1 -0
- package/dist/cli-sync-status.d.ts +1 -0
- package/dist/cli-sync-status.js +20 -0
- package/dist/cli-sync-status.js.map +1 -0
- package/dist/cli-v2-checkpoint.d.ts +38 -0
- package/dist/cli-v2-checkpoint.js +134 -0
- package/dist/cli-v2-checkpoint.js.map +1 -0
- package/dist/cli.js +154 -34
- package/dist/cli.js.map +1 -1
- package/dist/config/config.d.ts +29 -0
- package/dist/config/config.js +123 -0
- package/dist/config/config.js.map +1 -0
- package/dist/diagnostics.js +1 -6
- package/dist/diagnostics.js.map +1 -1
- package/dist/extensions/pi-hmem.js +141 -35
- package/dist/extensions/pi-hmem.js.map +1 -1
- package/dist/hmem-config.d.ts +30 -5
- package/dist/hmem-config.js +50 -8
- package/dist/hmem-config.js.map +1 -1
- package/dist/hmem-store.d.ts +60 -2
- package/dist/hmem-store.js +205 -26
- package/dist/hmem-store.js.map +1 -1
- package/dist/hooks/binding-resolver.d.ts +13 -0
- package/dist/hooks/binding-resolver.js +42 -0
- package/dist/hooks/binding-resolver.js.map +1 -0
- package/dist/hooks/brief.d.ts +2 -0
- package/dist/hooks/brief.js +26 -0
- package/dist/hooks/brief.js.map +1 -0
- package/dist/hooks/dispatch.d.ts +5 -0
- package/dist/hooks/dispatch.js +119 -0
- package/dist/hooks/dispatch.js.map +1 -0
- package/dist/hooks/git-probe.d.ts +4 -0
- package/dist/hooks/git-probe.js +46 -0
- package/dist/hooks/git-probe.js.map +1 -0
- package/dist/hooks/harness/claude-code.d.ts +10 -0
- package/dist/hooks/harness/claude-code.js +133 -0
- package/dist/hooks/harness/claude-code.js.map +1 -0
- package/dist/hooks/harness/hermes.d.ts +4 -0
- package/dist/hooks/harness/hermes.js +20 -0
- package/dist/hooks/harness/hermes.js.map +1 -0
- package/dist/hooks/harness/pi.d.ts +4 -0
- package/dist/hooks/harness/pi.js +21 -0
- package/dist/hooks/harness/pi.js.map +1 -0
- package/dist/hooks/prompt-submit.d.ts +16 -0
- package/dist/hooks/prompt-submit.js +11 -0
- package/dist/hooks/prompt-submit.js.map +1 -0
- package/dist/hooks/session-start.d.ts +3 -0
- package/dist/hooks/session-start.js +31 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/stable-context.d.ts +11 -0
- package/dist/hooks/stable-context.js +117 -0
- package/dist/hooks/stable-context.js.map +1 -0
- package/dist/hooks/stop-log.d.ts +4 -0
- package/dist/hooks/stop-log.js +12 -0
- package/dist/hooks/stop-log.js.map +1 -0
- package/dist/hooks/summarizer-pick.d.ts +8 -0
- package/dist/hooks/summarizer-pick.js +18 -0
- package/dist/hooks/summarizer-pick.js.map +1 -0
- package/dist/hooks/transcript.d.ts +6 -0
- package/dist/hooks/transcript.js +72 -0
- package/dist/hooks/transcript.js.map +1 -0
- package/dist/hooks/types.d.ts +56 -0
- package/dist/hooks/types.js +2 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/mcp-curate-server.js +50 -4
- package/dist/mcp-curate-server.js.map +1 -1
- package/dist/mcp-server.js +121 -58
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-shared.js +119 -29
- package/dist/mcp-shared.js.map +1 -1
- package/dist/memory-search.d.ts +5 -2
- package/dist/memory-search.js +5 -2
- package/dist/memory-search.js.map +1 -1
- package/dist/migrate/o-decompose.d.ts +14 -0
- package/dist/migrate/o-decompose.js +112 -0
- package/dist/migrate/o-decompose.js.map +1 -0
- package/dist/migrate/tree.d.ts +16 -0
- package/dist/migrate/tree.js +102 -0
- package/dist/migrate/tree.js.map +1 -0
- package/dist/migrate/v1-reader.d.ts +38 -0
- package/dist/migrate/v1-reader.js +34 -0
- package/dist/migrate/v1-reader.js.map +1 -0
- package/dist/migrate/v1-to-v2.d.ts +25 -0
- package/dist/migrate/v1-to-v2.js +127 -0
- package/dist/migrate/v1-to-v2.js.map +1 -0
- package/dist/session-state.d.ts +3 -0
- package/dist/session-state.js +7 -5
- package/dist/session-state.js.map +1 -1
- package/dist/store/db.d.ts +25 -0
- package/dist/store/db.js +159 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/entries.d.ts +48 -0
- package/dist/store/entries.js +145 -0
- package/dist/store/entries.js.map +1 -0
- package/dist/store/events-fts.d.ts +18 -0
- package/dist/store/events-fts.js +18 -0
- package/dist/store/events-fts.js.map +1 -0
- package/dist/store/events.d.ts +30 -0
- package/dist/store/events.js +48 -0
- package/dist/store/events.js.map +1 -0
- package/dist/store/fts.d.ts +24 -0
- package/dist/store/fts.js +35 -0
- package/dist/store/fts.js.map +1 -0
- package/dist/store/links.d.ts +24 -0
- package/dist/store/links.js +29 -0
- package/dist/store/links.js.map +1 -0
- package/dist/store/schema-engine.d.ts +20 -0
- package/dist/store/schema-engine.js +41 -0
- package/dist/store/schema-engine.js.map +1 -0
- package/dist/store/schema-v2.sql +149 -0
- package/dist/store/sessions.d.ts +38 -0
- package/dist/store/sessions.js +98 -0
- package/dist/store/sessions.js.map +1 -0
- package/dist/store/types.d.ts +74 -0
- package/dist/store/types.js +3 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/ulid.d.ts +1 -0
- package/dist/store/ulid.js +10 -0
- package/dist/store/ulid.js.map +1 -0
- package/dist/summarize/anthropic.d.ts +8 -0
- package/dist/summarize/anthropic.js +38 -0
- package/dist/summarize/anthropic.js.map +1 -0
- package/dist/summarize/loop.d.ts +40 -0
- package/dist/summarize/loop.js +64 -0
- package/dist/summarize/loop.js.map +1 -0
- package/dist/sync/api.d.ts +49 -0
- package/dist/sync/api.js +99 -0
- package/dist/sync/api.js.map +1 -0
- package/dist/sync/config.d.ts +16 -0
- package/dist/sync/config.js +27 -0
- package/dist/sync/config.js.map +1 -0
- package/dist/sync/conflict.d.ts +24 -0
- package/dist/sync/conflict.js +125 -0
- package/dist/sync/conflict.js.map +1 -0
- package/dist/sync/crypto.d.ts +53 -0
- package/dist/sync/crypto.js +140 -0
- package/dist/sync/crypto.js.map +1 -0
- package/dist/sync/passphrase.d.ts +1 -0
- package/dist/sync/passphrase.js +17 -0
- package/dist/sync/passphrase.js.map +1 -0
- package/dist/sync/v2/dispatch.d.ts +6 -0
- package/dist/sync/v2/dispatch.js +24 -0
- package/dist/sync/v2/dispatch.js.map +1 -0
- package/dist/sync/v2/envelope.d.ts +13 -0
- package/dist/sync/v2/envelope.js +36 -0
- package/dist/sync/v2/envelope.js.map +1 -0
- package/dist/sync/v2/export.d.ts +10 -0
- package/dist/sync/v2/export.js +32 -0
- package/dist/sync/v2/export.js.map +1 -0
- package/dist/sync/v2/import.d.ts +10 -0
- package/dist/sync/v2/import.js +130 -0
- package/dist/sync/v2/import.js.map +1 -0
- package/dist/sync/v2/queue.d.ts +18 -0
- package/dist/sync/v2/queue.js +59 -0
- package/dist/sync/v2/queue.js.map +1 -0
- package/dist/sync/v2/reconcile.d.ts +3 -0
- package/dist/sync/v2/reconcile.js +18 -0
- package/dist/sync/v2/reconcile.js.map +1 -0
- package/dist/sync/v2/staging.d.ts +27 -0
- package/dist/sync/v2/staging.js +46 -0
- package/dist/sync/v2/staging.js.map +1 -0
- package/dist/sync/v2/sync.d.ts +18 -0
- package/dist/sync/v2/sync.js +63 -0
- package/dist/sync/v2/sync.js.map +1 -0
- package/dist/sync/v2/transport.d.ts +43 -0
- package/dist/sync/v2/transport.js +20 -0
- package/dist/sync/v2/transport.js.map +1 -0
- package/dist/sync-bridge.d.ts +2 -0
- package/dist/sync-bridge.js +134 -0
- package/dist/sync-bridge.js.map +1 -0
- package/dist/tools/analyze-v1.d.ts +1 -0
- package/dist/tools/analyze-v1.js +142 -0
- package/dist/tools/analyze-v1.js.map +1 -0
- package/dist/util/iso.d.ts +8 -0
- package/dist/util/iso.js +15 -0
- package/dist/util/iso.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +14 -0
- package/dist/utils.js.map +1 -0
- package/dist/v2/addressing.d.ts +9 -0
- package/dist/v2/addressing.js +55 -0
- package/dist/v2/addressing.js.map +1 -0
- package/dist/v2/checkpoint-agent.d.ts +75 -0
- package/dist/v2/checkpoint-agent.js +231 -0
- package/dist/v2/checkpoint-agent.js.map +1 -0
- package/dist/v2/checkpoint-select.d.ts +60 -0
- package/dist/v2/checkpoint-select.js +106 -0
- package/dist/v2/checkpoint-select.js.map +1 -0
- package/dist/v2/checkpoint.d.ts +62 -0
- package/dist/v2/checkpoint.js +103 -0
- package/dist/v2/checkpoint.js.map +1 -0
- package/dist/v2/curation.d.ts +23 -0
- package/dist/v2/curation.js +118 -0
- package/dist/v2/curation.js.map +1 -0
- package/dist/v2/projects.d.ts +29 -0
- package/dist/v2/projects.js +60 -0
- package/dist/v2/projects.js.map +1 -0
- package/dist/v2/read-render.d.ts +31 -0
- package/dist/v2/read-render.js +150 -0
- package/dist/v2/read-render.js.map +1 -0
- package/dist/v2/related.d.ts +8 -0
- package/dist/v2/related.js +35 -0
- package/dist/v2/related.js.map +1 -0
- package/dist/v2/search.d.ts +6 -0
- package/dist/v2/search.js +24 -0
- package/dist/v2/search.js.map +1 -0
- package/dist/v2/session-id.d.ts +7 -0
- package/dist/v2/session-id.js +14 -0
- package/dist/v2/session-id.js.map +1 -0
- package/dist/v2/sessions-tools.d.ts +11 -0
- package/dist/v2/sessions-tools.js +30 -0
- package/dist/v2/sessions-tools.js.map +1 -0
- package/dist/v2/store-facade.d.ts +23 -0
- package/dist/v2/store-facade.js +33 -0
- package/dist/v2/store-facade.js.map +1 -0
- package/dist/v2/summarize-adapter.d.ts +11 -0
- package/dist/v2/summarize-adapter.js +19 -0
- package/dist/v2/summarize-adapter.js.map +1 -0
- package/dist/v2/writes.d.ts +30 -0
- package/dist/v2/writes.js +135 -0
- package/dist/v2/writes.js.map +1 -0
- package/hmem.config.example.json +92 -10
- package/opencode-plugin/hmem.js +5 -2
- package/package.json +7 -3
- package/plugins/hermes-hmem/README.md +56 -0
- package/plugins/hermes-hmem/__init__.py +187 -0
- package/plugins/hermes-hmem/plugin.yaml +8 -0
- package/server.json +2 -2
- package/skills/hmem-activate/SKILL.md +1 -1
- package/skills/hmem-config/SKILL.md +70 -5
- package/skills/hmem-curate/SKILL.md +13 -6
- package/skills/hmem-dispatch/SKILL.md +1 -1
- package/skills/hmem-migrate-o/SKILL.md +3 -8
- package/skills/hmem-new-error/SKILL.md +1 -9
- package/skills/hmem-new-project/SKILL.md +1 -9
- package/skills/hmem-new-rule/SKILL.md +93 -0
- package/skills/hmem-read/SKILL.md +16 -8
- package/skills/hmem-release/SKILL.md +108 -9
- package/skills/hmem-search/SKILL.md +48 -25
- package/skills/hmem-session-start/SKILL.md +147 -46
- package/skills/hmem-setup/SKILL.md +3 -3
- package/skills/hmem-sync-setup/SKILL.md +1 -5
- package/skills/hmem-update/SKILL.md +345 -19
- package/skills/hmem-wipe/SKILL.md +41 -7
- package/skills/hmem-write/SKILL.md +1 -12
- package/skills/hmem-activate-workspace/evals/evals.json +0 -29
- package/skills/hmem-activate-workspace/iteration-1/benchmark.json +0 -370
- package/skills/hmem-activate-workspace/iteration-1/benchmark.md +0 -13
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/eval_metadata.json +0 -23
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/with_skill/grading.json +0 -55
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/with_skill/outputs/response.md +0 -121
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/with_skill/run-1/grading.json +0 -55
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/without_skill/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/without_skill/outputs/response.md +0 -78
- package/skills/hmem-activate-workspace/iteration-1/eval-1-simple-switch/without_skill/run-1/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/eval_metadata.json +0 -23
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/with_skill/grading.json +0 -49
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/with_skill/outputs/response.md +0 -98
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/with_skill/run-1/grading.json +0 -49
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/without_skill/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/without_skill/outputs/response.md +0 -57
- package/skills/hmem-activate-workspace/iteration-1/eval-2-misrouting-fix/without_skill/run-1/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/eval_metadata.json +0 -23
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/with_skill/grading.json +0 -48
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/with_skill/outputs/response.md +0 -69
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/with_skill/run-1/grading.json +0 -48
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/without_skill/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/without_skill/outputs/response.md +0 -59
- package/skills/hmem-activate-workspace/iteration-1/eval-3-temporary-load/without_skill/run-1/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/eval_metadata.json +0 -23
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/with_skill/grading.json +0 -55
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/with_skill/outputs/response.md +0 -182
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/with_skill/run-1/grading.json +0 -55
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/without_skill/grading.json +0 -44
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/without_skill/outputs/response.md +0 -43
- package/skills/hmem-activate-workspace/iteration-1/eval-4-wrong-project/without_skill/run-1/grading.json +0 -44
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-checkpoint-agent.ts
|
|
3
|
+
*
|
|
4
|
+
* Provider-agnostic agentic loop for the checkpoint agent.
|
|
5
|
+
* Replaces the `claude -p --model haiku` subprocess spawn.
|
|
6
|
+
*
|
|
7
|
+
* Supports: Anthropic (native), OpenAI-compatible (OpenAI, DeepSeek, Groq, etc.)
|
|
8
|
+
*/
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import os from "node:os";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
13
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
14
|
+
import OpenAI from "openai";
|
|
15
|
+
// ── Tool schemas (shared between providers) ──────────────────────────────────
|
|
16
|
+
const TOOL_SCHEMAS = {
|
|
17
|
+
read_memory: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
id: { type: "string", description: "Node ID, e.g. 'P0048' or 'O0048.3'" },
|
|
21
|
+
search: { type: "string", description: "Full-text search query" },
|
|
22
|
+
prefix: { type: "string", description: "Filter by category prefix (L, P, D, E, ...)" },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
write_memory: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
prefix: { type: "string", description: "Entry prefix: L, D, E, R, C" },
|
|
29
|
+
content: { type: "string", description: "Title + optional body (tab-indented children)" },
|
|
30
|
+
tags: { type: "array", items: { type: "string" }, description: "Hashtags, e.g. ['#hmem', '#bug']" },
|
|
31
|
+
links: { type: "array", items: { type: "string" }, description: "Linked entry IDs" },
|
|
32
|
+
},
|
|
33
|
+
required: ["prefix", "content"],
|
|
34
|
+
},
|
|
35
|
+
update_memory: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
id: { type: "string", description: "Node ID to update" },
|
|
39
|
+
content: { type: "string", description: "New content (replaces existing)" },
|
|
40
|
+
tags: { type: "array", items: { type: "string" } },
|
|
41
|
+
irrelevant: { type: "boolean" },
|
|
42
|
+
favorite: { type: "boolean" },
|
|
43
|
+
},
|
|
44
|
+
required: ["id"],
|
|
45
|
+
},
|
|
46
|
+
append_memory: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
id: { type: "string", description: "Parent node ID" },
|
|
50
|
+
content: { type: "string", description: "Child content (tab-indented for nesting)" },
|
|
51
|
+
},
|
|
52
|
+
required: ["id", "content"],
|
|
53
|
+
},
|
|
54
|
+
move_nodes: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
node_ids: { type: "array", items: { type: "string" }, description: "Exchange node IDs to move" },
|
|
58
|
+
target_o_id: { type: "string", description: "Target O-entry ID, e.g. 'O0042'" },
|
|
59
|
+
},
|
|
60
|
+
required: ["node_ids", "target_o_id"],
|
|
61
|
+
},
|
|
62
|
+
list_projects: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
// ── Tool executor ─────────────────────────────────────────────────────────────
|
|
68
|
+
function executeTool(name, input, store) {
|
|
69
|
+
try {
|
|
70
|
+
switch (name) {
|
|
71
|
+
case "read_memory": {
|
|
72
|
+
const { id, search, prefix } = input;
|
|
73
|
+
const entries = store.read({ id, search, prefix, depth: 3 });
|
|
74
|
+
if (!entries.length)
|
|
75
|
+
return "No results found.";
|
|
76
|
+
return entries.slice(0, 20).map(e => `${e.id} ${e.level_1 ?? ""}${e.level_2 ? "\n " + e.level_2 : ""}`).join("\n");
|
|
77
|
+
}
|
|
78
|
+
case "write_memory": {
|
|
79
|
+
const { prefix, content, tags, links } = input;
|
|
80
|
+
const result = store.write(prefix, content, links, undefined, undefined, tags);
|
|
81
|
+
return `Created: ${result.id}`;
|
|
82
|
+
}
|
|
83
|
+
case "update_memory": {
|
|
84
|
+
const { id, content, tags, irrelevant, favorite } = input;
|
|
85
|
+
const ok = store.updateNode(id, content, undefined, undefined, favorite, undefined, irrelevant, tags);
|
|
86
|
+
return ok ? `Updated: ${id}` : `Not found: ${id}`;
|
|
87
|
+
}
|
|
88
|
+
case "append_memory": {
|
|
89
|
+
const { id, content } = input;
|
|
90
|
+
const result = store.appendChildren(id, content);
|
|
91
|
+
return `Appended ${result.count} node(s): ${result.ids.join(", ")}`;
|
|
92
|
+
}
|
|
93
|
+
case "move_nodes": {
|
|
94
|
+
const { node_ids, target_o_id } = input;
|
|
95
|
+
const result = store.moveNodes(node_ids, target_o_id);
|
|
96
|
+
return `Moved ${result.moved}. Errors: ${result.errors.join(", ") || "none"}`;
|
|
97
|
+
}
|
|
98
|
+
case "list_projects": {
|
|
99
|
+
const projects = store.listProjects();
|
|
100
|
+
return projects.map(p => ` ${p.id} ${p.title}`).join("\n");
|
|
101
|
+
}
|
|
102
|
+
default:
|
|
103
|
+
return `Unknown tool: ${name}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
return `Error: ${e?.message ?? String(e)}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ── Anthropic loop ────────────────────────────────────────────────────────────
|
|
111
|
+
async function runAnthropicLoop(prompt, store, config) {
|
|
112
|
+
const apiKeyEnv = config.checkpointApiKeyEnv ?? "ANTHROPIC_API_KEY";
|
|
113
|
+
const apiKey = process.env[apiKeyEnv];
|
|
114
|
+
if (!apiKey)
|
|
115
|
+
throw new Error(`Missing env var: ${apiKeyEnv}`);
|
|
116
|
+
const client = new Anthropic({ apiKey });
|
|
117
|
+
const tools = Object.entries(TOOL_SCHEMAS).map(([name, schema]) => ({
|
|
118
|
+
name,
|
|
119
|
+
description: `hmem ${name}`,
|
|
120
|
+
input_schema: schema,
|
|
121
|
+
}));
|
|
122
|
+
const messages = [{ role: "user", content: prompt }];
|
|
123
|
+
for (let i = 0; i < 40; i++) {
|
|
124
|
+
const response = await client.messages.create({
|
|
125
|
+
model: config.checkpointModel,
|
|
126
|
+
max_tokens: 4096,
|
|
127
|
+
tools,
|
|
128
|
+
messages,
|
|
129
|
+
});
|
|
130
|
+
messages.push({ role: "assistant", content: response.content });
|
|
131
|
+
if (response.stop_reason === "end_turn")
|
|
132
|
+
break;
|
|
133
|
+
const toolUses = response.content.filter((b) => b.type === "tool_use");
|
|
134
|
+
if (!toolUses.length)
|
|
135
|
+
break;
|
|
136
|
+
const results = toolUses.map(block => ({
|
|
137
|
+
type: "tool_result",
|
|
138
|
+
tool_use_id: block.id,
|
|
139
|
+
content: executeTool(block.name, block.input, store),
|
|
140
|
+
}));
|
|
141
|
+
messages.push({ role: "user", content: results });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// ── OpenAI-compatible loop ────────────────────────────────────────────────────
|
|
145
|
+
async function runOpenAILoop(prompt, store, config) {
|
|
146
|
+
const apiKeyEnv = config.checkpointApiKeyEnv ?? "OPENAI_API_KEY";
|
|
147
|
+
const apiKey = process.env[apiKeyEnv];
|
|
148
|
+
if (!apiKey)
|
|
149
|
+
throw new Error(`Missing env var: ${apiKeyEnv}`);
|
|
150
|
+
const client = new OpenAI({
|
|
151
|
+
apiKey,
|
|
152
|
+
...(config.checkpointBaseUrl ? { baseURL: config.checkpointBaseUrl } : {}),
|
|
153
|
+
});
|
|
154
|
+
const tools = Object.entries(TOOL_SCHEMAS).map(([name, schema]) => ({
|
|
155
|
+
type: "function",
|
|
156
|
+
function: { name, description: `hmem ${name}`, parameters: schema },
|
|
157
|
+
}));
|
|
158
|
+
const messages = [{ role: "user", content: prompt }];
|
|
159
|
+
for (let i = 0; i < 40; i++) {
|
|
160
|
+
const response = await client.chat.completions.create({
|
|
161
|
+
model: config.checkpointModel,
|
|
162
|
+
tools,
|
|
163
|
+
messages,
|
|
164
|
+
});
|
|
165
|
+
const choice = response.choices[0];
|
|
166
|
+
if (!choice)
|
|
167
|
+
break;
|
|
168
|
+
messages.push(choice.message);
|
|
169
|
+
if (choice.finish_reason === "stop" || !choice.message.tool_calls?.length)
|
|
170
|
+
break;
|
|
171
|
+
for (const call of choice.message.tool_calls) {
|
|
172
|
+
if (!("function" in call))
|
|
173
|
+
continue;
|
|
174
|
+
let input = {};
|
|
175
|
+
try {
|
|
176
|
+
input = JSON.parse(call.function.arguments);
|
|
177
|
+
}
|
|
178
|
+
catch { }
|
|
179
|
+
const result = executeTool(call.function.name, input, store);
|
|
180
|
+
messages.push({ role: "tool", tool_call_id: call.id, content: result });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// ── claude -p subprocess fallback (for Max/OAuth users without API key) ────────
|
|
185
|
+
function buildMcpConfig(projectDir, hmemPath) {
|
|
186
|
+
let hmemServerPath;
|
|
187
|
+
try {
|
|
188
|
+
hmemServerPath = execSync("which hmem", { encoding: "utf8" }).trim();
|
|
189
|
+
const realPath = fs.realpathSync(hmemServerPath);
|
|
190
|
+
hmemServerPath = path.join(path.dirname(realPath), "mcp-server.js");
|
|
191
|
+
if (!fs.existsSync(hmemServerPath)) {
|
|
192
|
+
hmemServerPath = path.join(path.dirname(path.dirname(realPath)), "dist", "mcp-server.js");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
hmemServerPath = path.join(process.env.HOME || "/home", ".nvm/versions/node", process.version, "lib/node_modules/hmem-mcp/dist/mcp-server.js");
|
|
197
|
+
}
|
|
198
|
+
const mcpConfig = {
|
|
199
|
+
mcpServers: {
|
|
200
|
+
hmem: {
|
|
201
|
+
command: process.execPath,
|
|
202
|
+
args: [hmemServerPath],
|
|
203
|
+
env: { HMEM_PROJECT_DIR: projectDir, HMEM_PATH: hmemPath, HMEM_NO_SESSION: "1" },
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "hmem-checkpoint-"));
|
|
208
|
+
fs.chmodSync(tmpDir, 0o700);
|
|
209
|
+
const tmpPath = path.join(tmpDir, "mcp-config.json");
|
|
210
|
+
fs.writeFileSync(tmpPath, JSON.stringify(mcpConfig), "utf8");
|
|
211
|
+
return tmpPath;
|
|
212
|
+
}
|
|
213
|
+
async function runClaudeSubprocess(prompt, hmemPath, model) {
|
|
214
|
+
const projectDir = path.dirname(hmemPath);
|
|
215
|
+
const mcpConfigPath = buildMcpConfig(projectDir, hmemPath);
|
|
216
|
+
try {
|
|
217
|
+
execFileSync("claude", [
|
|
218
|
+
"-p", "--model", model,
|
|
219
|
+
"--mcp-config", mcpConfigPath,
|
|
220
|
+
"--allowedTools", "mcp__hmem__update_memory mcp__hmem__write_memory mcp__hmem__append_memory mcp__hmem__read_memory mcp__hmem__move_nodes mcp__hmem__list_projects",
|
|
221
|
+
"--dangerously-skip-permissions",
|
|
222
|
+
], { input: prompt, encoding: "utf8", timeout: 120_000 });
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
try {
|
|
226
|
+
fs.unlinkSync(mcpConfigPath);
|
|
227
|
+
}
|
|
228
|
+
catch { }
|
|
229
|
+
try {
|
|
230
|
+
fs.rmdirSync(path.dirname(mcpConfigPath));
|
|
231
|
+
}
|
|
232
|
+
catch { }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function hasClaudeBinary() {
|
|
236
|
+
try {
|
|
237
|
+
execSync("which claude", { stdio: "ignore" });
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Detect which AI harness invoked us. Honors explicit HMEM_HARNESS override first
|
|
246
|
+
* (plugins/extensions should set this when they spawn `hmem checkpoint`); falls
|
|
247
|
+
* back to env-var signatures the harnesses set themselves.
|
|
248
|
+
*/
|
|
249
|
+
export function detectHarness() {
|
|
250
|
+
const explicit = process.env.HMEM_HARNESS?.toLowerCase();
|
|
251
|
+
if (explicit === "claude-code" || explicit === "codex" || explicit === "opencode" ||
|
|
252
|
+
explicit === "pi" || explicit === "hermes") {
|
|
253
|
+
return explicit;
|
|
254
|
+
}
|
|
255
|
+
if (process.env.CLAUDECODE || process.env.CLAUDE_CODE_SESSION_ID)
|
|
256
|
+
return "claude-code";
|
|
257
|
+
if (process.env.CODEX_SESSION_ID || process.env.CODEX_API_KEY)
|
|
258
|
+
return "codex";
|
|
259
|
+
return "unknown";
|
|
260
|
+
}
|
|
261
|
+
// ── Public entry point ────────────────────────────────────────────────────────
|
|
262
|
+
/**
|
|
263
|
+
* Harness-aware provider routing:
|
|
264
|
+
* - Claude Code → Haiku via `claude -p` subprocess (uses Max OAuth, no API key)
|
|
265
|
+
* - Codex → gpt-5.4-mini via OpenAI API (uses OPENAI_API_KEY)
|
|
266
|
+
* - OpenCode / Pi / Hermes / unknown → user's configured provider (hmem.config.json)
|
|
267
|
+
*
|
|
268
|
+
* The harness routing takes precedence over the configured provider — Claude Code
|
|
269
|
+
* users explicitly want Haiku-via-OAuth (covered by Max), not their DeepSeek key.
|
|
270
|
+
*/
|
|
271
|
+
export async function runCheckpointAgent(prompt, store, config, hmemPath) {
|
|
272
|
+
const harness = detectHarness();
|
|
273
|
+
console.error(`[hmem checkpoint] harness=${harness} hmemPath=${hmemPath ? "set" : "unset"} claudeBin=${hasClaudeBinary()}`);
|
|
274
|
+
// 1. Claude Code → Haiku via `claude -p` (Max OAuth, no API key needed)
|
|
275
|
+
if (harness === "claude-code" && hmemPath && hasClaudeBinary()) {
|
|
276
|
+
console.error(`[hmem checkpoint] → routing to claude -p (Haiku via Max OAuth)`);
|
|
277
|
+
store.close();
|
|
278
|
+
await runClaudeSubprocess(prompt, hmemPath, "claude-haiku-4-5-20251001");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// 2. Codex → gpt-5.4-mini via OpenAI API
|
|
282
|
+
if (harness === "codex") {
|
|
283
|
+
const codexConfig = {
|
|
284
|
+
...config,
|
|
285
|
+
checkpointProvider: "openai",
|
|
286
|
+
checkpointModel: "gpt-5.4-mini",
|
|
287
|
+
checkpointApiKeyEnv: "OPENAI_API_KEY",
|
|
288
|
+
checkpointBaseUrl: undefined,
|
|
289
|
+
};
|
|
290
|
+
await runOpenAILoop(prompt, store, codexConfig);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// 3. OpenCode / Pi / Hermes / unknown → user's configured provider
|
|
294
|
+
const apiKeyEnv = config.checkpointApiKeyEnv
|
|
295
|
+
?? (config.checkpointProvider === "openai" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY");
|
|
296
|
+
const apiKey = process.env[apiKeyEnv];
|
|
297
|
+
if (apiKey) {
|
|
298
|
+
console.error(`[hmem checkpoint] → routing to ${config.checkpointProvider} API (${config.checkpointModel})`);
|
|
299
|
+
if (config.checkpointProvider === "openai") {
|
|
300
|
+
await runOpenAILoop(prompt, store, config);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
await runAnthropicLoop(prompt, store, config);
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
// 4. Last-resort: claude -p subprocess if Claude binary is on PATH (zero-config Claude Max)
|
|
308
|
+
if (hmemPath && hasClaudeBinary()) {
|
|
309
|
+
store.close();
|
|
310
|
+
await runClaudeSubprocess(prompt, hmemPath, config.checkpointModel);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
throw new Error(`[hmem checkpoint] No checkpoint provider available for harness=${harness}.\n` +
|
|
314
|
+
"Configure one in hmem.config.json → memory:\n" +
|
|
315
|
+
' "checkpointProvider": "anthropic" (or "openai")\n' +
|
|
316
|
+
' "checkpointModel": "claude-haiku-4-5-20251001"\n' +
|
|
317
|
+
' "checkpointApiKeyEnv": "ANTHROPIC_API_KEY" (env var name holding your key)\n' +
|
|
318
|
+
"Or install `claude` CLI for the Claude Max zero-config fallback.");
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=cli-checkpoint-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-checkpoint-agent.js","sourceRoot":"","sources":["../src/cli-checkpoint-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/cli-checkpoint.js
CHANGED
|
@@ -14,49 +14,48 @@
|
|
|
14
14
|
* HMEM_PROJECT_DIR — directory for config + company.hmem
|
|
15
15
|
*/
|
|
16
16
|
import fs from "node:fs";
|
|
17
|
-
import os from "node:os";
|
|
18
17
|
import path from "node:path";
|
|
19
|
-
import {
|
|
18
|
+
import { spawn } from "node:child_process";
|
|
20
19
|
import { HmemStore } from "./hmem-store.js";
|
|
21
20
|
import { loadHmemConfig } from "./hmem-config.js";
|
|
22
21
|
import { currentSessionId } from "./session-state.js";
|
|
23
|
-
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
import { runCheckpointAgent } from "./cli-checkpoint-agent.js";
|
|
23
|
+
function syncReady(hmemPath) {
|
|
24
|
+
if (!process.env.HMEM_SYNC_PASSPHRASE)
|
|
25
|
+
return false;
|
|
27
26
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
const cfgPath = path.join(path.dirname(hmemPath), "config.json");
|
|
28
|
+
if (!fs.existsSync(cfgPath))
|
|
29
|
+
return false;
|
|
30
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
|
|
31
|
+
if (!cfg.api_key || !cfg.active_file)
|
|
32
|
+
return false;
|
|
33
|
+
const fileCfg = cfg.files?.[cfg.active_file];
|
|
34
|
+
return !!(fileCfg?.salt && fileCfg?.hmem_path);
|
|
36
35
|
}
|
|
37
36
|
catch {
|
|
38
|
-
|
|
39
|
-
hmemServerPath = path.join(process.env.HOME || "/home", ".nvm/versions/node", process.version, "lib/node_modules/hmem-mcp/dist/mcp-server.js");
|
|
37
|
+
return false;
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
39
|
+
}
|
|
40
|
+
async function runSyncChild(args, label) {
|
|
41
|
+
await new Promise((resolve) => {
|
|
42
|
+
const child = spawn(process.execPath, [process.argv[1], "sync", ...args], {
|
|
43
|
+
env: { ...process.env },
|
|
44
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45
|
+
windowsHide: true,
|
|
46
|
+
});
|
|
47
|
+
let stderr = "";
|
|
48
|
+
child.stderr?.on("data", (d) => { stderr += d.toString(); });
|
|
49
|
+
child.on("close", (code) => {
|
|
50
|
+
if (code !== 0)
|
|
51
|
+
console.error(`[hmem checkpoint] sync ${label} exited ${code}: ${stderr.trim()}`);
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
child.on("error", (err) => {
|
|
55
|
+
console.error(`[hmem checkpoint] sync ${label} spawn failed: ${err.message}`);
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
60
59
|
}
|
|
61
60
|
export async function checkpoint() {
|
|
62
61
|
const projectDir = process.env.HMEM_PROJECT_DIR;
|
|
@@ -65,24 +64,119 @@ export async function checkpoint() {
|
|
|
65
64
|
const hmemPath = process.env.HMEM_PATH;
|
|
66
65
|
if (!fs.existsSync(hmemPath))
|
|
67
66
|
process.exit(0);
|
|
67
|
+
const doSync = syncReady(hmemPath);
|
|
68
|
+
if (doSync)
|
|
69
|
+
await runSyncChild(["pull"], "pull");
|
|
68
70
|
const config = loadHmemConfig(path.dirname(hmemPath));
|
|
69
71
|
const store = new HmemStore(hmemPath, config);
|
|
70
|
-
let mcpConfigPath = "";
|
|
71
72
|
try {
|
|
72
|
-
// 1. Get active project and its O-entry
|
|
73
|
+
// 1. Get active project and its O-entry. Tries in order:
|
|
74
|
+
// (a) HMEM_ACTIVE_PROJECT env (set by log-exchange when it knows the project)
|
|
75
|
+
// (b) getActiveProject(currentSessionId) — session marker → DB active=1 flag
|
|
76
|
+
// (c) getMostRecentlyActiveProject() — newest O-entry exchange (heuristic)
|
|
77
|
+
// The previous "silent return on null" hid genuine misrouted exchanges; loud
|
|
78
|
+
// logging + a heuristic fallback prevents the multi-device "session-marker stripped
|
|
79
|
+
// but exchanges still arrive" failure mode.
|
|
73
80
|
const envProjectId = process.env.HMEM_ACTIVE_PROJECT;
|
|
74
|
-
|
|
81
|
+
let activeProject = envProjectId
|
|
75
82
|
? store.getProjectById(envProjectId)
|
|
76
83
|
: store.getActiveProject(currentSessionId());
|
|
77
|
-
if (!activeProject)
|
|
84
|
+
if (!activeProject) {
|
|
85
|
+
const recent = store.getMostRecentlyActiveProject();
|
|
86
|
+
if (recent) {
|
|
87
|
+
activeProject = recent;
|
|
88
|
+
console.error(`[hmem checkpoint] No active-project marker — falling back to most recent O-entry activity: ${recent.id}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!activeProject) {
|
|
92
|
+
console.error("[hmem checkpoint] No active project found. Tried: " +
|
|
93
|
+
`env(HMEM_ACTIVE_PROJECT)=${envProjectId ?? "(unset)"}, ` +
|
|
94
|
+
`session-marker(sessionId=${currentSessionId() ?? "(none)"})=miss, ` +
|
|
95
|
+
"DB active=1 flag=miss, recent O-entry activity=none. " +
|
|
96
|
+
"Skipping checkpoint — exchanges will accumulate without summary until a project is activated.");
|
|
78
97
|
return;
|
|
98
|
+
}
|
|
79
99
|
const projectSeq = parseInt(activeProject.id.replace(/\D/g, ""), 10);
|
|
80
100
|
const oId = store.resolveProjectO(projectSeq);
|
|
81
101
|
// 2. Find the latest full batch (L3 with >= batchSize L4 children)
|
|
82
102
|
const batchSize = config.checkpointInterval || 5;
|
|
83
103
|
const latestFullBatch = store.getLatestFullBatch(oId, batchSize);
|
|
84
|
-
|
|
104
|
+
// Determine current session node to exclude from orphan search
|
|
105
|
+
const latestSession = store.getChildNodes(oId)
|
|
106
|
+
.filter(n => n.depth === 2)
|
|
107
|
+
.sort((a, b) => b.seq - a.seq)[0];
|
|
108
|
+
const currentSessionNodeId = latestFullBatch?.sessionId ?? latestSession?.id ?? null;
|
|
109
|
+
// Find orphaned batches from previous sessions that never got summarized.
|
|
110
|
+
// cap=5: catch up backlog without exceeding context budget (~5KB per batch after truncation).
|
|
111
|
+
const orphanedBatches = store.getOrphanedBatches(oId, currentSessionNodeId);
|
|
112
|
+
if (!latestFullBatch && orphanedBatches.length === 0)
|
|
85
113
|
return;
|
|
114
|
+
// Build orphan section text once — used by both the orphan-only path
|
|
115
|
+
// (when no full batch) and the normal path (as Section 0b alongside the latest batch).
|
|
116
|
+
// Side effect: tags #skill-dialog on matching exchanges.
|
|
117
|
+
const orphanSections = orphanedBatches.map((ob, i) => {
|
|
118
|
+
const exs = store.getOEntryExchangesV2(oId, 20, { sessionScope: [ob.sessionId] });
|
|
119
|
+
const batchExs = exs.filter(ex => ex.nodeId.startsWith(ob.batchId + "."));
|
|
120
|
+
if (batchExs.length === 0)
|
|
121
|
+
return null;
|
|
122
|
+
const formatted = batchExs.map((ex, j) => {
|
|
123
|
+
let user = ex.userText.replace(/<channel[^>]*>\s*/g, "").replace(/<\/channel>\s*/g, "").trim();
|
|
124
|
+
let agent = (ex.agentText ?? "").replace(/<[^>]+>/g, "").trim();
|
|
125
|
+
user = user.length > 800 ? user.substring(0, 800) + "..." : user;
|
|
126
|
+
agent = agent.length > 1200 ? agent.substring(0, 1200) + "..." : agent;
|
|
127
|
+
return `--- Exchange ${j + 1} (${ex.nodeId}) ---\nUSER: ${user}\nAGENT: ${agent}`;
|
|
128
|
+
}).join("\n\n");
|
|
129
|
+
const listing = batchExs.map(ex => ` ${ex.nodeId}: "${ex.title}"`).join("\n");
|
|
130
|
+
for (const ex of batchExs) {
|
|
131
|
+
if (ex.userText.includes("Base directory for this skill:")) {
|
|
132
|
+
store.addTag(ex.nodeId, "#skill-dialog");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return `=== Orphan Batch ${i + 1}: ${ob.batchId} | Session ${ob.sessionId} (${ob.sessionDate}) — "${ob.sessionTitle}" ===
|
|
136
|
+
Current exchange titles:
|
|
137
|
+
${listing}
|
|
138
|
+
|
|
139
|
+
${formatted}`;
|
|
140
|
+
}).filter((s) => s !== null);
|
|
141
|
+
// Orphan-only path: no full batch but orphaned batches exist
|
|
142
|
+
if (!latestFullBatch) {
|
|
143
|
+
const pName = activeProject.title.split("|")[0].trim();
|
|
144
|
+
const pId = activeProject.id;
|
|
145
|
+
const pList = store.listProjects().map(p => ` ${p.id} ${p.title}`).join("\n");
|
|
146
|
+
if (orphanSections.length === 0)
|
|
147
|
+
return;
|
|
148
|
+
const orphanPrompt = `You are a checkpoint agent for "${pName}" (${pId}).
|
|
149
|
+
Process ${orphanSections.length} orphaned batch(es) — prior sessions too short for a regular checkpoint.
|
|
150
|
+
|
|
151
|
+
== All Projects ==
|
|
152
|
+
${pList}
|
|
153
|
+
|
|
154
|
+
${orphanSections.join("\n\n")}
|
|
155
|
+
|
|
156
|
+
## Tasks for EACH batch above (Tasks 1, 2, 5, 6 only):
|
|
157
|
+
|
|
158
|
+
### 1. Title each exchange
|
|
159
|
+
For each: update_memory(id="<nodeId>", content="Descriptive title, max 50 chars, match conversation language")
|
|
160
|
+
GOOD: "Fix: cleanTitle strips separators" | BAD: "Projekt laden" or "ok"
|
|
161
|
+
|
|
162
|
+
### 2. Write rolling summary for each batch
|
|
163
|
+
update_memory(id="<batchId>", content="Summary: 2-5 sentences covering this batch. Match conversation language.")
|
|
164
|
+
|
|
165
|
+
### 5. Tag exchanges
|
|
166
|
+
For each exchange, add ONE tag if applicable: #skill-dialog, #irrelevant, #planning, #debugging, #admin, #meta, #repetition
|
|
167
|
+
|
|
168
|
+
### 6. Update each session title and summary
|
|
169
|
+
update_memory(id="<sessionId>", content="Short session title, max 60 chars\\n> 2-5 sentences. Key decisions, outcomes. Written for someone picking up cold.")
|
|
170
|
+
|
|
171
|
+
## Rules:
|
|
172
|
+
- Match language of existing entries
|
|
173
|
+
- Tags: lowercase with #
|
|
174
|
+
- Do NOT extract L/E/D entries (skip Task 3)
|
|
175
|
+
- Do NOT update P-entry (skip Task 4)`;
|
|
176
|
+
await runCheckpointAgent(orphanPrompt, store, config);
|
|
177
|
+
console.log(`[hmem checkpoint] Orphan batches processed: ${orphanSections.length} (${config.checkpointProvider}/${config.checkpointModel})`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
86
180
|
const batchId = latestFullBatch.id;
|
|
87
181
|
const sessionId = latestFullBatch.sessionId;
|
|
88
182
|
// 3. Get exchanges from this batch
|
|
@@ -126,10 +220,7 @@ export async function checkpoint() {
|
|
|
126
220
|
const allProjects = store.listProjects();
|
|
127
221
|
const projectName = activeProject.title.split("|")[0].trim();
|
|
128
222
|
const projectId = activeProject.id;
|
|
129
|
-
//
|
|
130
|
-
store.close();
|
|
131
|
-
// 7. Build MCP config and prompt
|
|
132
|
-
mcpConfigPath = buildMcpConfig(projectDir, hmemPath);
|
|
223
|
+
// 7. Build prompt
|
|
133
224
|
const formattedExchanges = batchExchanges.map((ex, i) => {
|
|
134
225
|
// Strip XML channel tags from Telegram messages before passing to Haiku
|
|
135
226
|
let user = ex.userText.replace(/<channel[^>]*>\s*/g, "").replace(/<\/channel>\s*/g, "").trim();
|
|
@@ -167,6 +258,16 @@ Call: update_memory(id="<id>", content="Short title\\n> 2-5 sentences. Skip if n
|
|
|
167
258
|
|
|
168
259
|
${catchupSessions.map(d => `Session ${d.id} (${d.date}) — "${d.title}":\n${d.body}`).join("\n\n")}
|
|
169
260
|
|
|
261
|
+
`
|
|
262
|
+
: "";
|
|
263
|
+
// Section 0b: orphan batches from previous sessions that never got summarized.
|
|
264
|
+
// Applies Tasks 1, 2, 5 to each (title, batch summary, tag) — NOT P-entry updates or knowledge extraction.
|
|
265
|
+
const orphanCatchupSection = orphanSections.length > 0
|
|
266
|
+
? `### 0b. Catch up unsummarized batches from past sessions
|
|
267
|
+
${orphanSections.length} prior batch(es) were never summarized — likely because a newer full batch arrived first. Apply Tasks 1, 2, and 5 to EACH batch below (titles, rolling summary on the batch node, exchange tags). Do NOT extract L/E/D entries from orphans (Task 3) and do NOT update the P-entry (Task 4) from them.
|
|
268
|
+
|
|
269
|
+
${orphanSections.join("\n\n")}
|
|
270
|
+
|
|
170
271
|
`
|
|
171
272
|
: "";
|
|
172
273
|
const prompt = `You are a checkpoint agent for "${projectName}" (${projectId}).
|
|
@@ -181,7 +282,7 @@ ${prevSummaryText}
|
|
|
181
282
|
== Batch Exchanges ==
|
|
182
283
|
${formattedExchanges}
|
|
183
284
|
|
|
184
|
-
${catchupSection}## Tasks (execute ALL in order):
|
|
285
|
+
${catchupSection}${orphanCatchupSection}## Tasks (execute ALL in order):
|
|
185
286
|
|
|
186
287
|
### 1. Title each exchange (REQUIRED)
|
|
187
288
|
Current titles (auto-extracted):
|
|
@@ -256,50 +357,36 @@ Do ALL exchanges belong to ${projectName}?
|
|
|
256
357
|
Check against the project list above. If an exchange belongs elsewhere, call:
|
|
257
358
|
move_nodes(node_ids=["<exchange_id>"], target_o_id="O00XX")
|
|
258
359
|
|
|
360
|
+
### 8. Update O-entry project state (${oId})
|
|
361
|
+
1. read_memory(id="${oId}") — read the CURRENT body first
|
|
362
|
+
2. Synthesize: keep what's still true, drop what's outdated, add what changed this session
|
|
363
|
+
3. update_memory(id="${oId}", content="<fresh replacement, max 4 sentences>")
|
|
364
|
+
|
|
365
|
+
The result must be a REPLACEMENT, not an addition. Cap at 4 sentences total regardless of how much is in the old body.
|
|
366
|
+
Content: current project status, what just shipped/changed, top open item or next step.
|
|
367
|
+
Written for someone picking up cold — concrete specifics, no jargon.
|
|
368
|
+
Skip if this session was purely admin/infra with no meaningful project-level change.
|
|
369
|
+
This body is injected verbatim into every load_project briefing.
|
|
370
|
+
|
|
259
371
|
## Rules:
|
|
260
372
|
- read_memory() FIRST to see current state
|
|
261
373
|
- Match language of existing entries
|
|
262
374
|
- Tags: 3-5 per entry, lowercase with #
|
|
263
375
|
- Only save what's valuable in 6 months`;
|
|
264
|
-
// 8.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
"mcp__hmem__write_memory",
|
|
268
|
-
"mcp__hmem__append_memory",
|
|
269
|
-
"mcp__hmem__update_memory",
|
|
270
|
-
"mcp__hmem__list_projects",
|
|
271
|
-
"mcp__hmem__move_nodes",
|
|
272
|
-
].join(" ");
|
|
273
|
-
const disallowedTools = "mcp__hmem__flush_context";
|
|
274
|
-
try {
|
|
275
|
-
const output = execFileSync("claude", [
|
|
276
|
-
"-p", "--model", "haiku",
|
|
277
|
-
"--mcp-config", mcpConfigPath,
|
|
278
|
-
"--allowedTools", allowedTools,
|
|
279
|
-
"--disallowedTools", disallowedTools,
|
|
280
|
-
"--dangerously-skip-permissions",
|
|
281
|
-
], { input: prompt, encoding: "utf8", timeout: 120_000 }).trim();
|
|
282
|
-
console.log(`[hmem checkpoint] Haiku: ${output.substring(0, 300)}`);
|
|
283
|
-
}
|
|
284
|
-
catch (e) {
|
|
285
|
-
const stdout = e.stdout?.toString()?.substring(0, 200) || "";
|
|
286
|
-
console.error(`[hmem checkpoint] Failed (exit ${e.status}): ${stdout}`);
|
|
287
|
-
}
|
|
376
|
+
// 8. Run checkpoint agent (actual provider chosen by runCheckpointAgent based on harness — see its diagnostic logs)
|
|
377
|
+
await runCheckpointAgent(prompt, store, config, hmemPath);
|
|
378
|
+
console.log(`[hmem checkpoint] Done (batch ${batchId}, ${batchExchanges.length} exchanges)`);
|
|
288
379
|
}
|
|
289
380
|
catch (e) {
|
|
290
381
|
console.error(`[hmem checkpoint] ${e}`);
|
|
291
382
|
}
|
|
292
383
|
finally {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
fs.unlinkSync(mcpConfigPath);
|
|
296
|
-
}
|
|
297
|
-
catch { }
|
|
298
|
-
try {
|
|
299
|
-
fs.rmdirSync(path.dirname(mcpConfigPath));
|
|
300
|
-
}
|
|
301
|
-
catch { }
|
|
384
|
+
try {
|
|
385
|
+
store.close();
|
|
302
386
|
}
|
|
387
|
+
catch { }
|
|
388
|
+
if (doSync)
|
|
389
|
+
await runSyncChild(["push", "--skip-pull"], "push");
|
|
303
390
|
}
|
|
304
391
|
}
|
|
305
392
|
//# sourceMappingURL=cli-checkpoint.js.map
|