@karmaniverous/jeeves-watcher-openclaw 0.1.0 → 0.1.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/README.md CHANGED
@@ -6,12 +6,32 @@
6
6
 
7
7
  A running [jeeves-watcher](https://www.npmjs.com/package/@karmaniverous/jeeves-watcher) service with its REST API accessible.
8
8
 
9
- ## Install
9
+ ## Installation
10
+
11
+ ### Standard (OpenClaw CLI)
10
12
 
11
13
  ```bash
12
14
  openclaw plugins install @karmaniverous/jeeves-watcher-openclaw
13
15
  ```
14
16
 
17
+ ### Self-Installer (Windows workaround)
18
+
19
+ OpenClaw's `plugins install` command has a known [`spawn EINVAL`](https://github.com/openclaw/openclaw/issues/9224) bug on Windows. This package includes a self-installer that bypasses the issue:
20
+
21
+ ```bash
22
+ npx @karmaniverous/jeeves-watcher-openclaw install
23
+ ```
24
+
25
+ This copies the plugin into OpenClaw's extensions directory and patches the config. To remove:
26
+
27
+ ```bash
28
+ npx @karmaniverous/jeeves-watcher-openclaw uninstall
29
+ ```
30
+
31
+ **Non-default installations:** Set `OPENCLAW_CONFIG` (path to `openclaw.json`) or `OPENCLAW_HOME` (path to `.openclaw` directory) if OpenClaw is not installed at the default location.
32
+
33
+ After install or uninstall, restart the OpenClaw gateway to apply changes.
34
+
15
35
  ## Configuration
16
36
 
17
37
  Set the `apiUrl` in the plugin configuration to point at your jeeves-watcher service:
package/dist/cli.js ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, rmSync, mkdirSync, cpSync, readFileSync, writeFileSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join, dirname, resolve } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ /**
8
+ * CLI for installing/uninstalling the jeeves-watcher OpenClaw plugin.
9
+ *
10
+ * Usage:
11
+ * npx \@karmaniverous/jeeves-watcher-openclaw install
12
+ * npx \@karmaniverous/jeeves-watcher-openclaw uninstall
13
+ *
14
+ * Bypasses OpenClaw's `plugins install` command, which has a known
15
+ * spawn EINVAL bug on Windows (https://github.com/openclaw/openclaw/issues/9224).
16
+ *
17
+ * Supports non-default installations via:
18
+ * - OPENCLAW_CONFIG env var (path to openclaw.json)
19
+ * - OPENCLAW_HOME env var (path to .openclaw directory)
20
+ * - Default: ~/.openclaw/openclaw.json
21
+ */
22
+ const PLUGIN_ID = 'jeeves-watcher-openclaw';
23
+ /** Resolve the OpenClaw home directory. */
24
+ function resolveOpenClawHome() {
25
+ // 1. OPENCLAW_CONFIG points directly to the config file
26
+ if (process.env.OPENCLAW_CONFIG) {
27
+ return dirname(resolve(process.env.OPENCLAW_CONFIG));
28
+ }
29
+ // 2. OPENCLAW_HOME points to the .openclaw directory
30
+ if (process.env.OPENCLAW_HOME) {
31
+ return resolve(process.env.OPENCLAW_HOME);
32
+ }
33
+ // 3. Default location
34
+ return join(homedir(), '.openclaw');
35
+ }
36
+ /** Resolve the config file path. */
37
+ function resolveConfigPath(home) {
38
+ if (process.env.OPENCLAW_CONFIG) {
39
+ return resolve(process.env.OPENCLAW_CONFIG);
40
+ }
41
+ return join(home, 'openclaw.json');
42
+ }
43
+ /** Get the package root (where this CLI lives). */
44
+ function getPackageRoot() {
45
+ const thisFile = fileURLToPath(import.meta.url);
46
+ // In dist: dist/cli.js → package root is ..
47
+ // In src: src/cli.ts → package root is ..
48
+ return resolve(dirname(thisFile), '..');
49
+ }
50
+ /** Read and parse JSON, returning null on failure. */
51
+ function readJson(path) {
52
+ try {
53
+ return JSON.parse(readFileSync(path, 'utf8'));
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ /** Write JSON with 2-space indent + trailing newline. */
60
+ function writeJson(path, data) {
61
+ writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
62
+ }
63
+ /** Install the plugin into OpenClaw's extensions directory. */
64
+ function install() {
65
+ const home = resolveOpenClawHome();
66
+ const configPath = resolveConfigPath(home);
67
+ const extDir = join(home, 'extensions', PLUGIN_ID);
68
+ const pkgRoot = getPackageRoot();
69
+ console.log(`OpenClaw home: ${home}`);
70
+ console.log(`Config: ${configPath}`);
71
+ console.log(`Extensions dir: ${extDir}`);
72
+ console.log(`Package root: ${pkgRoot}`);
73
+ console.log();
74
+ // Validate OpenClaw home exists
75
+ if (!existsSync(home)) {
76
+ console.error(`Error: OpenClaw home directory not found at ${home}`);
77
+ console.error('Set OPENCLAW_HOME or OPENCLAW_CONFIG if using a non-default installation.');
78
+ process.exit(1);
79
+ }
80
+ // Validate config exists
81
+ if (!existsSync(configPath)) {
82
+ console.error(`Error: OpenClaw config not found at ${configPath}`);
83
+ console.error('Set OPENCLAW_CONFIG if using a non-default config location.');
84
+ process.exit(1);
85
+ }
86
+ // Validate package root has openclaw.plugin.json
87
+ const pluginManifestPath = join(pkgRoot, 'openclaw.plugin.json');
88
+ if (!existsSync(pluginManifestPath)) {
89
+ console.error(`Error: openclaw.plugin.json not found at ${pluginManifestPath}`);
90
+ process.exit(1);
91
+ }
92
+ // Copy package to extensions directory
93
+ console.log('Copying plugin to extensions directory...');
94
+ if (existsSync(extDir)) {
95
+ rmSync(extDir, { recursive: true, force: true });
96
+ }
97
+ mkdirSync(extDir, { recursive: true });
98
+ // Copy dist/, openclaw.plugin.json, package.json
99
+ const filesToCopy = ['dist', 'openclaw.plugin.json', 'package.json'];
100
+ for (const file of filesToCopy) {
101
+ const src = join(pkgRoot, file);
102
+ const dest = join(extDir, file);
103
+ if (existsSync(src)) {
104
+ cpSync(src, dest, { recursive: true });
105
+ console.log(` ✓ ${file}`);
106
+ }
107
+ }
108
+ // Copy node_modules if present (for runtime dependencies)
109
+ const nodeModulesSrc = join(pkgRoot, 'node_modules');
110
+ if (existsSync(nodeModulesSrc)) {
111
+ cpSync(nodeModulesSrc, join(extDir, 'node_modules'), { recursive: true });
112
+ console.log(' ✓ node_modules');
113
+ }
114
+ // Patch OpenClaw config
115
+ console.log();
116
+ console.log('Patching OpenClaw config...');
117
+ const config = readJson(configPath);
118
+ if (!config) {
119
+ console.error(`Error: Could not parse ${configPath}`);
120
+ process.exit(1);
121
+ }
122
+ // Ensure plugins section exists
123
+ if (!config.plugins || typeof config.plugins !== 'object') {
124
+ config.plugins = {};
125
+ }
126
+ const plugins = config.plugins;
127
+ // If plugins.allow exists and is populated, add ourselves to it
128
+ if (Array.isArray(plugins.allow) && plugins.allow.length > 0) {
129
+ const allow = plugins.allow;
130
+ if (!allow.includes(PLUGIN_ID)) {
131
+ allow.push(PLUGIN_ID);
132
+ console.log(` ✓ Added "${PLUGIN_ID}" to plugins.allow`);
133
+ }
134
+ }
135
+ // Add to plugins.entries
136
+ if (!plugins.entries || typeof plugins.entries !== 'object') {
137
+ plugins.entries = {};
138
+ }
139
+ const entries = plugins.entries;
140
+ if (!entries[PLUGIN_ID]) {
141
+ entries[PLUGIN_ID] = { enabled: true };
142
+ console.log(` ✓ Added "${PLUGIN_ID}" to plugins.entries`);
143
+ }
144
+ // If tools.allow exists and is populated, add ourselves to it
145
+ const tools = (config.tools ?? {});
146
+ if (Array.isArray(tools.allow) && tools.allow.length > 0) {
147
+ const toolsAllow = tools.allow;
148
+ if (!toolsAllow.includes(PLUGIN_ID)) {
149
+ toolsAllow.push(PLUGIN_ID);
150
+ console.log(` ✓ Added "${PLUGIN_ID}" to tools.allow`);
151
+ }
152
+ }
153
+ writeJson(configPath, config);
154
+ console.log();
155
+ console.log('✅ Plugin installed successfully.');
156
+ console.log(' Restart the OpenClaw gateway to load the plugin.');
157
+ }
158
+ /** Uninstall the plugin from OpenClaw's extensions directory. */
159
+ function uninstall() {
160
+ const home = resolveOpenClawHome();
161
+ const configPath = resolveConfigPath(home);
162
+ const extDir = join(home, 'extensions', PLUGIN_ID);
163
+ console.log(`OpenClaw home: ${home}`);
164
+ console.log(`Config: ${configPath}`);
165
+ console.log(`Extensions dir: ${extDir}`);
166
+ console.log();
167
+ // Remove extensions directory
168
+ if (existsSync(extDir)) {
169
+ rmSync(extDir, { recursive: true, force: true });
170
+ console.log(`✓ Removed ${extDir}`);
171
+ }
172
+ else {
173
+ console.log(` (extensions directory not found, skipping)`);
174
+ }
175
+ // Patch OpenClaw config
176
+ if (existsSync(configPath)) {
177
+ console.log('Patching OpenClaw config...');
178
+ const config = readJson(configPath);
179
+ if (config) {
180
+ const plugins = (config.plugins ?? {});
181
+ // Remove from plugins.allow if it exists and is populated
182
+ if (Array.isArray(plugins.allow) && plugins.allow.length > 0) {
183
+ plugins.allow = plugins.allow.filter((id) => id !== PLUGIN_ID);
184
+ console.log(` ✓ Removed "${PLUGIN_ID}" from plugins.allow`);
185
+ }
186
+ // Remove from plugins.entries
187
+ if (plugins.entries && typeof plugins.entries === 'object') {
188
+ const entries = plugins.entries;
189
+ if (PLUGIN_ID in entries) {
190
+ Reflect.deleteProperty(entries, PLUGIN_ID);
191
+ console.log(` ✓ Removed "${PLUGIN_ID}" from plugins.entries`);
192
+ }
193
+ }
194
+ // Remove from tools.allow if it exists and is populated
195
+ const tools = (config.tools ?? {});
196
+ if (Array.isArray(tools.allow) && tools.allow.length > 0) {
197
+ tools.allow = tools.allow.filter((id) => id !== PLUGIN_ID);
198
+ console.log(` ✓ Removed "${PLUGIN_ID}" from tools.allow`);
199
+ }
200
+ writeJson(configPath, config);
201
+ }
202
+ }
203
+ console.log();
204
+ console.log('✅ Plugin uninstalled successfully.');
205
+ console.log(' Restart the OpenClaw gateway to complete removal.');
206
+ }
207
+ // Main
208
+ const command = process.argv[2];
209
+ switch (command) {
210
+ case 'install':
211
+ install();
212
+ break;
213
+ case 'uninstall':
214
+ uninstall();
215
+ break;
216
+ default:
217
+ console.log(`@karmaniverous/jeeves-watcher-openclaw — OpenClaw plugin installer`);
218
+ console.log();
219
+ console.log('Usage:');
220
+ console.log(' npx @karmaniverous/jeeves-watcher-openclaw install Install plugin');
221
+ console.log(' npx @karmaniverous/jeeves-watcher-openclaw uninstall Remove plugin');
222
+ console.log();
223
+ console.log('Environment variables:');
224
+ console.log(' OPENCLAW_CONFIG Path to openclaw.json (overrides all)');
225
+ console.log(' OPENCLAW_HOME Path to .openclaw directory');
226
+ console.log();
227
+ console.log('Default: ~/.openclaw/openclaw.json');
228
+ if (command &&
229
+ command !== 'help' &&
230
+ command !== '--help' &&
231
+ command !== '-h') {
232
+ console.error(`\nUnknown command: ${command}`);
233
+ process.exit(1);
234
+ }
235
+ break;
236
+ }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * @module rollup.config
3
- * Rollup configuration for the OpenClaw plugin package. Single ESM output.
3
+ * Rollup configuration for the OpenClaw plugin package.
4
+ * Two entry points: plugin (ESM + declarations) and CLI (ESM executable).
4
5
  */
5
6
  import type { RollupOptions } from 'rollup';
6
- declare const config: RollupOptions;
7
- export default config;
7
+ declare const _default: RollupOptions[];
8
+ export default _default;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * CLI for installing/uninstalling the jeeves-watcher OpenClaw plugin.
3
+ *
4
+ * Usage:
5
+ * npx \@karmaniverous/jeeves-watcher-openclaw install
6
+ * npx \@karmaniverous/jeeves-watcher-openclaw uninstall
7
+ *
8
+ * Bypasses OpenClaw's `plugins install` command, which has a known
9
+ * spawn EINVAL bug on Windows (https://github.com/openclaw/openclaw/issues/9224).
10
+ *
11
+ * Supports non-default installations via:
12
+ * - OPENCLAW_CONFIG env var (path to openclaw.json)
13
+ * - OPENCLAW_HOME env var (path to .openclaw directory)
14
+ * - Default: ~/.openclaw/openclaw.json
15
+ */
16
+ export {};
@@ -1,9 +1,12 @@
1
1
  {
2
- "id": "jeeves-watcher",
2
+ "id": "jeeves-watcher-openclaw",
3
3
  "name": "Jeeves Watcher",
4
4
  "description": "Semantic search and metadata enrichment via a jeeves-watcher instance.",
5
- "version": "0.5.0",
6
- "skills": ["dist/skills/jeeves-watcher", "dist/skills/jeeves-watcher-admin"],
5
+ "version": "0.1.2",
6
+ "skills": [
7
+ "dist/skills/jeeves-watcher",
8
+ "dist/skills/jeeves-watcher-admin"
9
+ ],
7
10
  "configSchema": {
8
11
  "type": "object",
9
12
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-watcher-openclaw",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "jeeves-watcher-openclaw": "./dist/cli.js"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "import": {
@@ -17,8 +20,7 @@
17
20
  },
18
21
  "files": [
19
22
  "dist",
20
- "openclaw.plugin.json",
21
- "dist/skills"
23
+ "openclaw.plugin.json"
22
24
  ],
23
25
  "publishConfig": {
24
26
  "access": "public"
@@ -77,12 +79,16 @@
77
79
  "git": {
78
80
  "changelog": "npx auto-changelog --unreleased-only --stdout --template https://raw.githubusercontent.com/release-it/release-it/main/templates/changelog-compact.hbs",
79
81
  "commitMessage": "chore: release @karmaniverous/jeeves-watcher-openclaw v${version}",
82
+ "tagName": "openclaw/${version}",
80
83
  "requireBranch": "main"
81
84
  },
82
85
  "github": {
83
86
  "release": true
84
87
  },
85
88
  "hooks": {
89
+ "after:bump": [
90
+ "node -e \"const f='openclaw.plugin.json';const j=JSON.parse(require('fs').readFileSync(f,'utf8'));j.version='${version}';require('fs').writeFileSync(f,JSON.stringify(j,null,2)+'\\n')\""
91
+ ],
86
92
  "after:init": [
87
93
  "npm run lint",
88
94
  "npm run typecheck",