@karmaniverous/jeeves-watcher-openclaw 0.3.6 → 0.3.8

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/dist/cli.js CHANGED
@@ -8,9 +8,13 @@ import { fileURLToPath } from 'url';
8
8
  * CLI for installing/uninstalling the jeeves-watcher OpenClaw plugin.
9
9
  *
10
10
  * Usage:
11
- * npx \@karmaniverous/jeeves-watcher-openclaw install
11
+ * npx \@karmaniverous/jeeves-watcher-openclaw install [--memory]
12
12
  * npx \@karmaniverous/jeeves-watcher-openclaw uninstall
13
13
  *
14
+ * The --memory flag claims the OpenClaw memory slot, replacing memory-core
15
+ * with the plugin's Qdrant-backed memory_search and memory_get tools.
16
+ * Without --memory, only watcher admin tools are registered.
17
+ *
14
18
  * Bypasses OpenClaw's `plugins install` command, which has a known
15
19
  * spawn EINVAL bug on Windows (https://github.com/openclaw/openclaw/issues/9224).
16
20
  *
@@ -79,7 +83,7 @@ function patchAllowList(parent, key, label, mode) {
79
83
  return undefined;
80
84
  }
81
85
  /** Patch OpenClaw config for install or uninstall. Returns log messages. */
82
- function patchConfig(config, mode) {
86
+ function patchConfig(config, mode, options = {}) {
83
87
  const messages = [];
84
88
  // Ensure plugins section
85
89
  if (!config.plugins || typeof config.plugins !== 'object') {
@@ -110,13 +114,20 @@ function patchConfig(config, mode) {
110
114
  plugins.slots = {};
111
115
  }
112
116
  const slots = plugins.slots;
113
- if (mode === 'add') {
117
+ if (mode === 'add' && options.memory) {
114
118
  const prev = slots.memory;
115
119
  slots.memory = PLUGIN_ID;
116
120
  if (prev !== PLUGIN_ID) {
117
121
  messages.push(`Set plugins.slots.memory to "${PLUGIN_ID}"${prev ? ` (was "${prev}")` : ''}`);
118
122
  }
119
123
  }
124
+ else if (mode === 'add' && !options.memory) {
125
+ // Non-memory install: revert slot if we held it
126
+ if (slots.memory === PLUGIN_ID) {
127
+ slots.memory = 'memory-core';
128
+ messages.push(`Reverted plugins.slots.memory to "memory-core" (non-memory install)`);
129
+ }
130
+ }
120
131
  else if (slots.memory === PLUGIN_ID) {
121
132
  slots.memory = 'memory-core';
122
133
  messages.push(`Reverted plugins.slots.memory to "memory-core"`);
@@ -129,7 +140,7 @@ function patchConfig(config, mode) {
129
140
  return messages;
130
141
  }
131
142
  /** Install the plugin into OpenClaw's extensions directory. */
132
- function install() {
143
+ function install(memoryMode) {
133
144
  const home = resolveOpenClawHome();
134
145
  const configPath = resolveConfigPath(home);
135
146
  const extDir = join(home, 'extensions', PLUGIN_ID);
@@ -138,6 +149,7 @@ function install() {
138
149
  console.log(`Config: ${configPath}`);
139
150
  console.log(`Extensions dir: ${extDir}`);
140
151
  console.log(`Package root: ${pkgRoot}`);
152
+ console.log(`Memory mode: ${memoryMode ? 'yes (claiming memory slot)' : 'no (watcher tools only)'}`);
141
153
  console.log();
142
154
  if (!existsSync(home)) {
143
155
  console.error(`Error: OpenClaw home directory not found at ${home}`);
@@ -173,6 +185,20 @@ function install() {
173
185
  cpSync(nodeModulesSrc, join(extDir, 'node_modules'), { recursive: true });
174
186
  console.log(' ✓ node_modules');
175
187
  }
188
+ // Patch manifest based on memory mode
189
+ const installedManifestPath = join(extDir, 'openclaw.plugin.json');
190
+ const manifest = readJson(installedManifestPath);
191
+ if (manifest) {
192
+ if (memoryMode) {
193
+ manifest.kind = 'memory';
194
+ console.log(' ✓ Set kind: "memory" in manifest');
195
+ }
196
+ else {
197
+ delete manifest.kind;
198
+ console.log(' ✓ Removed kind from manifest (non-memory mode)');
199
+ }
200
+ writeJson(installedManifestPath, manifest);
201
+ }
176
202
  // Patch config
177
203
  console.log();
178
204
  console.log('Patching OpenClaw config...');
@@ -181,13 +207,19 @@ function install() {
181
207
  console.error(`Error: Could not parse ${configPath}`);
182
208
  process.exit(1);
183
209
  }
184
- for (const msg of patchConfig(config, 'add')) {
210
+ for (const msg of patchConfig(config, 'add', { memory: memoryMode })) {
185
211
  console.log(` ✓ ${msg}`);
186
212
  }
187
213
  writeJson(configPath, config);
188
214
  console.log();
189
215
  console.log('✅ Plugin installed successfully.');
190
216
  console.log(' Restart the OpenClaw gateway to load the plugin.');
217
+ if (memoryMode) {
218
+ console.log(' Memory slot claimed — memory_search and memory_get tools will be available.');
219
+ }
220
+ else {
221
+ console.log(' Watcher tools available. Run with --memory after bootstrapping to enable memory features.');
222
+ }
191
223
  }
192
224
  /** Uninstall the plugin from OpenClaw's extensions directory. */
193
225
  function uninstall() {
@@ -221,9 +253,10 @@ function uninstall() {
221
253
  }
222
254
  // Main
223
255
  const command = process.argv[2];
256
+ const memoryFlag = process.argv.includes('--memory');
224
257
  switch (command) {
225
258
  case 'install':
226
- install();
259
+ install(memoryFlag);
227
260
  break;
228
261
  case 'uninstall':
229
262
  uninstall();
@@ -232,8 +265,11 @@ switch (command) {
232
265
  console.log(`@karmaniverous/jeeves-watcher-openclaw — OpenClaw plugin installer`);
233
266
  console.log();
234
267
  console.log('Usage:');
235
- console.log(' npx @karmaniverous/jeeves-watcher-openclaw install Install plugin');
236
- console.log(' npx @karmaniverous/jeeves-watcher-openclaw uninstall Remove plugin');
268
+ console.log(' npx @karmaniverous/jeeves-watcher-openclaw install [--memory] Install plugin');
269
+ console.log(' npx @karmaniverous/jeeves-watcher-openclaw uninstall Remove plugin');
270
+ console.log();
271
+ console.log('Options:');
272
+ console.log(' --memory Claim memory slot (replaces memory-core with Qdrant-backed search)');
237
273
  console.log();
238
274
  console.log('Environment variables:');
239
275
  console.log(' OPENCLAW_CONFIG Path to openclaw.json (overrides all)');
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ function normalizePath(p) {
15
15
  }
16
16
  /**
17
17
  * Resolve the workspace path from gateway config.
18
- * Priority: agent-specific > defaults > fallback (~/.openclaw/workspace).
18
+ * Priority: agent-specific \> defaults \> fallback (~/.openclaw/workspace).
19
19
  */
20
20
  function getWorkspacePath(api) {
21
21
  const agentWorkspace = api.config?.agents?.entries?.['main']?.workspace ??
@@ -27,6 +27,26 @@ function getApiUrl(api) {
27
27
  const url = api.config?.plugins?.entries?.['jeeves-watcher-openclaw']?.config?.apiUrl;
28
28
  return typeof url === 'string' ? url : DEFAULT_API_URL;
29
29
  }
30
+ /**
31
+ * Resolve user-supplied schemas from plugin config.
32
+ * Returns a map of rule name → schema array (always normalized to array).
33
+ */
34
+ function getPluginSchemas(api) {
35
+ const config = api.config?.plugins?.entries?.['jeeves-watcher-openclaw']?.config;
36
+ const raw = config?.schemas;
37
+ if (!raw || typeof raw !== 'object')
38
+ return {};
39
+ const result = {};
40
+ for (const [name, value] of Object.entries(raw)) {
41
+ if (Array.isArray(value)) {
42
+ result[name] = value;
43
+ }
44
+ else if (typeof value === 'object' || typeof value === 'string') {
45
+ result[name] = [value];
46
+ }
47
+ }
48
+ return result;
49
+ }
30
50
  /** Format a successful tool result. */
31
51
  function ok(data) {
32
52
  return {
@@ -90,12 +110,42 @@ async function postJson(url, body) {
90
110
  * memory_search call. Re-attempts on failure. memory_get reads files
91
111
  * directly from the filesystem with path validation.
92
112
  */
93
- /** Build virtual inference rules for a workspace path. */
94
- function buildVirtualRules(workspace) {
113
+ /** Private property prefix namespaces plugin metadata to avoid collisions. */
114
+ const PROP_PREFIX = '_jeeves_watcher_openclaw_';
115
+ /** Private property keys used by the plugin for filtering. */
116
+ const PROP_SOURCE = `${PROP_PREFIX}source_`;
117
+ const PROP_KIND = `${PROP_PREFIX}kind_`;
118
+ /** Memory source value for filter queries. */
119
+ const SOURCE_MEMORY = 'memory';
120
+ /** Virtual rule names (exported for testing and config reference). */
121
+ const RULE_LONGTERM = 'openclaw-memory-longterm';
122
+ const RULE_DAILY = 'openclaw-memory-daily';
123
+ /**
124
+ * Build virtual inference rules for a workspace path.
125
+ *
126
+ * Each rule's schema is composed of:
127
+ * 1. Plugin-internal schema (private namespaced properties, no uiHint)
128
+ * 2. User-supplied schemas from plugin config (optional, owner-controlled)
129
+ */
130
+ function buildVirtualRules(workspace, userSchemas) {
95
131
  const ws = normalizePath(workspace);
132
+ const longtermInternal = {
133
+ type: 'object',
134
+ properties: {
135
+ [PROP_SOURCE]: { type: 'string', set: SOURCE_MEMORY },
136
+ [PROP_KIND]: { type: 'string', set: 'long-term' },
137
+ },
138
+ };
139
+ const dailyInternal = {
140
+ type: 'object',
141
+ properties: {
142
+ [PROP_SOURCE]: { type: 'string', set: SOURCE_MEMORY },
143
+ [PROP_KIND]: { type: 'string', set: 'daily-log' },
144
+ },
145
+ };
96
146
  return [
97
147
  {
98
- name: 'openclaw-memory-longterm',
148
+ name: RULE_LONGTERM,
99
149
  description: 'OpenClaw long-term memory file',
100
150
  match: {
101
151
  properties: {
@@ -106,18 +156,10 @@ function buildVirtualRules(workspace) {
106
156
  },
107
157
  },
108
158
  },
109
- schema: [
110
- {
111
- type: 'object',
112
- properties: {
113
- domain: { type: 'string', set: 'memory' },
114
- kind: { type: 'string', set: 'long-term' },
115
- },
116
- },
117
- ],
159
+ schema: [longtermInternal, ...(userSchemas[RULE_LONGTERM] ?? [])],
118
160
  },
119
161
  {
120
- name: 'openclaw-memory-daily',
162
+ name: RULE_DAILY,
121
163
  description: 'OpenClaw daily memory logs',
122
164
  match: {
123
165
  properties: {
@@ -128,15 +170,7 @@ function buildVirtualRules(workspace) {
128
170
  },
129
171
  },
130
172
  },
131
- schema: [
132
- {
133
- type: 'object',
134
- properties: {
135
- domain: { type: 'string', set: 'memory' },
136
- kind: { type: 'string', set: 'daily-log' },
137
- },
138
- },
139
- ],
173
+ schema: [dailyInternal, ...(userSchemas[RULE_DAILY] ?? [])],
140
174
  },
141
175
  ];
142
176
  }
@@ -158,6 +192,7 @@ function isAllowedMemoryPath(filePath, workspace) {
158
192
  */
159
193
  function createMemoryTools(api, baseUrl) {
160
194
  const workspace = getWorkspacePath(api);
195
+ const userSchemas = getPluginSchemas(api);
161
196
  const state = {
162
197
  initialized: false,
163
198
  lastWatcherUptime: 0,
@@ -180,7 +215,7 @@ function createMemoryTools(api, baseUrl) {
180
215
  body: JSON.stringify({ source: PLUGIN_SOURCE }),
181
216
  });
182
217
  // Register virtual rules
183
- const virtualRules = buildVirtualRules(state.workspace);
218
+ const virtualRules = buildVirtualRules(state.workspace, userSchemas);
184
219
  await postJson(`${state.baseUrl}/rules/register`, {
185
220
  source: PLUGIN_SOURCE,
186
221
  rules: virtualRules,
@@ -208,7 +243,7 @@ function createMemoryTools(api, baseUrl) {
208
243
  const body = {
209
244
  query: params.query,
210
245
  filter: {
211
- must: [{ key: 'domain', match: { value: 'memory' } }],
246
+ must: [{ key: PROP_SOURCE, match: { value: SOURCE_MEMORY } }],
212
247
  },
213
248
  };
214
249
  if (params.maxResults !== undefined)
package/dist/src/cli.d.ts CHANGED
@@ -2,9 +2,13 @@
2
2
  * CLI for installing/uninstalling the jeeves-watcher OpenClaw plugin.
3
3
  *
4
4
  * Usage:
5
- * npx \@karmaniverous/jeeves-watcher-openclaw install
5
+ * npx \@karmaniverous/jeeves-watcher-openclaw install [--memory]
6
6
  * npx \@karmaniverous/jeeves-watcher-openclaw uninstall
7
7
  *
8
+ * The --memory flag claims the OpenClaw memory slot, replacing memory-core
9
+ * with the plugin's Qdrant-backed memory_search and memory_get tools.
10
+ * Without --memory, only watcher admin tools are registered.
11
+ *
8
12
  * Bypasses OpenClaw's `plugins install` command, which has a known
9
13
  * spawn EINVAL bug on Windows (https://github.com/openclaw/openclaw/issues/9224).
10
14
  *
@@ -13,5 +17,10 @@
13
17
  * - OPENCLAW_HOME env var (path to .openclaw directory)
14
18
  * - Default: ~/.openclaw/openclaw.json
15
19
  */
20
+ /** Options for patchConfig. */
21
+ export interface PatchConfigOptions {
22
+ /** Whether to claim the memory slot (--memory flag). */
23
+ memory?: boolean;
24
+ }
16
25
  /** Patch OpenClaw config for install or uninstall. Returns log messages. */
17
- export declare function patchConfig(config: Record<string, unknown>, mode: 'add' | 'remove'): string[];
26
+ export declare function patchConfig(config: Record<string, unknown>, mode: 'add' | 'remove', options?: PatchConfigOptions): string[];
@@ -42,11 +42,22 @@ export declare const PLUGIN_SOURCE = "jeeves-watcher-openclaw";
42
42
  export declare function normalizePath(p: string): string;
43
43
  /**
44
44
  * Resolve the workspace path from gateway config.
45
- * Priority: agent-specific > defaults > fallback (~/.openclaw/workspace).
45
+ * Priority: agent-specific \> defaults \> fallback (~/.openclaw/workspace).
46
46
  */
47
47
  export declare function getWorkspacePath(api: PluginApi): string;
48
48
  /** Resolve the watcher API base URL from plugin config. */
49
49
  export declare function getApiUrl(api: PluginApi): string;
50
+ /**
51
+ * Schema value type — matches watcher inference rule schema conventions.
52
+ * Can be an inline JSON Schema object, a file reference string,
53
+ * a named schema reference, or a composable array of these.
54
+ */
55
+ export type SchemaValue = Record<string, unknown> | string | Array<Record<string, unknown> | string>;
56
+ /**
57
+ * Resolve user-supplied schemas from plugin config.
58
+ * Returns a map of rule name → schema array (always normalized to array).
59
+ */
60
+ export declare function getPluginSchemas(api: PluginApi): Record<string, Array<Record<string, unknown> | string>>;
50
61
  /** Format a successful tool result. */
51
62
  export declare function ok(data: unknown): ToolResult;
52
63
  /** Format an error tool result. */
@@ -7,6 +7,14 @@
7
7
  * directly from the filesystem with path validation.
8
8
  */
9
9
  import { type PluginApi, type ToolResult } from './helpers.js';
10
+ /** Private property keys used by the plugin for filtering. */
11
+ export declare const PROP_SOURCE = "_jeeves_watcher_openclaw_source_";
12
+ export declare const PROP_KIND = "_jeeves_watcher_openclaw_kind_";
13
+ /** Memory source value for filter queries. */
14
+ export declare const SOURCE_MEMORY = "memory";
15
+ /** Virtual rule names (exported for testing and config reference). */
16
+ export declare const RULE_LONGTERM = "openclaw-memory-longterm";
17
+ export declare const RULE_DAILY = "openclaw-memory-daily";
10
18
  /**
11
19
  * Create memory tool registrations for the plugin.
12
20
  * Returns register functions for memory_search and memory_get.
@@ -2,8 +2,7 @@
2
2
  "id": "jeeves-watcher-openclaw",
3
3
  "name": "Jeeves Watcher",
4
4
  "description": "Semantic search, metadata enrichment, and instance administration for a jeeves-watcher deployment.",
5
- "version": "0.3.6",
6
- "kind": "memory",
5
+ "version": "0.3.8",
7
6
  "skills": [
8
7
  "dist/skills/jeeves-watcher"
9
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-watcher-openclaw",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "author": "Jason Williscroft",
5
5
  "description": "OpenClaw plugin for jeeves-watcher — semantic search and metadata enrichment tools",
6
6
  "license": "BSD-3-Clause",