@hippodid/openclaw-plugin 1.0.5 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hippodid/openclaw-plugin",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Cloud sync for MEMORY.md with structured character memory. Survives context compaction.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,58 +1,37 @@
1
1
  import type { HippoDidClient } from '../hippodid-client.js';
2
- import type { PluginConfig, OpenClawPluginAPI } from '../types.js';
2
+ import type { PluginConfig } from '../types.js';
3
3
 
4
4
  export function createAutoCaptureHook(
5
5
  client: HippoDidClient,
6
6
  config: PluginConfig,
7
7
  logger: { info(msg: string): void; warn(msg: string): void },
8
- ): (api: OpenClawPluginAPI) => void {
9
- return (api: OpenClawPluginAPI) => {
10
- api.on('agent_end', (...args: unknown[]) => {
11
- try {
12
- const exchange = extractExchange(args);
13
- if (!exchange) return;
8
+ ): (api: any) => void {
9
+ return (api: any) => {
10
+ // OpenClaw 2026 does not support api.on() for post-response hooks.
11
+ // Register a capture tool that agents invoke to store important information.
12
+ api.registerTool('hippodid:remember', {
13
+ description: 'Save important information to HippoDid character memory. Call this to store facts, decisions, preferences, or context that should persist across sessions.',
14
+ args: [
15
+ {
16
+ name: 'content',
17
+ description: 'The information to remember',
18
+ required: true,
19
+ },
20
+ ],
21
+ handler: async (args: Record<string, string>) => {
22
+ const content = args['content'] ?? '';
23
+ if (!content) return 'Nothing to remember.';
14
24
 
15
- client
16
- .addMemory(config.characterId, exchange, 'openclaw-auto-capture')
17
- .then((result) => {
18
- if (result.ok) {
19
- logger.info('hippodid: captured exchange for memory extraction');
20
- } else {
21
- logger.warn(
22
- `hippodid: capture failed: ${result.error.message}`,
23
- );
24
- }
25
- })
26
- .catch((e) => {
27
- logger.warn(
28
- `hippodid: capture error: ${e instanceof Error ? e.message : 'unknown'}`,
29
- );
30
- });
31
- } catch (e) {
32
- logger.warn(
33
- `hippodid: capture hook error: ${e instanceof Error ? e.message : 'unknown'}`,
34
- );
35
- }
25
+ const result = await client.addMemory(config.characterId, content);
26
+ if (result.ok) {
27
+ logger.info(`hippodid: captured memory: ${content.slice(0, 80)}...`);
28
+ return 'Remembered.';
29
+ } else {
30
+ logger.warn(`hippodid: capture failed: ${result.error.message}`);
31
+ return `Failed to remember: ${result.error.message}`;
32
+ }
33
+ },
36
34
  });
35
+ logger.info('hippodid: auto-capture tool registered as hippodid:remember');
37
36
  };
38
37
  }
39
-
40
- function extractExchange(args: unknown[]): string | null {
41
- if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {
42
- const event = args[0] as Record<string, unknown>;
43
-
44
- const userMsg =
45
- typeof event['userMessage'] === 'string' ? event['userMessage'] : '';
46
- const agentResp =
47
- typeof event['agentResponse'] === 'string' ? event['agentResponse'] : '';
48
-
49
- if (userMsg || agentResp) {
50
- return `User: ${userMsg}\n\nAgent: ${agentResp}`;
51
- }
52
-
53
- if (typeof event['content'] === 'string') return event['content'];
54
- if (typeof event['text'] === 'string') return event['text'];
55
- }
56
- if (typeof args[0] === 'string') return args[0];
57
- return null;
58
- }
@@ -1,67 +1,36 @@
1
1
  import type { HippoDidClient } from '../hippodid-client.js';
2
- import type { PluginConfig, OpenClawPluginAPI } from '../types.js';
2
+ import type { PluginConfig } from '../types.js';
3
3
 
4
4
  export function createAutoRecallHook(
5
5
  client: HippoDidClient,
6
6
  config: PluginConfig,
7
7
  logger: { info(msg: string): void; warn(msg: string): void },
8
- ): (api: OpenClawPluginAPI) => void {
9
- return (api: OpenClawPluginAPI) => {
10
- api.on('before_agent_start', async (...args: unknown[]) => {
11
- try {
12
- const userMessage = extractUserMessage(args);
13
- if (!userMessage) return;
14
-
15
- const result = await client.searchMemories(
16
- config.characterId,
17
- userMessage,
18
- 5,
19
- );
20
-
21
- if (!result.ok) {
22
- logger.warn(
23
- `hippodid: recall search failed: ${result.error.message}`,
24
- );
25
- return;
26
- }
27
-
28
- const memories = result.value;
29
- if (memories.length === 0) {
30
- logger.info('hippodid: no relevant memories found');
31
- return;
8
+ ): (api: any) => void {
9
+ return (api: any) => {
10
+ // OpenClaw 2026 does not support api.on() for pre-response hooks.
11
+ // Register a recall tool that agents invoke when they need memory context.
12
+ api.registerTool('hippodid:recall', {
13
+ description: 'Search HippoDid character memory and return relevant context. Call this at the start of a task to recall relevant memories.',
14
+ args: [
15
+ {
16
+ name: 'query',
17
+ description: 'What to search for in memory',
18
+ required: true,
19
+ },
20
+ ],
21
+ handler: async (args: Record<string, string>) => {
22
+ const query = args['query'] ?? '';
23
+ const result = await client.searchMemories(config.characterId, query);
24
+ if (result.ok) {
25
+ const memories = result.value;
26
+ logger.info(`hippodid: recalled ${memories.length} memories for query: ${query}`);
27
+ return memories.map((m) => m.content).join('\n\n');
28
+ } else {
29
+ logger.warn(`hippodid: recall failed: ${result.error.message}`);
30
+ return 'No memories found.';
32
31
  }
33
-
34
- const contextBlock = formatMemoriesBlock(memories);
35
- api.context.prepend(contextBlock);
36
- logger.info(`hippodid: recalled ${memories.length} memories for context`);
37
- } catch (e) {
38
- logger.warn(
39
- `hippodid: recall hook error: ${e instanceof Error ? e.message : 'unknown'}`,
40
- );
41
- }
32
+ },
42
33
  });
34
+ logger.info('hippodid: auto-recall tool registered as hippodid:recall');
43
35
  };
44
36
  }
45
-
46
- function extractUserMessage(args: unknown[]): string | null {
47
- if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {
48
- const event = args[0] as Record<string, unknown>;
49
- if (typeof event['message'] === 'string') return event['message'];
50
- if (typeof event['content'] === 'string') return event['content'];
51
- if (typeof event['text'] === 'string') return event['text'];
52
- }
53
- if (typeof args[0] === 'string') return args[0];
54
- return null;
55
- }
56
-
57
- interface MemoryEntry {
58
- content: string;
59
- category: string;
60
- }
61
-
62
- function formatMemoriesBlock(memories: MemoryEntry[]): string {
63
- const lines = memories.map(
64
- (m) => `- [Category: ${m.category}] ${m.content}`,
65
- );
66
- return `<hippodid-memories>\n${lines.join('\n')}\n</hippodid-memories>`;
67
- }
@@ -1,22 +1,14 @@
1
1
  import type { FileSync } from '../file-sync.js';
2
- import type { OpenClawPluginAPI } from '../types.js';
3
2
 
4
3
  export function createMemoryFlushHook(
5
4
  fileSync: FileSync,
6
5
  logger: { info(msg: string): void; warn(msg: string): void },
7
- ): (api: OpenClawPluginAPI) => void {
8
- return (api: OpenClawPluginAPI) => {
9
- api.on('memoryFlush', async () => {
10
- try {
11
- const { synced, changed } = await fileSync.flushNow();
12
- logger.info(
13
- `hippodid: pre-compaction flush synced ${synced} files (${changed} changed)`,
14
- );
15
- } catch (e) {
16
- logger.warn(
17
- `hippodid: pre-compaction flush failed: ${e instanceof Error ? e.message : 'unknown'}`,
18
- );
19
- }
20
- });
6
+ ): (api: any) => void {
7
+ return (_api: any) => {
8
+ // OpenClaw 2026 does not support api.on() for event hooks.
9
+ // Pre-compaction flush is available via the hippodid:sync tool,
10
+ // which agents can call explicitly before a compaction.
11
+ // Background sync is handled by fileSync.start() interval.
12
+ logger.info('hippodid: memory flush handler ready (use hippodid:sync tool to trigger)');
21
13
  };
22
14
  }
@@ -1,42 +1,16 @@
1
1
  import type { FileSync } from '../file-sync.js';
2
2
  import type { TierManager } from '../tier-manager.js';
3
- import type { OpenClawPluginAPI } from '../types.js';
4
3
 
5
4
  export function createSessionHooks(
6
5
  fileSync: FileSync,
7
6
  tierManager: TierManager,
8
- autoRecallEnabled: boolean,
7
+ autoRecall: boolean,
9
8
  logger: { info(msg: string): void; warn(msg: string): void },
10
- ): (api: OpenClawPluginAPI) => void {
11
- return (api: OpenClawPluginAPI) => {
12
- api.on('session:start', async () => {
13
- try {
14
- await tierManager.initialize();
15
-
16
- if (tierManager.shouldHydrateOnStart(autoRecallEnabled)) {
17
- const count = await fileSync.hydrateFromCloud();
18
- logger.info(`hippodid: session started, hydrated ${count} files from cloud`);
19
- } else {
20
- logger.info('hippodid: session started, hydration skipped (autoRecall active)');
21
- }
22
- } catch (e) {
23
- logger.warn(
24
- `hippodid: session start error: ${e instanceof Error ? e.message : 'unknown'}`,
25
- );
26
- }
27
- });
28
-
29
- api.on('session:end', async () => {
30
- try {
31
- const { synced, changed } = await fileSync.flushNow();
32
- logger.info(
33
- `hippodid: session ended, final sync — ${synced} files (${changed} changed)`,
34
- );
35
- } catch (e) {
36
- logger.warn(
37
- `hippodid: session end flush failed: ${e instanceof Error ? e.message : 'unknown'}`,
38
- );
39
- }
40
- });
9
+ ): (api: any) => void {
10
+ return (_api: any) => {
11
+ // OpenClaw 2026 does not support api.on() for session lifecycle events.
12
+ // Session start hydration happens automatically via fileSync.start()
13
+ // which pulls cloud state on initialization.
14
+ logger.info('hippodid: session lifecycle handler ready');
41
15
  };
42
16
  }
package/src/index.ts CHANGED
@@ -17,7 +17,7 @@ export default {
17
17
 
18
18
  register(api: any): void {
19
19
  try {
20
- const config = resolveConfig(api.config);
20
+ const config = resolveConfig(api.config ?? {});
21
21
  const logger = api.logger ?? {
22
22
  info: (msg: string) => console.log(msg),
23
23
  warn: (msg: string) => console.warn(msg),
@@ -122,9 +122,20 @@ export default {
122
122
  };
123
123
 
124
124
  function resolveConfig(raw: any): PluginConfig {
125
+ if (!raw || typeof raw !== 'object') {
126
+ return {
127
+ apiKey: '',
128
+ characterId: '',
129
+ baseUrl: 'https://api.hippodid.com',
130
+ syncIntervalSeconds: 300,
131
+ autoRecall: false,
132
+ autoCapture: false,
133
+ additionalPaths: [],
134
+ };
135
+ }
125
136
  return {
126
- apiKey: raw.apiKey,
127
- characterId: raw.characterId,
137
+ apiKey: raw.apiKey ?? '',
138
+ characterId: raw.characterId ?? '',
128
139
  baseUrl: raw.baseUrl ?? 'https://api.hippodid.com',
129
140
  syncIntervalSeconds: raw.syncIntervalSeconds ?? 300,
130
141
  autoRecall: raw.autoRecall ?? false,
package/src/types.ts CHANGED
@@ -127,32 +127,7 @@ export interface FileTrackingEntry {
127
127
  lastSyncedAt: Date;
128
128
  }
129
129
 
130
- // --- OpenClaw Plugin API (local type, matches openclaw/plugin-sdk/core) ---
131
-
132
- export interface OpenClawPluginAPI {
133
- config: PluginConfig;
134
- logger: {
135
- info(message: string): void;
136
- warn(message: string): void;
137
- error(message: string): void;
138
- };
139
- on(event: string, handler: (...args: any[]) => void | Promise<void>): void;
140
- context: {
141
- prepend(content: string): void;
142
- };
143
- commands: {
144
- register(name: string, options: CommandOptions): void;
145
- };
146
- }
147
-
148
- export interface CommandOptions {
149
- description: string;
150
- args?: CommandArg[];
151
- handler: (args: Record<string, string>) => void | Promise<void>;
152
- }
153
-
154
- export interface CommandArg {
155
- name: string;
156
- description: string;
157
- required?: boolean;
158
- }
130
+ // OpenClaw Plugin API typed as `any` at boundaries.
131
+ // The real type comes from openclaw/plugin-sdk/core at runtime.
132
+ // Methods used: api.registerTool(), api.logger, api.config
133
+ export type OpenClawPluginAPI = any;