@karmaniverous/jeeves-meta-openclaw 0.1.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.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @karmaniverous/jeeves-meta-openclaw
2
+
3
+ OpenClaw plugin for [jeeves-meta](../lib/). Registers synthesis tools and virtual inference rules with the OpenClaw gateway.
4
+
5
+ ## Features
6
+
7
+ - **Four interactive tools** — `synth_list`, `synth_detail`, `synth_trigger`, `synth_preview`
8
+ - **GatewayExecutor** — spawns LLM sessions via the OpenClaw gateway HTTP API (included in core lib)
9
+ - **Virtual inference rules** — registers Qdrant indexing rules for `.meta/meta.json` files, archive snapshots, and config
10
+ - **TOOLS.md injection** — dynamic system prompt with entity stats and tool listing
11
+ - **Consumer skill** — `SKILL.md` for agent integration
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @karmaniverous/jeeves-meta-openclaw
17
+ ```
18
+
19
+ Then run the CLI installer to register with the OpenClaw gateway:
20
+
21
+ ```bash
22
+ npx @karmaniverous/jeeves-meta-openclaw install
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ The plugin reads its config path from the plugin `configPath` setting in `openclaw.json`. The config file itself is a standard `SynthConfig` JSON:
28
+
29
+ ```json
30
+ {
31
+ "watchPaths": ["j:/domains"],
32
+ "watcherUrl": "http://localhost:1936",
33
+ "gatewayUrl": "http://127.0.0.1:3000",
34
+ "defaultArchitect": "@file:jeeves-meta/prompts/architect.md",
35
+ "defaultCritic": "@file:jeeves-meta/prompts/critic.md"
36
+ }
37
+ ```
38
+
39
+ See the [Configuration Guide](../lib/guides/configuration.md) for all fields and defaults.
40
+
41
+ ## Documentation
42
+
43
+ - **[Plugin Setup](guides/plugin-setup.md)** — installation, config, lifecycle
44
+ - **[Tools Reference](guides/tools-reference.md)** — synth_list, synth_detail, synth_trigger, synth_preview
45
+ - **[Virtual Rules](guides/virtual-rules.md)** — Qdrant inference rules
46
+ - **[TOOLS.md Injection](guides/tools-injection.md)** — dynamic prompt generation
47
+
48
+ ## License
49
+
50
+ BSD-3-Clause
package/dist/cli.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, rmSync, mkdirSync, cpSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join, dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ /**
8
+ * CLI for installing/uninstalling the jeeves-meta OpenClaw plugin.
9
+ *
10
+ * Usage:
11
+ * npx \@karmaniverous/jeeves-meta-openclaw install
12
+ * npx \@karmaniverous/jeeves-meta-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
+ * @module cli
23
+ */
24
+ const PLUGIN_ID = 'jeeves-meta-openclaw';
25
+ /** Resolve the OpenClaw home directory. */
26
+ function resolveOpenClawHome() {
27
+ if (process.env.OPENCLAW_CONFIG) {
28
+ return dirname(resolve(process.env.OPENCLAW_CONFIG));
29
+ }
30
+ if (process.env.OPENCLAW_HOME) {
31
+ return resolve(process.env.OPENCLAW_HOME);
32
+ }
33
+ return join(homedir(), '.openclaw');
34
+ }
35
+ /** Resolve the config file path. */
36
+ function resolveConfigPath(home) {
37
+ if (process.env.OPENCLAW_CONFIG) {
38
+ return resolve(process.env.OPENCLAW_CONFIG);
39
+ }
40
+ return join(home, 'openclaw.json');
41
+ }
42
+ /** Get the package root (where this CLI lives). */
43
+ function getPackageRoot() {
44
+ const thisFile = fileURLToPath(import.meta.url);
45
+ return resolve(dirname(thisFile), '..');
46
+ }
47
+ /** Read and parse JSON, returning null on failure. */
48
+ function readJson(path) {
49
+ try {
50
+ return JSON.parse(readFileSync(path, 'utf8'));
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ /** Write JSON with 2-space indent + trailing newline. */
57
+ function writeJson(path, data) {
58
+ writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
59
+ }
60
+ /**
61
+ * Patch an allowlist array: add or remove the plugin ID.
62
+ * Returns a log message if a change was made, or undefined.
63
+ */
64
+ function patchAllowList(parent, key, label, mode) {
65
+ if (!Array.isArray(parent[key]) || parent[key].length === 0)
66
+ return undefined;
67
+ const list = parent[key];
68
+ if (mode === 'add') {
69
+ if (!list.includes(PLUGIN_ID)) {
70
+ list.push(PLUGIN_ID);
71
+ return `Added "${PLUGIN_ID}" to ${label}`;
72
+ }
73
+ }
74
+ else {
75
+ const filtered = list.filter((id) => id !== PLUGIN_ID);
76
+ if (filtered.length !== list.length) {
77
+ parent[key] = filtered;
78
+ return `Removed "${PLUGIN_ID}" from ${label}`;
79
+ }
80
+ }
81
+ return undefined;
82
+ }
83
+ /** Patch OpenClaw config for install or uninstall. Returns log messages. */
84
+ function patchConfig(config, mode) {
85
+ const messages = [];
86
+ // Ensure plugins section
87
+ if (!config.plugins || typeof config.plugins !== 'object') {
88
+ config.plugins = {};
89
+ }
90
+ const plugins = config.plugins;
91
+ // plugins.allow
92
+ const pluginAllow = patchAllowList(plugins, 'allow', 'plugins.allow', mode);
93
+ if (pluginAllow)
94
+ messages.push(pluginAllow);
95
+ // plugins.entries
96
+ if (!plugins.entries || typeof plugins.entries !== 'object') {
97
+ plugins.entries = {};
98
+ }
99
+ const entries = plugins.entries;
100
+ if (mode === 'add') {
101
+ if (!entries[PLUGIN_ID]) {
102
+ entries[PLUGIN_ID] = { enabled: true };
103
+ messages.push(`Added "${PLUGIN_ID}" to plugins.entries`);
104
+ }
105
+ }
106
+ else if (PLUGIN_ID in entries) {
107
+ Reflect.deleteProperty(entries, PLUGIN_ID);
108
+ messages.push(`Removed "${PLUGIN_ID}" from plugins.entries`);
109
+ }
110
+ // tools.allow
111
+ const tools = (config.tools ?? {});
112
+ const toolAllow = patchAllowList(tools, 'allow', 'tools.allow', mode);
113
+ if (toolAllow)
114
+ messages.push(toolAllow);
115
+ return messages;
116
+ }
117
+ /** Install the plugin into OpenClaw's extensions directory. */
118
+ function install() {
119
+ const home = resolveOpenClawHome();
120
+ const configPath = resolveConfigPath(home);
121
+ const extDir = join(home, 'extensions', PLUGIN_ID);
122
+ const pkgRoot = getPackageRoot();
123
+ console.log(`OpenClaw home: ${home}`);
124
+ console.log(`Config: ${configPath}`);
125
+ console.log(`Extensions dir: ${extDir}`);
126
+ console.log(`Package root: ${pkgRoot}`);
127
+ console.log();
128
+ if (!existsSync(home)) {
129
+ console.error(`Error: OpenClaw home directory not found at ${home}`);
130
+ console.error('Set OPENCLAW_HOME or OPENCLAW_CONFIG if using a non-default installation.');
131
+ process.exit(1);
132
+ }
133
+ if (!existsSync(configPath)) {
134
+ console.error(`Error: OpenClaw config not found at ${configPath}`);
135
+ console.error('Set OPENCLAW_CONFIG if using a non-default config location.');
136
+ process.exit(1);
137
+ }
138
+ const pluginManifestPath = join(pkgRoot, 'openclaw.plugin.json');
139
+ if (!existsSync(pluginManifestPath)) {
140
+ console.error(`Error: openclaw.plugin.json not found at ${pluginManifestPath}`);
141
+ process.exit(1);
142
+ }
143
+ // Copy package to extensions directory
144
+ console.log('Copying plugin to extensions directory...');
145
+ if (existsSync(extDir)) {
146
+ rmSync(extDir, { recursive: true, force: true });
147
+ }
148
+ mkdirSync(extDir, { recursive: true });
149
+ for (const file of ['dist', 'openclaw.plugin.json', 'package.json']) {
150
+ const src = join(pkgRoot, file);
151
+ const dest = join(extDir, file);
152
+ if (existsSync(src)) {
153
+ cpSync(src, dest, { recursive: true });
154
+ console.log(` \u2713 ${file}`);
155
+ }
156
+ }
157
+ const nodeModulesSrc = join(pkgRoot, 'node_modules');
158
+ if (existsSync(nodeModulesSrc)) {
159
+ cpSync(nodeModulesSrc, join(extDir, 'node_modules'), { recursive: true });
160
+ console.log(' \u2713 node_modules');
161
+ }
162
+ // Patch config
163
+ console.log();
164
+ console.log('Patching OpenClaw config...');
165
+ const config = readJson(configPath);
166
+ if (!config) {
167
+ console.error(`Error: Could not parse ${configPath}`);
168
+ process.exit(1);
169
+ }
170
+ for (const msg of patchConfig(config, 'add')) {
171
+ console.log(` \u2713 ${msg}`);
172
+ }
173
+ writeJson(configPath, config);
174
+ console.log();
175
+ console.log('\u2705 Plugin installed successfully.');
176
+ console.log(' Restart the OpenClaw gateway to load the plugin.');
177
+ }
178
+ /** Uninstall the plugin from OpenClaw's extensions directory. */
179
+ function uninstall() {
180
+ const home = resolveOpenClawHome();
181
+ const configPath = resolveConfigPath(home);
182
+ const extDir = join(home, 'extensions', PLUGIN_ID);
183
+ console.log(`OpenClaw home: ${home}`);
184
+ console.log(`Config: ${configPath}`);
185
+ console.log(`Extensions dir: ${extDir}`);
186
+ console.log();
187
+ if (existsSync(extDir)) {
188
+ rmSync(extDir, { recursive: true, force: true });
189
+ console.log(`\u2713 Removed ${extDir}`);
190
+ }
191
+ else {
192
+ console.log(' (extensions directory not found, skipping)');
193
+ }
194
+ if (existsSync(configPath)) {
195
+ console.log('Patching OpenClaw config...');
196
+ const config = readJson(configPath);
197
+ if (config) {
198
+ for (const msg of patchConfig(config, 'remove')) {
199
+ console.log(` \u2713 ${msg}`);
200
+ }
201
+ writeJson(configPath, config);
202
+ }
203
+ }
204
+ console.log();
205
+ console.log('\u2705 Plugin uninstalled successfully.');
206
+ console.log(' Restart the OpenClaw gateway to complete removal.');
207
+ }
208
+ // Main
209
+ const command = process.argv[2];
210
+ switch (command) {
211
+ case 'install':
212
+ install();
213
+ break;
214
+ case 'uninstall':
215
+ uninstall();
216
+ break;
217
+ default:
218
+ console.log(`@karmaniverous/jeeves-meta-openclaw \u2014 OpenClaw plugin installer`);
219
+ console.log();
220
+ console.log('Usage:');
221
+ console.log(' npx @karmaniverous/jeeves-meta-openclaw install Install plugin');
222
+ console.log(' npx @karmaniverous/jeeves-meta-openclaw uninstall Remove plugin');
223
+ console.log();
224
+ console.log('Environment variables:');
225
+ console.log(' OPENCLAW_CONFIG Path to openclaw.json (overrides all)');
226
+ console.log(' OPENCLAW_HOME Path to .openclaw directory');
227
+ console.log();
228
+ console.log('Default: ~/.openclaw/openclaw.json');
229
+ if (command &&
230
+ command !== 'help' &&
231
+ command !== '--help' &&
232
+ command !== '-h') {
233
+ console.error(`\nUnknown command: ${command}`);
234
+ process.exit(1);
235
+ }
236
+ break;
237
+ }
238
+
239
+ export { patchConfig };