openclaw-engram 0.2.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.
Files changed (90) hide show
  1. package/dist/availability.d.ts +34 -0
  2. package/dist/availability.d.ts.map +1 -0
  3. package/dist/availability.js +70 -0
  4. package/dist/availability.js.map +1 -0
  5. package/dist/client.d.ts +147 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +199 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/commands/memory.d.ts +11 -0
  10. package/dist/commands/memory.d.ts.map +1 -0
  11. package/dist/commands/memory.js +49 -0
  12. package/dist/commands/memory.js.map +1 -0
  13. package/dist/commands/remember.d.ts +15 -0
  14. package/dist/commands/remember.d.ts.map +1 -0
  15. package/dist/commands/remember.js +61 -0
  16. package/dist/commands/remember.js.map +1 -0
  17. package/dist/config.d.ts +73 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +81 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/context/formatter.d.ts +33 -0
  22. package/dist/context/formatter.d.ts.map +1 -0
  23. package/dist/context/formatter.js +193 -0
  24. package/dist/context/formatter.js.map +1 -0
  25. package/dist/hooks/after-tool-call.d.ts +19 -0
  26. package/dist/hooks/after-tool-call.d.ts.map +1 -0
  27. package/dist/hooks/after-tool-call.js +53 -0
  28. package/dist/hooks/after-tool-call.js.map +1 -0
  29. package/dist/hooks/before-compaction.d.ts +19 -0
  30. package/dist/hooks/before-compaction.d.ts.map +1 -0
  31. package/dist/hooks/before-compaction.js +60 -0
  32. package/dist/hooks/before-compaction.js.map +1 -0
  33. package/dist/hooks/before-prompt-build.d.ts +20 -0
  34. package/dist/hooks/before-prompt-build.d.ts.map +1 -0
  35. package/dist/hooks/before-prompt-build.js +76 -0
  36. package/dist/hooks/before-prompt-build.js.map +1 -0
  37. package/dist/hooks/session-end.d.ts +18 -0
  38. package/dist/hooks/session-end.d.ts.map +1 -0
  39. package/dist/hooks/session-end.js +57 -0
  40. package/dist/hooks/session-end.js.map +1 -0
  41. package/dist/hooks/session-start.d.ts +17 -0
  42. package/dist/hooks/session-start.d.ts.map +1 -0
  43. package/dist/hooks/session-start.js +77 -0
  44. package/dist/hooks/session-start.js.map +1 -0
  45. package/dist/identity.d.ts +36 -0
  46. package/dist/identity.d.ts.map +1 -0
  47. package/dist/identity.js +106 -0
  48. package/dist/identity.js.map +1 -0
  49. package/dist/index.d.ts +24 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +208 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/services/file-watcher.d.ts +11 -0
  54. package/dist/services/file-watcher.d.ts.map +1 -0
  55. package/dist/services/file-watcher.js +139 -0
  56. package/dist/services/file-watcher.js.map +1 -0
  57. package/dist/tools/engram-decisions.d.ts +8 -0
  58. package/dist/tools/engram-decisions.d.ts.map +1 -0
  59. package/dist/tools/engram-decisions.js +70 -0
  60. package/dist/tools/engram-decisions.js.map +1 -0
  61. package/dist/tools/engram-remember.d.ts +9 -0
  62. package/dist/tools/engram-remember.d.ts.map +1 -0
  63. package/dist/tools/engram-remember.js +116 -0
  64. package/dist/tools/engram-remember.js.map +1 -0
  65. package/dist/tools/engram-search.d.ts +9 -0
  66. package/dist/tools/engram-search.d.ts.map +1 -0
  67. package/dist/tools/engram-search.js +62 -0
  68. package/dist/tools/engram-search.js.map +1 -0
  69. package/dist/tools/memory-forget.d.ts +10 -0
  70. package/dist/tools/memory-forget.d.ts.map +1 -0
  71. package/dist/tools/memory-forget.js +41 -0
  72. package/dist/tools/memory-forget.js.map +1 -0
  73. package/dist/tools/memory-get.d.ts +11 -0
  74. package/dist/tools/memory-get.d.ts.map +1 -0
  75. package/dist/tools/memory-get.js +86 -0
  76. package/dist/tools/memory-get.js.map +1 -0
  77. package/dist/tools/memory-migrate.d.ts +11 -0
  78. package/dist/tools/memory-migrate.d.ts.map +1 -0
  79. package/dist/tools/memory-migrate.js +180 -0
  80. package/dist/tools/memory-migrate.js.map +1 -0
  81. package/dist/types/openclaw.d.ts +212 -0
  82. package/dist/types/openclaw.d.ts.map +1 -0
  83. package/dist/types/openclaw.js +9 -0
  84. package/dist/types/openclaw.js.map +1 -0
  85. package/dist/utils/memory-files.d.ts +25 -0
  86. package/dist/utils/memory-files.d.ts.map +1 -0
  87. package/dist/utils/memory-files.js +187 -0
  88. package/dist/utils/memory-files.js.map +1 -0
  89. package/openclaw.plugin.json +86 -0
  90. package/package.json +45 -0
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * before_prompt_build hook — per-turn dynamic context search.
4
+ *
5
+ * Queries engram with the current user prompt and injects the top matching
6
+ * observations as prependContext so they appear immediately before the user's
7
+ * message in each turn.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.handleBeforePromptBuild = handleBeforePromptBuild;
11
+ const identity_js_1 = require("../identity.js");
12
+ const formatter_js_1 = require("../context/formatter.js");
13
+ /**
14
+ * Handle the before_prompt_build hook.
15
+ *
16
+ * @param event - The before_prompt_build event from OpenClaw.
17
+ * @param client - Shared engram REST client.
18
+ * @param config - Resolved plugin config.
19
+ * @returns Context to prepend, or void if nothing to inject.
20
+ */
21
+ async function handleBeforePromptBuild(event, client, config, logger) {
22
+ try {
23
+ if (!client.isAvailable())
24
+ return;
25
+ if (!event.prompt || event.prompt.trim() === '')
26
+ return;
27
+ const agentId = event.agentId ?? '';
28
+ const identity = (0, identity_js_1.resolveIdentity)(agentId, event.workspaceDir);
29
+ const project = config.project ?? identity.projectId;
30
+ let response;
31
+ try {
32
+ response = await client.searchContext({
33
+ project,
34
+ query: event.prompt,
35
+ cwd: event.workspaceDir,
36
+ agent_id: agentId,
37
+ });
38
+ }
39
+ catch (err) {
40
+ (logger ?? console).warn('[engram] before-prompt-build: searchContext failed', err);
41
+ return;
42
+ }
43
+ if (!response || !Array.isArray(response.observations) || response.observations.length === 0) {
44
+ return;
45
+ }
46
+ const { context, injectedIds, trimmedCount } = (0, formatter_js_1.formatContext)(response.observations, { tokenBudget: config.tokenBudget });
47
+ if (trimmedCount > 0) {
48
+ (logger ?? console).warn(`[engram] before-prompt-build: trimmed ${trimmedCount} observations to fit token budget`);
49
+ }
50
+ if (!context)
51
+ return;
52
+ (logger ?? console).warn(`[engram] before-prompt-build: injecting ${injectedIds.length} observations for project ${project}`);
53
+ // Mark injected observations (fire-and-forget)
54
+ if (injectedIds.length > 0) {
55
+ try {
56
+ const sessionResp = await client.initSession({
57
+ claudeSessionId: event.sessionId ?? agentId,
58
+ project,
59
+ prompt: event.prompt,
60
+ });
61
+ if (sessionResp && !sessionResp.skipped && sessionResp.sessionDbId) {
62
+ void client.markInjected(sessionResp.sessionDbId, injectedIds)
63
+ .catch(() => { });
64
+ }
65
+ }
66
+ catch {
67
+ // Non-critical — context was already injected
68
+ }
69
+ }
70
+ return { prependContext: context };
71
+ }
72
+ catch (err) {
73
+ (logger ?? console).error('[engram] hook error:', err);
74
+ }
75
+ }
76
+ //# sourceMappingURL=before-prompt-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"before-prompt-build.js","sourceRoot":"","sources":["../../src/hooks/before-prompt-build.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAoBH,0DAqEC;AArFD,gDAAiD;AACjD,0DAAwD;AAOxD;;;;;;;GAOG;AACI,KAAK,UAAU,uBAAuB,CAC3C,KAA6B,EAC7B,MAAwB,EACxB,MAAoB,EACpB,MAAqB;IAErB,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAO;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO;QAExD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC;QAErD,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC;gBACpC,OAAO;gBACP,KAAK,EAAE,KAAK,CAAC,MAAM;gBACnB,GAAG,EAAE,KAAK,CAAC,YAAY;gBACvB,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,oDAAoD,EAAE,GAAG,CAAC,CAAC;YACpF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7F,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,IAAA,4BAAa,EAC1D,QAAQ,CAAC,YAAY,EACrB,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CACpC,CAAC;QAEF,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CACtB,yCAAyC,YAAY,mCAAmC,CACzF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CACtB,2CAA2C,WAAW,CAAC,MAAM,6BAA6B,OAAO,EAAE,CACpG,CAAC;QAEF,+CAA+C;QAC/C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;oBAC3C,eAAe,EAAE,KAAK,CAAC,SAAS,IAAI,OAAO;oBAC3C,OAAO;oBACP,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBACH,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;oBACnE,KAAK,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC;yBAC3D,KAAK,CAAC,GAAG,EAAE,GAAmC,CAAC,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;QACH,CAAC;QAED,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * session_end hook — final backfill and session statistics.
3
+ *
4
+ * Submits any remaining conversation content to engram for extraction.
5
+ * This is the last chance to persist observations from the session.
6
+ */
7
+ import type { EngramRestClient } from '../client.js';
8
+ import type { PluginConfig } from '../config.js';
9
+ import type { SessionEndEvent, PluginLogger } from '../types/openclaw.js';
10
+ /**
11
+ * Handle the session_end hook.
12
+ *
13
+ * @param event - The session_end event from OpenClaw.
14
+ * @param client - Shared engram REST client.
15
+ * @param config - Resolved plugin config.
16
+ */
17
+ export declare function handleSessionEnd(event: SessionEndEvent, client: EngramRestClient, config: PluginConfig, logger?: PluginLogger): void;
18
+ //# sourceMappingURL=session-end.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-end.d.ts","sourceRoot":"","sources":["../../src/hooks/session-end.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,eAAe,EAAuB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAK/F;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,YAAY,GACpB,IAAI,CAwCN"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ /**
3
+ * session_end hook — final backfill and session statistics.
4
+ *
5
+ * Submits any remaining conversation content to engram for extraction.
6
+ * This is the last chance to persist observations from the session.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleSessionEnd = handleSessionEnd;
10
+ const identity_js_1 = require("../identity.js");
11
+ const MAX_MESSAGES = 20;
12
+ const CONTENT_MAX_CHARS = 6000;
13
+ /**
14
+ * Handle the session_end hook.
15
+ *
16
+ * @param event - The session_end event from OpenClaw.
17
+ * @param client - Shared engram REST client.
18
+ * @param config - Resolved plugin config.
19
+ */
20
+ function handleSessionEnd(event, client, config, logger) {
21
+ try {
22
+ if (!client.isAvailable())
23
+ return;
24
+ if (!config.autoExtract)
25
+ return;
26
+ const agentId = event.agentId ?? '';
27
+ const identity = (0, identity_js_1.resolveIdentity)(agentId, event.workspaceDir);
28
+ const project = config.project ?? identity.projectId;
29
+ const messages = Array.isArray(event.messages) ? event.messages : [];
30
+ if (messages.length === 0)
31
+ return;
32
+ const recent = messages.slice(-MAX_MESSAGES);
33
+ const content = recent
34
+ .map((m) => `[${m.role}]: ${m.content}`)
35
+ .join('\n\n');
36
+ if (!content)
37
+ return;
38
+ const truncated = content.length > CONTENT_MAX_CHARS
39
+ ? content.slice(0, CONTENT_MAX_CHARS)
40
+ : content;
41
+ const sessionId = event.sessionId ?? '';
42
+ if (!sessionId)
43
+ return;
44
+ // Fire-and-forget — do not await
45
+ void client.backfillSession({
46
+ session_id: sessionId,
47
+ project,
48
+ content: truncated,
49
+ });
50
+ (logger ?? console).warn(`[engram] session-end: submitted ${recent.length} messages for backfill` +
51
+ ` (project ${project}, reason: ${event.reason ?? 'unknown'})`);
52
+ }
53
+ catch (err) {
54
+ (logger ?? console).error('[engram] hook error:', err);
55
+ }
56
+ }
57
+ //# sourceMappingURL=session-end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../src/hooks/session-end.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAiBH,4CA6CC;AA1DD,gDAAiD;AAGjD,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAC9B,KAAsB,EACtB,MAAwB,EACxB,MAAoB,EACpB,MAAqB;IAErB,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAO;QAClC,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,OAAO;QAEhC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC;QAErD,MAAM,QAAQ,GAA0B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAElC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM;aACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;aACvC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEhB,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,iBAAiB;YAClD,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC;YACrC,CAAC,CAAC,OAAO,CAAC;QAEZ,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,iCAAiC;QACjC,KAAK,MAAM,CAAC,eAAe,CAAC;YAC1B,UAAU,EAAE,SAAS;YACrB,OAAO;YACP,OAAO,EAAE,SAAS;SACnB,CAAC,CAAC;QAEH,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CACtB,mCAAmC,MAAM,CAAC,MAAM,wBAAwB;YACtE,aAAa,OAAO,aAAa,KAAK,CAAC,MAAM,IAAI,SAAS,GAAG,CAChE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * session_start hook — fetches static session context from engram and injects
3
+ * it as appendSystemContext so it is available for the entire session.
4
+ */
5
+ import type { EngramRestClient } from '../client.js';
6
+ import type { PluginConfig } from '../config.js';
7
+ import type { SessionStartEvent, SessionStartResult, PluginLogger } from '../types/openclaw.js';
8
+ /**
9
+ * Handle the session_start hook.
10
+ *
11
+ * @param event - The session_start event from OpenClaw.
12
+ * @param client - Shared engram REST client.
13
+ * @param config - Resolved plugin config.
14
+ * @returns Append-system-context result or void.
15
+ */
16
+ export declare function handleSessionStart(event: SessionStartEvent, client: EngramRestClient, config: PluginConfig, logger?: PluginLogger): Promise<SessionStartResult | void>;
17
+ //# sourceMappingURL=session-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../src/hooks/session-start.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACb,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAyDpC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * session_start hook — fetches static session context from engram and injects
4
+ * it as appendSystemContext so it is available for the entire session.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.handleSessionStart = handleSessionStart;
8
+ const identity_js_1 = require("../identity.js");
9
+ const formatter_js_1 = require("../context/formatter.js");
10
+ /**
11
+ * Handle the session_start hook.
12
+ *
13
+ * @param event - The session_start event from OpenClaw.
14
+ * @param client - Shared engram REST client.
15
+ * @param config - Resolved plugin config.
16
+ * @returns Append-system-context result or void.
17
+ */
18
+ async function handleSessionStart(event, client, config, logger) {
19
+ try {
20
+ if (!client.isAvailable())
21
+ return;
22
+ const agentId = event.agentId ?? '';
23
+ const identity = (0, identity_js_1.resolveIdentity)(agentId, event.workspaceDir);
24
+ const project = config.project ?? identity.projectId;
25
+ const response = await client.getContextInject(agentId, event.workspaceDir);
26
+ if (!response || !Array.isArray(response.observations) || response.observations.length === 0) {
27
+ return;
28
+ }
29
+ const { context, injectedIds, trimmedCount } = (0, formatter_js_1.formatContext)(response.observations, { tokenBudget: config.tokenBudget });
30
+ if (trimmedCount > 0) {
31
+ (logger ?? console).warn(`[engram] session-start: trimmed ${trimmedCount} observations to fit token budget`);
32
+ }
33
+ if (!context)
34
+ return;
35
+ // Mark observations as injected (fire-and-forget)
36
+ if (injectedIds.length > 0 && response.sessionId) {
37
+ void client.markInjected(response.sessionId, injectedIds);
38
+ }
39
+ // Initialize session tracking (fire-and-forget)
40
+ const claudeSessionId = event.sessionId ?? agentId;
41
+ if (!claudeSessionId) {
42
+ (logger ?? console).warn('[engram] session-start: no sessionId or agentId available — skipping session init');
43
+ }
44
+ else {
45
+ void client.initSession({
46
+ claudeSessionId,
47
+ project,
48
+ prompt: event.initialPrompt,
49
+ });
50
+ }
51
+ (logger ?? console).warn(`[engram] session-start: injected ${injectedIds.length} observations for project ${project}`);
52
+ // Build static instructions + dynamic session context
53
+ const staticInstructions = buildStaticInstructions(project);
54
+ const fullContext = staticInstructions + '\n\n' + context;
55
+ return { appendSystemContext: fullContext };
56
+ }
57
+ catch (err) {
58
+ (logger ?? console).error('[engram] hook error:', err);
59
+ }
60
+ }
61
+ /**
62
+ * Build cacheable static instructions injected once per session.
63
+ * These describe available engram capabilities to the agent.
64
+ */
65
+ function buildStaticInstructions(project) {
66
+ return [
67
+ '# Engram Persistent Memory',
68
+ '',
69
+ 'You have access to persistent memory via engram. Available tools:',
70
+ '- `engram_search` — search prior observations, decisions, and patterns',
71
+ '- `engram_remember` — store new observations for future sessions',
72
+ '- `engram_decisions` — query architectural decisions',
73
+ '',
74
+ `Memory is scoped to project "${project}". Use \`engram_remember\` to store important insights, decisions, and discoveries.`,
75
+ ].join('\n');
76
+ }
77
+ //# sourceMappingURL=session-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../src/hooks/session-start.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAoBH,gDA8DC;AA9ED,gDAAiD;AACjD,0DAAwD;AAOxD;;;;;;;GAOG;AACI,KAAK,UAAU,kBAAkB,CACtC,KAAwB,EACxB,MAAwB,EACxB,MAAoB,EACpB,MAAqB;IAErB,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAAE,OAAO;QAElC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC;QAErD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAC5C,OAAO,EACP,KAAK,CAAC,YAAY,CACnB,CAAC;QAEF,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7F,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,IAAA,4BAAa,EAC1D,QAAQ,CAAC,YAAY,EACrB,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CACpC,CAAC;QAEF,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,mCAAmC,YAAY,mCAAmC,CAAC,CAAC;QAC/G,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,kDAAkD;QAClD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACjD,KAAK,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC5D,CAAC;QAED,gDAAgD;QAChD,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC;QACnD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;QAChH,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,CAAC,WAAW,CAAC;gBACtB,eAAe;gBACf,OAAO;gBACP,MAAM,EAAE,KAAK,CAAC,aAAa;aAC5B,CAAC,CAAC;QACL,CAAC;QAED,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CACtB,oCAAoC,WAAW,CAAC,MAAM,6BAA6B,OAAO,EAAE,CAC7F,CAAC;QAEF,sDAAsD;QACtD,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAC;QAE1D,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,OAAe;IAC9C,OAAO;QACL,4BAA4B;QAC5B,EAAE;QACF,mEAAmE;QACnE,wEAAwE;QACxE,kEAAkE;QAClE,sDAAsD;QACtD,EAAE;QACF,gCAAgC,OAAO,qFAAqF;KAC7H,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Project identity resolution.
3
+ *
4
+ * Priority order:
5
+ * 1. agentId (always available from OpenClaw, stable per session)
6
+ * 2. Git remote origin URL + relative path (cross-platform, cross-OS-path stable)
7
+ * 3. Absolute workspace path hash (fallback for non-git directories)
8
+ *
9
+ * The agentId is the PRIMARY scope for OpenClaw — every agent session has a unique
10
+ * stable identifier. Git-based ID is computed when workspaceDir is available so that
11
+ * observations can be shared across agents working in the same repository.
12
+ */
13
+ export interface ProjectIdentity {
14
+ /** Primary project identifier used for engram scoping. */
15
+ projectId: string;
16
+ /** The agentId from OpenClaw (always set). */
17
+ agentId: string;
18
+ /** Git remote URL if the workspace is a git repo with a remote. */
19
+ gitRemote?: string;
20
+ /** Relative path within the git repo, if applicable. */
21
+ relativePath?: string;
22
+ }
23
+ /**
24
+ * Compute the canonical project ID for the given working directory.
25
+ * Prefers git-remote-based ID; falls back to path-based ID.
26
+ */
27
+ export declare function projectIDFromWorkspace(workspaceDir: string): string;
28
+ /**
29
+ * Resolve the full project identity for an agent session.
30
+ *
31
+ * @param agentId - The unique agent session ID from OpenClaw (primary scope).
32
+ * @param workspaceDir - Optional workspace directory for git-based ID resolution.
33
+ * @returns A ProjectIdentity with the resolved projectId.
34
+ */
35
+ export declare function resolveIdentity(agentId: string, workspaceDir?: string): ProjectIdentity;
36
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA6DD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGnE;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,GACpB,eAAe,CAoBjB"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * Project identity resolution.
4
+ *
5
+ * Priority order:
6
+ * 1. agentId (always available from OpenClaw, stable per session)
7
+ * 2. Git remote origin URL + relative path (cross-platform, cross-OS-path stable)
8
+ * 3. Absolute workspace path hash (fallback for non-git directories)
9
+ *
10
+ * The agentId is the PRIMARY scope for OpenClaw — every agent session has a unique
11
+ * stable identifier. Git-based ID is computed when workspaceDir is available so that
12
+ * observations can be shared across agents working in the same repository.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.projectIDFromWorkspace = projectIDFromWorkspace;
16
+ exports.resolveIdentity = resolveIdentity;
17
+ const node_crypto_1 = require("node:crypto");
18
+ const node_child_process_1 = require("node:child_process");
19
+ const node_path_1 = require("node:path");
20
+ // Module-level memoization cache — keyed by resolved cwd path
21
+ const gitRemoteCache = new Map();
22
+ /**
23
+ * Compute a stable project ID from the git remote origin URL and relative path.
24
+ * Returns null if the directory is not a git repository or has no remote.
25
+ */
26
+ function getGitRemoteID(cwd) {
27
+ const cacheKey = (0, node_path_1.resolve)(cwd);
28
+ if (gitRemoteCache.has(cacheKey))
29
+ return gitRemoteCache.get(cacheKey);
30
+ try {
31
+ const opts = {
32
+ cwd,
33
+ stdio: ['ignore', 'pipe', 'ignore'],
34
+ timeout: 3000,
35
+ };
36
+ const remoteURL = (0, node_child_process_1.execSync)('git remote get-url origin', opts).toString().trim();
37
+ if (!remoteURL) {
38
+ gitRemoteCache.set(cacheKey, null);
39
+ return null;
40
+ }
41
+ const relativePath = (0, node_child_process_1.execSync)('git rev-parse --show-prefix', opts).toString().trim();
42
+ const key = remoteURL + '/' + relativePath;
43
+ const hash = (0, node_crypto_1.createHash)('sha256').update(key).digest('hex');
44
+ // Derive repo name from remote URL so projectId is stable across checkouts
45
+ const repoName = remoteURL.replace(/\/$/, '').split('/').pop()?.replace(/\.git$/, '') || 'repo';
46
+ const result = {
47
+ projectId: repoName + '_' + hash.slice(0, 8),
48
+ gitRemote: remoteURL,
49
+ relativePath,
50
+ };
51
+ gitRemoteCache.set(cacheKey, result);
52
+ return result;
53
+ }
54
+ catch {
55
+ gitRemoteCache.set(cacheKey, null);
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * Legacy path-based project ID (6-char hash of absolute path).
61
+ * Used as a fallback for directories without a git remote.
62
+ */
63
+ function legacyProjectID(cwd) {
64
+ const resolvedPath = (0, node_path_1.resolve)(cwd);
65
+ const dirName = (0, node_path_1.basename)(resolvedPath);
66
+ const hash = (0, node_crypto_1.createHash)('sha256').update(resolvedPath).digest('hex');
67
+ return dirName + '_' + hash.slice(0, 6);
68
+ }
69
+ /**
70
+ * Compute the canonical project ID for the given working directory.
71
+ * Prefers git-remote-based ID; falls back to path-based ID.
72
+ */
73
+ function projectIDFromWorkspace(workspaceDir) {
74
+ const gitResult = getGitRemoteID(workspaceDir);
75
+ return gitResult ? gitResult.projectId : legacyProjectID(workspaceDir);
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // Public API
79
+ // ---------------------------------------------------------------------------
80
+ /**
81
+ * Resolve the full project identity for an agent session.
82
+ *
83
+ * @param agentId - The unique agent session ID from OpenClaw (primary scope).
84
+ * @param workspaceDir - Optional workspace directory for git-based ID resolution.
85
+ * @returns A ProjectIdentity with the resolved projectId.
86
+ */
87
+ function resolveIdentity(agentId, workspaceDir) {
88
+ // agentId-first: when no workspace directory is available, use agentId as scope
89
+ if (!workspaceDir) {
90
+ return { projectId: agentId, agentId };
91
+ }
92
+ const gitResult = getGitRemoteID(workspaceDir);
93
+ if (gitResult) {
94
+ return {
95
+ projectId: gitResult.projectId,
96
+ agentId,
97
+ gitRemote: gitResult.gitRemote,
98
+ relativePath: gitResult.relativePath,
99
+ };
100
+ }
101
+ return {
102
+ projectId: legacyProjectID(workspaceDir),
103
+ agentId,
104
+ };
105
+ }
106
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * OpenClaw Engram Plugin
3
+ *
4
+ * Connects OpenClaw agents to engram persistent memory via REST API.
5
+ * Provides:
6
+ * - Session-level static context injection (appendSystemContext)
7
+ * - Per-turn dynamic context search (prependContext)
8
+ * - Automatic self-learning via tool event ingestion
9
+ * - Transcript backfill on compaction / session end
10
+ * - Agent tools: engram_search, engram_remember, engram_decisions,
11
+ * memory_search, memory_store, memory_forget, memory_get,
12
+ * memory_migrate
13
+ * - Slash commands: /memory, /remember, /migrate
14
+ * - CLI: openclaw memory status|search|store|migrate
15
+ */
16
+ import type { OpenClawPluginDefinition } from './types/openclaw.js';
17
+ declare const plugin: OpenClawPluginDefinition;
18
+ export default plugin;
19
+ export { EngramRestClient } from './client.js';
20
+ export { parseConfig, getJsonSchema } from './config.js';
21
+ export { resolveIdentity, projectIDFromWorkspace } from './identity.js';
22
+ export { formatContext } from './context/formatter.js';
23
+ export { AvailabilityTracker } from './availability.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,wBAAwB,EAIzB,MAAM,qBAAqB,CAAC;AA4B7B,QAAA,MAAM,MAAM,EAAE,wBAsLb,CAAC;AAEF,eAAe,MAAM,CAAC;AAGtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}