@keyoku/openclaw 1.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.
Files changed (66) hide show
  1. package/dist/capture.d.ts +23 -0
  2. package/dist/capture.d.ts.map +1 -0
  3. package/dist/capture.js +114 -0
  4. package/dist/capture.js.map +1 -0
  5. package/dist/cli.d.ts +8 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +71 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config.d.ts +28 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +19 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.d.ts +22 -0
  14. package/dist/context.d.ts.map +1 -0
  15. package/dist/context.js +136 -0
  16. package/dist/context.js.map +1 -0
  17. package/dist/heartbeat-setup.d.ts +10 -0
  18. package/dist/heartbeat-setup.d.ts.map +1 -0
  19. package/dist/heartbeat-setup.js +49 -0
  20. package/dist/heartbeat-setup.js.map +1 -0
  21. package/dist/hooks.d.ts +10 -0
  22. package/dist/hooks.d.ts.map +1 -0
  23. package/dist/hooks.js +152 -0
  24. package/dist/hooks.js.map +1 -0
  25. package/dist/incremental-capture.d.ts +24 -0
  26. package/dist/incremental-capture.d.ts.map +1 -0
  27. package/dist/incremental-capture.js +81 -0
  28. package/dist/incremental-capture.js.map +1 -0
  29. package/dist/index.d.ts +24 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +54 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/migration.d.ts +29 -0
  34. package/dist/migration.d.ts.map +1 -0
  35. package/dist/migration.js +203 -0
  36. package/dist/migration.js.map +1 -0
  37. package/dist/service.d.ts +7 -0
  38. package/dist/service.d.ts.map +1 -0
  39. package/dist/service.js +133 -0
  40. package/dist/service.js.map +1 -0
  41. package/dist/tools.d.ts +11 -0
  42. package/dist/tools.d.ts.map +1 -0
  43. package/dist/tools.js +188 -0
  44. package/dist/tools.js.map +1 -0
  45. package/dist/types.d.ts +55 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +8 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +31 -0
  50. package/src/capture.ts +116 -0
  51. package/src/cli.ts +95 -0
  52. package/src/config.ts +43 -0
  53. package/src/context.ts +164 -0
  54. package/src/heartbeat-setup.ts +53 -0
  55. package/src/hooks.ts +175 -0
  56. package/src/incremental-capture.ts +88 -0
  57. package/src/index.ts +68 -0
  58. package/src/migration.ts +241 -0
  59. package/src/service.ts +145 -0
  60. package/src/tools.ts +239 -0
  61. package/src/types.ts +40 -0
  62. package/test/capture.test.ts +139 -0
  63. package/test/context.test.ts +273 -0
  64. package/test/hooks.test.ts +137 -0
  65. package/test/tools.test.ts +174 -0
  66. package/tsconfig.json +8 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Keyoku binary lifecycle management.
