@hippodid/openclaw-plugin 1.0.1 → 1.0.2

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.1",
3
+ "version": "1.0.2",
4
4
  "description": "Cloud sync for MEMORY.md with structured character memory. Survives context compaction.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -7,7 +7,7 @@ export function createAutoCaptureHook(
7
7
  logger: { info(msg: string): void; warn(msg: string): void },
8
8
  ): (api: OpenClawPluginAPI) => void {
9
9
  return (api: OpenClawPluginAPI) => {
10
- api.hooks.on('agent_end', (...args: unknown[]) => {
10
+ api.on('agent_end', (...args: unknown[]) => {
11
11
  try {
12
12
  const exchange = extractExchange(args);
13
13
  if (!exchange) return;
@@ -7,7 +7,7 @@ export function createAutoRecallHook(
7
7
  logger: { info(msg: string): void; warn(msg: string): void },
8
8
  ): (api: OpenClawPluginAPI) => void {
9
9
  return (api: OpenClawPluginAPI) => {
10
- api.hooks.on('before_agent_start', async (...args: unknown[]) => {
10
+ api.on('before_agent_start', async (...args: unknown[]) => {
11
11
  try {
12
12
  const userMessage = extractUserMessage(args);
13
13
  if (!userMessage) return;
@@ -6,7 +6,7 @@ export function createMemoryFlushHook(
6
6
  logger: { info(msg: string): void; warn(msg: string): void },
7
7
  ): (api: OpenClawPluginAPI) => void {
8
8
  return (api: OpenClawPluginAPI) => {
9
- api.hooks.on('memoryFlush', async () => {
9
+ api.on('memoryFlush', async () => {
10
10
  try {
11
11
  const { synced, changed } = await fileSync.flushNow();
12
12
  logger.info(
@@ -9,7 +9,7 @@ export function createSessionHooks(
9
9
  logger: { info(msg: string): void; warn(msg: string): void },
10
10
  ): (api: OpenClawPluginAPI) => void {
11
11
  return (api: OpenClawPluginAPI) => {
12
- api.hooks.on('session:start', async () => {
12
+ api.on('session:start', async () => {
13
13
  try {
14
14
  await tierManager.initialize();
15
15
 
@@ -26,7 +26,7 @@ export function createSessionHooks(
26
26
  }
27
27
  });
28
28
 
29
- api.hooks.on('session:end', async () => {
29
+ api.on('session:end', async () => {
30
30
  try {
31
31
  const { synced, changed } = await fileSync.flushNow();
32
32
  logger.info(
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { resolve } from 'node:path';
3
- import type { OpenClawPluginAPI, PluginConfig } from './types.js';
3
+ import type { OpenClawPluginAPI, PluginConfig, WatchPathConfig } from './types.js';
4
4
  import { createClient, type HippoDidClient } from './hippodid-client.js';
5
5
  import { createFileSync, type FileSync } from './file-sync.js';
6
6
  import { resolveWatchPaths } from './workspace-detector.js';
@@ -10,74 +10,146 @@ import { createSessionHooks } from './hooks/session-lifecycle.js';
10
10
  import { createAutoRecallHook } from './hooks/auto-recall.js';
11
11
  import { createAutoCaptureHook } from './hooks/auto-capture.js';
12
12
 
13
- export const id = 'hippodid';
14
-
15
13
  const VERSION = '1.0.0';
16
14
 
17
- export default function register(api: OpenClawPluginAPI): void {
18
- try {
19
- const config = resolveConfig(api.config);
20
- const logger = api.logger ?? {
21
- info: (msg: string) => console.log(msg),
22
- warn: (msg: string) => console.warn(msg),
23
- error: (msg: string) => console.error(msg),
24
- };
25
-
26
- const client = createClient(config.apiKey, config.baseUrl);
27
- const tierManager = createTierManager(client, config.characterId, logger);
28
- const watchPaths = resolveWatchPaths(config);
29
- const effectiveSyncInterval = Math.max(config.syncIntervalSeconds, 60);
30
- const fileSync = createFileSync(client, config, watchPaths, logger, effectiveSyncInterval);
31
-
32
- const registerMemoryFlush = createMemoryFlushHook(fileSync, logger);
33
- registerMemoryFlush(api);
34
-
35
- const registerSessionHooks = createSessionHooks(
36
- fileSync,
37
- tierManager,
38
- config.autoRecall,
39
- logger,
40
- );
41
- registerSessionHooks(api);
42
-
43
- tierManager.initialize().then((tier) => {
44
- if (tierManager.shouldMountAutoRecall(config.autoRecall)) {
45
- const registerAutoRecall = createAutoRecallHook(client, config, logger);
46
- registerAutoRecall(api);
47
- }
15
+ const plugin = {
16
+ id: 'hippodid',
17
+ name: 'HippoDid Memory',
18
+ description:
19
+ 'Persistent cloud memory for OpenClaw — survives context compaction',
48
20
 
49
- if (tierManager.shouldMountAutoCapture(config.autoCapture)) {
50
- const registerAutoCapture = createAutoCaptureHook(client, config, logger);
51
- registerAutoCapture(api);
52
- }
21
+ configSchema: {
22
+ type: 'object' as const,
23
+ required: ['apiKey', 'characterId'],
24
+ additionalProperties: false,
25
+ properties: {
26
+ apiKey: { type: 'string' as const },
27
+ characterId: { type: 'string' as const },
28
+ baseUrl: {
29
+ type: 'string' as const,
30
+ default: 'https://api.hippodid.com',
31
+ },
32
+ syncIntervalSeconds: {
33
+ type: 'number' as const,
34
+ default: 300,
35
+ minimum: 60,
36
+ },
37
+ autoRecall: { type: 'boolean' as const, default: false },
38
+ autoCapture: { type: 'boolean' as const, default: false },
39
+ additionalPaths: {
40
+ type: 'array' as const,
41
+ items: {
42
+ type: 'object' as const,
43
+ properties: {
44
+ path: { type: 'string' as const },
45
+ label: { type: 'string' as const },
46
+ },
47
+ required: ['path'],
48
+ },
49
+ default: [],
50
+ },
51
+ },
52
+ },
53
53
 
54
- if (tierManager.shouldMountFileSync(config.autoCapture)) {
55
- fileSync.start();
56
- }
54
+ register(api: OpenClawPluginAPI): void {
55
+ try {
56
+ const config = resolveConfig(api.config);
57
+ const logger = api.logger ?? {
58
+ info: (msg: string) => console.log(msg),
59
+ warn: (msg: string) => console.warn(msg),
60
+ error: (msg: string) => console.error(msg),
61
+ };
57
62
 
58
- const autoRecallStatus = tierManager.shouldMountAutoRecall(config.autoRecall)
59
- ? 'ON'
60
- : 'OFF';
61
- const autoCaptureStatus = tierManager.shouldMountAutoCapture(config.autoCapture)
62
- ? 'ON'
63
- : 'OFF';
63
+ const client = createClient(config.apiKey, config.baseUrl);
64
+ const tierManager = createTierManager(
65
+ client,
66
+ config.characterId,
67
+ logger,
68
+ );
69
+ const watchPaths = resolveWatchPaths(config);
70
+ const effectiveSyncInterval = Math.max(
71
+ config.syncIntervalSeconds,
72
+ 60,
73
+ );
74
+ const fileSync = createFileSync(
75
+ client,
76
+ config,
77
+ watchPaths,
78
+ logger,
79
+ effectiveSyncInterval,
80
+ );
64
81
 
65
- logger.info(
66
- `hippodid: v${VERSION} | character: ${config.characterId} | tier: ${tier.tier} | watching ${watchPaths.length} paths | autoRecall: ${autoRecallStatus} | autoCapture: ${autoCaptureStatus}`,
82
+ logger.info('hippodid: plugin loaded');
83
+
84
+ const registerMemoryFlush = createMemoryFlushHook(fileSync, logger);
85
+ registerMemoryFlush(api);
86
+
87
+ const registerSessionHooks = createSessionHooks(
88
+ fileSync,
89
+ tierManager,
90
+ config.autoRecall,
91
+ logger,
67
92
  );
68
- }).catch((e) => {
69
- logger.warn(
70
- `hippodid: tier initialization failed, running in free mode: ${e instanceof Error ? e.message : 'unknown'}`,
93
+ registerSessionHooks(api);
94
+
95
+ tierManager
96
+ .initialize()
97
+ .then((tier) => {
98
+ if (tierManager.shouldMountAutoRecall(config.autoRecall)) {
99
+ const registerAutoRecall = createAutoRecallHook(
100
+ client,
101
+ config,
102
+ logger,
103
+ );
104
+ registerAutoRecall(api);
105
+ }
106
+
107
+ if (tierManager.shouldMountAutoCapture(config.autoCapture)) {
108
+ const registerAutoCapture = createAutoCaptureHook(
109
+ client,
110
+ config,
111
+ logger,
112
+ );
113
+ registerAutoCapture(api);
114
+ }
115
+
116
+ if (tierManager.shouldMountFileSync(config.autoCapture)) {
117
+ fileSync.start();
118
+ }
119
+
120
+ const autoRecallStatus = tierManager.shouldMountAutoRecall(
121
+ config.autoRecall,
122
+ )
123
+ ? 'ON'
124
+ : 'OFF';
125
+ const autoCaptureStatus = tierManager.shouldMountAutoCapture(
126
+ config.autoCapture,
127
+ )
128
+ ? 'ON'
129
+ : 'OFF';
130
+
131
+ logger.info(
132
+ `hippodid: v${VERSION} | character: ${config.characterId} | tier: ${tier.tier} | watching ${watchPaths.length} paths | autoRecall: ${autoRecallStatus} | autoCapture: ${autoCaptureStatus}`,
133
+ );
134
+ })
135
+ .catch((e) => {
136
+ logger.warn(
137
+ `hippodid: tier initialization failed, running in free mode: ${e instanceof Error ? e.message : 'unknown'}`,
138
+ );
139
+ fileSync.start();
140
+ });
141
+
142
+ registerCommands(api, config, client, fileSync, tierManager, logger);
143
+ } catch (e) {
144
+ const msg = e instanceof Error ? e.message : 'unknown';
145
+ (api.logger ?? console).error(
146
+ `hippodid: plugin initialization failed: ${msg}`,
71
147
  );
72
- fileSync.start();
73
- });
74
-
75
- registerCommands(api, config, client, fileSync, tierManager, logger);
76
- } catch (e) {
77
- const msg = e instanceof Error ? e.message : 'unknown';
78
- (api.logger ?? console).error(`hippodid: plugin initialization failed: ${msg}`);
79
- }
80
- }
148
+ }
149
+ },
150
+ };
151
+
152
+ export default plugin;
81
153
 
82
154
  function resolveConfig(raw: PluginConfig): PluginConfig {
83
155
  return {
@@ -123,7 +195,9 @@ function registerCommands(
123
195
  );
124
196
  }
125
197
  } else {
126
- logger.warn(`Could not fetch sync status: ${statusResult.error.message}`);
198
+ logger.warn(
199
+ `Could not fetch sync status: ${statusResult.error.message}`,
200
+ );
127
201
  }
128
202
  },
129
203
  });
package/src/types.ts CHANGED
@@ -127,7 +127,7 @@ export interface FileTrackingEntry {
127
127
  lastSyncedAt: Date;
128
128
  }
129
129
 
130
- // --- OpenClaw Plugin API (local type, based on plan assumptions) ---
130
+ // --- OpenClaw Plugin API (local type, matches openclaw/plugin-sdk/core) ---
131
131
 
132
132
  export interface OpenClawPluginAPI {
133
133
  config: PluginConfig;
@@ -136,9 +136,7 @@ export interface OpenClawPluginAPI {
136
136
  warn(message: string): void;
137
137
  error(message: string): void;
138
138
  };
139
- hooks: {
140
- on(event: string, handler: (...args: any[]) => void | Promise<void>): void;
141
- };
139
+ on(event: string, handler: (...args: any[]) => void | Promise<void>): void;
142
140
  context: {
143
141
  prepend(content: string): void;
144
142
  };