3
+ * Starts/stops the Keyoku Go binary as a child process.
4
+ */
5
+ import { spawn } from 'node:child_process';
6
+ import { existsSync, mkdirSync } from 'node:fs';
7
+ import { resolve } from 'node:path';
8
+ import { randomBytes } from 'node:crypto';
9
+ let keyokuProcess = null;
10
+ /**
11
+ * Check if Keyoku is already running by attempting a health check.
12
+ */
13
+ async function isKeyokuRunning(url) {
14
+ try {
15
+ const controller = new AbortController();
16
+ const timer = setTimeout(() => controller.abort(), 2000);
17
+ const res = await fetch(`${url}/health`, { signal: controller.signal });
18
+ clearTimeout(timer);
19
+ return res.ok;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ /**
26
+ * Wait for Keyoku to become healthy, polling every interval up to a timeout.
27
+ */
28
+ async function waitForHealthy(url, timeoutMs = 5000, intervalMs = 500) {
29
+ const deadline = Date.now() + timeoutMs;
30
+ while (Date.now() < deadline) {
31
+ if (await isKeyokuRunning(url))
32
+ return true;
33
+ await new Promise((r) => setTimeout(r, intervalMs));
34
+ }
35
+ return false;
36
+ }
37
+ /**
38
+ * Find keyoku binary on disk or PATH.
39
+ */
40
+ function findKeyokuBinary() {
41
+ const home = process.env.HOME ?? '';
42
+ const candidates = [
43
+ resolve(home, '.keyoku', 'bin', 'keyoku'),
44
+ resolve(home, '.local', 'bin', 'keyoku'),
45
+ ];
46
+ for (const candidate of candidates) {
47
+ if (existsSync(candidate))
48
+ return candidate;
49
+ }
50
+ // Fall back to PATH resolution
51
+ return 'keyoku';
52
+ }
53
+ /**
54
+ * Ensure the Keyoku data directory exists and return the DB path.
55
+ */
56
+ function ensureDataDir() {
57
+ const dir = resolve(process.env.HOME ?? '', '.keyoku', 'data');
58
+ mkdirSync(dir, { recursive: true });
59
+ return resolve(dir, 'keyoku.db');
60
+ }
61
+ export function registerService(api, keyokuUrl) {
62
+ api.registerService({
63
+ id: 'keyoku-engine',
64
+ async start() {
65
+ // Skip if already running
66
+ if (await isKeyokuRunning(keyokuUrl)) {
67
+ api.logger.info('keyoku: Keyoku already running');
68
+ return;
69
+ }
70
+ const binary = findKeyokuBinary();
71
+ if (!binary) {
72
+ api.logger.warn('keyoku: Keyoku binary not found — memory features require Keyoku to be running');
73
+ return;
74
+ }
75
+ // Prepare environment
76
+ const env = { ...process.env };
77
+ if (!env.KEYOKU_SESSION_TOKEN) {
78
+ env.KEYOKU_SESSION_TOKEN = randomBytes(16).toString('hex');
79
+ api.logger.info('keyoku: Generated session token');
80
+ }
81
+ if (!env.KEYOKU_DB_PATH) {
82
+ env.KEYOKU_DB_PATH = ensureDataDir();
83
+ api.logger.info(`keyoku: Using database at ${env.KEYOKU_DB_PATH}`);
84
+ }
85
+ try {
86
+ keyokuProcess = spawn(binary, [], {
87
+ stdio: ['ignore', 'pipe', 'pipe'],
88
+ detached: false,
89
+ env,
90
+ });
91
+ // Pipe stdout/stderr to logger
92
+ keyokuProcess.stdout?.on('data', (data) => {
93
+ const line = data.toString().trim();
94
+ if (line)
95
+ api.logger.info(`keyoku: ${line}`);
96
+ });
97
+ keyokuProcess.stderr?.on('data', (data) => {
98
+ const line = data.toString().trim();
99
+ if (line)
100
+ api.logger.warn(`keyoku: ${line}`);
101
+ });
102
+ keyokuProcess.on('error', (err) => {
103
+ api.logger.warn(`keyoku: Failed to start Keyoku: ${err.message}`);
104
+ keyokuProcess = null;
105
+ });
106
+ keyokuProcess.on('exit', (code) => {
107
+ if (code !== 0 && code !== null) {
108
+ api.logger.warn(`keyoku: Keyoku exited with code ${code}`);
109
+ }
110
+ keyokuProcess = null;
111
+ });
112
+ // Wait for health check with retry
113
+ if (await waitForHealthy(keyokuUrl)) {
114
+ api.logger.info('keyoku: Keyoku started successfully');
115
+ }
116
+ else {
117
+ api.logger.warn('keyoku: Keyoku started but health check failed — it may still be initializing');
118
+ }
119
+ }
120
+ catch (err) {
121
+ api.logger.warn(`keyoku: Could not start Keyoku: ${String(err)}`);
122
+ }
123
+ },
124
+ stop() {
125
+ if (keyokuProcess) {
126
+ keyokuProcess.kill('SIGTERM');
127
+ keyokuProcess = null;
128
+ api.logger.info('keyoku: Keyoku stopped');
129
+ }
130
+ },
131
+ });
132
+ }
133
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * OpenClaw tool registrations for Keyoku memory operations.
3
+ * Registers 7 tools:
4
+ * memory_search, memory_get (OpenClaw standard — replaces built-in file-based memory)
5
+ * memory_store, memory_forget, memory_stats (Keyoku memory management)
6
+ * schedule_create, schedule_list (Keyoku scheduling)
7
+ */
8
+ import type { KeyokuClient } from '@keyoku/memory';
9
+ import type { PluginApi } from './types.js';
10
+ export declare function registerTools(api: PluginApi, client: KeyokuClient, entityId: string, agentId: string): void;
11
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAkO3G"}
package/dist/tools.js ADDED
@@ -0,0 +1,188 @@
1
+ /**
2
+ * OpenClaw tool registrations for Keyoku memory operations.
3
+ * Registers 7 tools:
4
+ * memory_search, memory_get (OpenClaw standard — replaces built-in file-based memory)
5
+ * memory_store, memory_forget, memory_stats (Keyoku memory management)
6
+ * schedule_create, schedule_list (Keyoku scheduling)
7
+ */
8
+ import { Type } from '@sinclair/typebox';
9
+ export function registerTools(api, client, entityId, agentId) {
10
+ // memory_search — OpenClaw-standard search tool (replaces memory-core's built-in)
11
+ api.registerTool({
12
+ name: 'memory_search',
13
+ label: 'Memory Search',
14
+ description: 'Search through memories for relevant information. Returns semantically similar memories ranked by relevance.',
15
+ parameters: Type.Object({
16
+ query: Type.String({ description: 'Search query' }),
17
+ maxResults: Type.Optional(Type.Number({ description: 'Max results (default: 5)' })),
18
+ minScore: Type.Optional(Type.Number({ description: 'Minimum relevance score 0-1' })),
19
+ }),
20
+ async execute(_toolCallId, params) {
21
+ const { query, maxResults = 5, minScore = 0.1 } = params;
22
+ const results = await client.search(entityId, query, { limit: maxResults, min_score: minScore });
23
+ if (results.length === 0) {
24
+ return {
25
+ content: [{ type: 'text', text: JSON.stringify({ results: [], provider: 'memory', mode: 'semantic' }) }],
26
+ details: { count: 0 },
27
+ };
28
+ }
29
+ const mapped = results.map((r) => ({
30
+ path: `mem:${r.memory.id}`,
31
+ startLine: 1,
32
+ endLine: 1,
33
+ score: r.similarity,
34
+ snippet: r.memory.content,
35
+ source: 'memory',
36
+ citation: `mem:${r.memory.id}`,
37
+ }));
38
+ return {
39
+ content: [
40
+ { type: 'text', text: JSON.stringify({ results: mapped, provider: 'memory', mode: 'semantic' }) },
41
+ ],
42
+ details: { count: mapped.length },
43
+ };
44
+ },
45
+ }, { name: 'memory_search' });
46
+ // memory_get — OpenClaw-standard memory read tool (replaces file-based reads)
47
+ api.registerTool({
48
+ name: 'memory_get',
49
+ label: 'Memory Get',
50
+ description: 'Read a specific memory by its ID (mem:<id>) or search for a memory by keyword.',
51
+ parameters: Type.Object({
52
+ path: Type.String({ description: 'Memory path (mem:<id>) or keyword to search' }),
53
+ from: Type.Optional(Type.Number({ description: 'Line offset (unused)' })),
54
+ lines: Type.Optional(Type.Number({ description: 'Line count (unused)' })),
55
+ }),
56
+ async execute(_toolCallId, params) {
57
+ const { path: memPath } = params;
58
+ if (memPath.startsWith('mem:') || memPath.startsWith('keyoku:')) {
59
+ const id = memPath.startsWith('mem:') ? memPath.slice(4) : memPath.slice(7);
60
+ try {
61
+ const memory = await client.getMemory(id);
62
+ return {
63
+ content: [{ type: 'text', text: JSON.stringify({ text: memory.content, path: memPath }) }],
64
+ };
65
+ }
66
+ catch {
67
+ return {
68
+ content: [{ type: 'text', text: JSON.stringify({ text: '', path: memPath, error: 'Memory not found' }) }],
69
+ };
70
+ }
71
+ }
72
+ // Fallback: treat path as a search query
73
+ const results = await client.search(entityId, memPath, { limit: 1 });
74
+ if (results.length > 0) {
75
+ return {
76
+ content: [
77
+ {
78
+ type: 'text',
79
+ text: JSON.stringify({
80
+ text: results[0].memory.content,
81
+ path: `mem:${results[0].memory.id}`,
82
+ }),
83
+ },
84
+ ],
85
+ };
86
+ }
87
+ return {
88
+ content: [{ type: 'text', text: JSON.stringify({ text: '', path: memPath, error: 'Not found' }) }],
89
+ };
90
+ },
91
+ }, { name: 'memory_get' });
92
+ // memory_store — store a new memory
93
+ api.registerTool({
94
+ name: 'memory_store',
95
+ label: 'Memory Store',
96
+ description: 'Save important information in long-term memory. Use for preferences, facts, decisions.',
97
+ parameters: Type.Object({
98
+ text: Type.String({ description: 'Information to remember' }),
99
+ }),
100
+ async execute(_toolCallId, params) {
101
+ const { text } = params;
102
+ const result = await client.remember(entityId, text, { agent_id: agentId });
103
+ return {
104
+ content: [{ type: 'text', text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}"` }],
105
+ details: { memories_created: result.memories_created },
106
+ };
107
+ },
108
+ }, { name: 'memory_store' });
109
+ // memory_forget — delete a memory by ID
110
+ api.registerTool({
111
+ name: 'memory_forget',
112
+ label: 'Memory Forget',
113
+ description: 'Delete a specific memory by ID.',
114
+ parameters: Type.Object({
115
+ memory_id: Type.String({ description: 'The memory ID to delete' }),
116
+ }),
117
+ async execute(_toolCallId, params) {
118
+ const { memory_id } = params;
119
+ const result = await client.deleteMemory(memory_id);
120
+ return {
121
+ content: [{ type: 'text', text: `Memory ${memory_id} deleted.` }],
122
+ details: { status: result.status },
123
+ };
124
+ },
125
+ }, { name: 'memory_forget' });
126
+ // memory_stats — get memory statistics
127
+ api.registerTool({
128
+ name: 'memory_stats',
129
+ label: 'Memory Stats',
130
+ description: 'Get memory statistics for the current entity.',
131
+ parameters: Type.Object({}),
132
+ async execute() {
133
+ const stats = await client.getStats(entityId);
134
+ const text = [
135
+ `Total memories: ${stats.total_memories}`,
136
+ `Active memories: ${stats.active_memories}`,
137
+ `By type: ${JSON.stringify(stats.by_type)}`,
138
+ `By state: ${JSON.stringify(stats.by_state)}`,
139
+ ].join('\n');
140
+ return {
141
+ content: [{ type: 'text', text }],
142
+ details: { ...stats },
143
+ };
144
+ },
145
+ }, { name: 'memory_stats' });
146
+ // schedule_create — create a scheduled memory
147
+ api.registerTool({
148
+ name: 'schedule_create',
149
+ label: 'Schedule Create',
150
+ description: 'Create a scheduled task/reminder. Cron tags: "daily", "weekly", "monthly", or a cron expression.',
151
+ parameters: Type.Object({
152
+ content: Type.String({ description: 'What to schedule' }),
153
+ cron_tag: Type.String({ description: 'Cron tag: "daily", "weekly", "monthly", or cron expression' }),
154
+ }),
155
+ async execute(_toolCallId, params) {
156
+ const { content, cron_tag } = params;
157
+ const result = await client.createSchedule(entityId, agentId, content, cron_tag);
158
+ return {
159
+ content: [{ type: 'text', text: `Scheduled: "${content}" (${cron_tag})` }],
160
+ details: { id: result.id },
161
+ };
162
+ },
163
+ }, { name: 'schedule_create' });
164
+ // schedule_list — list schedules
165
+ api.registerTool({
166
+ name: 'schedule_list',
167
+ label: 'Schedule List',
168
+ description: 'List active schedules.',
169
+ parameters: Type.Object({}),
170
+ async execute() {
171
+ const schedules = await client.listSchedules(entityId, agentId);
172
+ if (schedules.length === 0) {
173
+ return {
174
+ content: [{ type: 'text', text: 'No active schedules.' }],
175
+ details: { count: 0 },
176
+ };
177
+ }
178
+ const text = schedules
179
+ .map((s, i) => `${i + 1}. ${s.content} (id: ${s.id})`)
180
+ .join('\n');
181
+ return {
182
+ content: [{ type: 'text', text: `${schedules.length} schedules:\n\n${text}` }],
183
+ details: { count: schedules.length },
184
+ };
185
+ },
186
+ }, { name: 'schedule_list' });
187
+ }
188
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Minimal OpenClaw plugin API types.
3
+ * These mirror the types from openclaw/src/plugins/types.ts
4
+ * so that @keyoku/openclaw can compile without importing openclaw directly.
5
+ * At runtime, the actual OpenClaw API object is passed in.
6
+ */
7
+ export type PluginLogger = {
8
+ debug?: (message: string) => void;
9
+ info: (message: string) => void;
10
+ warn: (message: string) => void;
11
+ error: (message: string) => void;
12
+ };
13
+ export type ToolResult = {
14
+ content: Array<{
15
+ type: string;
16
+ text: string;
17
+ }>;
18
+ details?: Record<string, unknown>;
19
+ };
20
+ export type AgentTool = {
21
+ name: string;
22
+ label?: string;
23
+ description: string;
24
+ parameters: unknown;
25
+ execute: (toolCallId: string, params: Record<string, unknown>) => Promise<ToolResult>;
26
+ };
27
+ export type PluginApi = {
28
+ id: string;
29
+ name: string;
30
+ logger: PluginLogger;
31
+ pluginConfig?: Record<string, unknown>;
32
+ registerTool: (tool: AgentTool, opts?: {
33
+ name?: string;
34
+ names?: string[];
35
+ }) => void;
36
+ registerHook?: (events: string | string[], handler: (...args: unknown[]) => unknown, opts?: Record<string, unknown>) => void;
37
+ registerCli: (registrar: (ctx: {
38
+ program: unknown;
39
+ config: unknown;
40
+ logger: PluginLogger;
41
+ }) => void, opts?: {
42
+ commands?: string[];
43
+ }) => void;
44
+ registerService: (service: {
45
+ id: string;
46
+ start: (ctx: unknown) => void | Promise<void>;
47
+ stop?: (ctx: unknown) => void | Promise<void>;
48
+ }) => void;
49
+ resolvePath: (input: string) => string;
50
+ on: (hookName: string, handler: (...args: unknown[]) => unknown, opts?: {
51
+ priority?: number;
52
+ }) => void;
53
+ config?: Record<string, unknown>;
54
+ };
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACvF,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IACpF,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7H,WAAW,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7I,eAAe,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IACjJ,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Minimal OpenClaw plugin API types.
3
+ * These mirror the types from openclaw/src/plugins/types.ts
4
+ * so that @keyoku/openclaw can compile without importing openclaw directly.
5
+ * At runtime, the actual OpenClaw API object is passed in.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@keyoku/openclaw",
3
+ "version": "1.0.0",
4
+ "description": "Keyoku memory plugin for OpenClaw — persistent memory, heartbeat enhancement, and scheduling",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc"
10
+ },
11
+ "dependencies": {
12
+ "@keyoku/memory": "1.0.0",
13
+ "@keyoku/types": "1.0.0",
14
+ "@sinclair/typebox": "^0.34.0"
15
+ },
16
+ "peerDependencies": {
17
+ "openclaw": ">=0.1.0"
18
+ },
19
+ "peerDependenciesMeta": {
20
+ "openclaw": {
21
+ "optional": true
22
+ }
23
+ },
24
+ "openclaw": {
25
+ "extensions": ["dist/index.js"]
26
+ },
27
+ "license": "MIT",
28
+ "engines": {
29
+ "node": ">=20"
30
+ }
31
+ }
package/src/capture.ts ADDED
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Heuristic extraction of memorable facts from conversation messages.
3
+ * Only captures from user messages to avoid self-poisoning from model output.
4
+ */
5
+
6
+ const MEMORY_TRIGGERS = [
7
+ /remember|don't forget|keep in mind/i,
8
+ /i (like|prefer|hate|love|want|need|always|never)/i,
9
+ /my\s+\w+\s+is|is\s+my/i,
10
+ /decided|will use|going with|chose|switched to/i,
11
+ /important|critical|must|required/i,
12
+ /[\w.-]+@[\w.-]+\.\w+/, // email
13
+ /\+\d{10,}/, // phone number
14
+ ];
15
+
16
+ const PROMPT_INJECTION_PATTERNS = [
17
+ /ignore (all|any|previous|above|prior) instructions/i,
18
+ /do not follow (the )?(system|developer)/i,
19
+ /system prompt/i,
20
+ /<\s*(system|assistant|developer|tool)\b/i,
21
+ ];
22
+
23
+ /**
24
+ * Check if text looks like a prompt injection attempt.
25
+ */
26
+ export function looksLikePromptInjection(text: string): boolean {
27
+ const normalized = text.replace(/\s+/g, ' ').trim();
28
+ if (!normalized) return false;
29
+ return PROMPT_INJECTION_PATTERNS.some((p) => p.test(normalized));
30
+ }
31
+
32
+ /**
33
+ * Determine if a message should be captured as a memory.
34
+ */
35
+ export function shouldCapture(text: string, maxChars = 2000): boolean {
36
+ if (text.length < 10 || text.length > maxChars) return false;
37
+ if (text.includes('<relevant-memories>')) return false;
38
+ if (text.includes('<heartbeat-signals>')) return false;
39
+ if (text.startsWith('<') && text.includes('</')) return false;
40
+ if (looksLikePromptInjection(text)) return false;
41
+ return MEMORY_TRIGGERS.some((r) => r.test(text));
42
+ }
43
+
44
+ const SUBSTANTIAL_PATTERNS = [
45
+ // Decisions and choices
46
+ /\b(decided|will use|going with|chose|configured|set up|switched to|picked|selected)\b/i,
47
+ // Summaries and conclusions
48
+ /\b(summary|conclusion|result|finding|outcome|in short|to summarize|overall)\b/i,
49
+ // Actions completed
50
+ /\b(created|built|implemented|fixed|resolved|deployed|installed|migrated|refactored)\b/i,
51
+ // Explicit memory cues
52
+ /\b(note|remember|important|key takeaway|keep in mind|for reference|fyi)\b/i,
53
+ // Architecture and design
54
+ /\b(architecture|design|pattern|approach|strategy|tradeoff|trade-off)\b/i,
55
+ // Project structure
56
+ /\b(directory|folder|file structure|layout|organized|structured)\b/i,
57
+ // Tech stack and tools
58
+ /\b(using|stack|framework|library|database|api|endpoint|schema|model)\b/i,
59
+ // Contains bullet points or numbered lists (likely a list/summary)
60
+ /^\s*[-*]\s+/m,
61
+ /^\s*\d+[.)]\s+/m,
62
+ // Contains code references
63
+ /`[^`]+`/,
64
+ // Contains URLs or paths
65
+ /https?:\/\/\S+/,
66
+ /\/[\w-]+\/[\w-]+/,
67
+ ];
68
+
69
+ /**
70
+ * Check if text contains substantial information worth capturing.
71
+ * Used for incremental (per-message) capture of assistant output.
72
+ */
73
+ export function hasSubstantialContent(text: string): boolean {
74
+ if (text.length < 50) return false;
75
+ return SUBSTANTIAL_PATTERNS.some((p) => p.test(text));
76
+ }
77
+
78
+ /**
79
+ * Extract capturable text segments from conversation messages.
80
+ * Only processes user messages to avoid self-poisoning.
81
+ */
82
+ export function extractCapturableTexts(messages: unknown[], maxChars = 2000): string[] {
83
+ const texts: string[] = [];
84
+
85
+ for (const msg of messages) {
86
+ if (!msg || typeof msg !== 'object') continue;
87
+ const msgObj = msg as Record<string, unknown>;
88
+
89
+ // Only capture from user messages
90
+ if (msgObj.role !== 'user') continue;
91
+
92
+ const content = msgObj.content;
93
+ if (typeof content === 'string') {
94
+ if (shouldCapture(content, maxChars)) texts.push(content);
95
+ continue;
96
+ }
97
+
98
+ if (Array.isArray(content)) {
99
+ for (const block of content) {
100
+ if (
101
+ block &&
102
+ typeof block === 'object' &&
103
+ 'type' in block &&
104
+ (block as Record<string, unknown>).type === 'text' &&
105
+ 'text' in block &&
106
+ typeof (block as Record<string, unknown>).text === 'string'
107
+ ) {
108
+ const text = (block as Record<string, unknown>).text as string;
109
+ if (shouldCapture(text, maxChars)) texts.push(text);
110
+ }
111
+ }
112
+ }
113
+ }
114
+
115
+ return texts;
116
+ }