@karmaniverous/jeeves-server-openclaw 0.1.0-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/dist/cli.js +222 -0
- package/dist/index.js +416 -0
- package/dist/rollup.config.d.ts +7 -0
- package/dist/scripts/build-skills.d.ts +1 -0
- package/dist/skills/jeeves-server/SKILL.md +139 -0
- package/dist/src/cli.d.ts +8 -0
- package/dist/src/cli.test.d.ts +1 -0
- package/dist/src/helpers.d.ts +46 -0
- package/dist/src/helpers.test.d.ts +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/promptInjection.d.ts +7 -0
- package/dist/src/promptInjection.test.d.ts +1 -0
- package/dist/src/serverTools.d.ts +6 -0
- package/dist/src/toolsWriter.d.ts +8 -0
- package/openclaw.plugin.json +34 -0
- package/package.json +107 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
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-server OpenClaw plugin.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* npx \@karmaniverous/jeeves-server-openclaw install
|
|
12
|
+
* npx \@karmaniverous/jeeves-server-openclaw uninstall
|
|
13
|
+
*/
|
|
14
|
+
const PLUGIN_ID = 'jeeves-server-openclaw';
|
|
15
|
+
function resolveOpenClawHome() {
|
|
16
|
+
if (process.env.OPENCLAW_CONFIG)
|
|
17
|
+
return dirname(resolve(process.env.OPENCLAW_CONFIG));
|
|
18
|
+
if (process.env.OPENCLAW_HOME)
|
|
19
|
+
return resolve(process.env.OPENCLAW_HOME);
|
|
20
|
+
return join(homedir(), '.openclaw');
|
|
21
|
+
}
|
|
22
|
+
function resolveConfigPath(home) {
|
|
23
|
+
if (process.env.OPENCLAW_CONFIG)
|
|
24
|
+
return resolve(process.env.OPENCLAW_CONFIG);
|
|
25
|
+
return join(home, 'openclaw.json');
|
|
26
|
+
}
|
|
27
|
+
function getPackageRoot() {
|
|
28
|
+
return resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
29
|
+
}
|
|
30
|
+
function readJson(p) {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(readFileSync(p, 'utf8'));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writeJson(p, data) {
|
|
39
|
+
writeFileSync(p, JSON.stringify(data, null, 2) + '\n');
|
|
40
|
+
}
|
|
41
|
+
function patchAllowList(parent, key, label, mode) {
|
|
42
|
+
if (!Array.isArray(parent[key]) || parent[key].length === 0)
|
|
43
|
+
return undefined;
|
|
44
|
+
const list = parent[key];
|
|
45
|
+
if (mode === 'add') {
|
|
46
|
+
if (!list.includes(PLUGIN_ID)) {
|
|
47
|
+
list.push(PLUGIN_ID);
|
|
48
|
+
return 'Added "' + PLUGIN_ID + '" to ' + label;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const filtered = list.filter((id) => id !== PLUGIN_ID);
|
|
53
|
+
if (filtered.length !== list.length) {
|
|
54
|
+
parent[key] = filtered;
|
|
55
|
+
return 'Removed "' + PLUGIN_ID + '" from ' + label;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function patchConfig(config, mode) {
|
|
61
|
+
const messages = [];
|
|
62
|
+
if (!config.plugins || typeof config.plugins !== 'object')
|
|
63
|
+
config.plugins = {};
|
|
64
|
+
const plugins = config.plugins;
|
|
65
|
+
const pluginAllow = patchAllowList(plugins, 'allow', 'plugins.allow', mode);
|
|
66
|
+
if (pluginAllow)
|
|
67
|
+
messages.push(pluginAllow);
|
|
68
|
+
if (!plugins.entries || typeof plugins.entries !== 'object')
|
|
69
|
+
plugins.entries = {};
|
|
70
|
+
const entries = plugins.entries;
|
|
71
|
+
if (mode === 'add') {
|
|
72
|
+
if (!entries[PLUGIN_ID]) {
|
|
73
|
+
entries[PLUGIN_ID] = { enabled: true };
|
|
74
|
+
messages.push('Added "' + PLUGIN_ID + '" to plugins.entries');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (PLUGIN_ID in entries) {
|
|
78
|
+
Reflect.deleteProperty(entries, PLUGIN_ID);
|
|
79
|
+
messages.push('Removed "' + PLUGIN_ID + '" from plugins.entries');
|
|
80
|
+
}
|
|
81
|
+
if (!config.tools || typeof config.tools !== 'object')
|
|
82
|
+
config.tools = {};
|
|
83
|
+
const tools = config.tools;
|
|
84
|
+
const toolAllow = patchAllowList(tools, 'allow', 'tools.allow', mode);
|
|
85
|
+
if (toolAllow)
|
|
86
|
+
messages.push(toolAllow);
|
|
87
|
+
return messages;
|
|
88
|
+
}
|
|
89
|
+
function install() {
|
|
90
|
+
const home = resolveOpenClawHome();
|
|
91
|
+
const configPath = resolveConfigPath(home);
|
|
92
|
+
const extDir = join(home, 'extensions', PLUGIN_ID);
|
|
93
|
+
const pkgRoot = getPackageRoot();
|
|
94
|
+
console.log('OpenClaw home: ' + home);
|
|
95
|
+
console.log('Config: ' + configPath);
|
|
96
|
+
console.log('Extensions dir: ' + extDir);
|
|
97
|
+
console.log('Package root: ' + pkgRoot);
|
|
98
|
+
console.log();
|
|
99
|
+
if (!existsSync(home)) {
|
|
100
|
+
console.error('Error: OpenClaw home not found at ' + home);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
if (!existsSync(configPath)) {
|
|
104
|
+
console.error('Error: OpenClaw config not found at ' + configPath);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
console.log('Copying plugin to extensions directory...');
|
|
108
|
+
if (existsSync(extDir))
|
|
109
|
+
rmSync(extDir, { recursive: true, force: true });
|
|
110
|
+
mkdirSync(extDir, { recursive: true });
|
|
111
|
+
for (const file of ['dist', 'openclaw.plugin.json', 'package.json']) {
|
|
112
|
+
const src = join(pkgRoot, file);
|
|
113
|
+
const dest = join(extDir, file);
|
|
114
|
+
if (existsSync(src)) {
|
|
115
|
+
cpSync(src, dest, { recursive: true });
|
|
116
|
+
console.log(' \u2713 ' + file);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const nodeModulesSrc = join(pkgRoot, 'node_modules');
|
|
120
|
+
if (existsSync(nodeModulesSrc)) {
|
|
121
|
+
cpSync(nodeModulesSrc, join(extDir, 'node_modules'), { recursive: true });
|
|
122
|
+
console.log(' \u2713 node_modules');
|
|
123
|
+
}
|
|
124
|
+
console.log();
|
|
125
|
+
console.log('Patching OpenClaw config...');
|
|
126
|
+
const config = readJson(configPath);
|
|
127
|
+
if (!config) {
|
|
128
|
+
console.error('Error: Could not parse ' + configPath);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
for (const msg of patchConfig(config, 'add'))
|
|
132
|
+
console.log(' \u2713 ' + msg);
|
|
133
|
+
writeJson(configPath, config);
|
|
134
|
+
console.log();
|
|
135
|
+
console.log('\u2705 Plugin installed successfully.');
|
|
136
|
+
console.log(' Restart the OpenClaw gateway to load the plugin.');
|
|
137
|
+
}
|
|
138
|
+
function uninstall() {
|
|
139
|
+
const home = resolveOpenClawHome();
|
|
140
|
+
const configPath = resolveConfigPath(home);
|
|
141
|
+
const extDir = join(home, 'extensions', PLUGIN_ID);
|
|
142
|
+
console.log('OpenClaw home: ' + home);
|
|
143
|
+
console.log('Config: ' + configPath);
|
|
144
|
+
console.log('Extensions dir: ' + extDir);
|
|
145
|
+
console.log();
|
|
146
|
+
if (existsSync(extDir)) {
|
|
147
|
+
rmSync(extDir, { recursive: true, force: true });
|
|
148
|
+
console.log('\u2713 Removed ' + extDir);
|
|
149
|
+
}
|
|
150
|
+
else
|
|
151
|
+
console.log(' (extensions directory not found, skipping)');
|
|
152
|
+
if (existsSync(configPath)) {
|
|
153
|
+
console.log('Patching OpenClaw config...');
|
|
154
|
+
const config = readJson(configPath);
|
|
155
|
+
if (config) {
|
|
156
|
+
for (const msg of patchConfig(config, 'remove'))
|
|
157
|
+
console.log(' \u2713 ' + msg);
|
|
158
|
+
writeJson(configPath, config);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Clean up TOOLS.md server section
|
|
162
|
+
cleanupToolsMd(home, configPath);
|
|
163
|
+
console.log();
|
|
164
|
+
console.log('\u2705 Plugin uninstalled successfully.');
|
|
165
|
+
console.log(' Restart the OpenClaw gateway to complete removal.');
|
|
166
|
+
}
|
|
167
|
+
function resolveWorkspaceDir(home, configPath) {
|
|
168
|
+
const config = readJson(configPath);
|
|
169
|
+
if (!config)
|
|
170
|
+
return null;
|
|
171
|
+
const agents = config.agents;
|
|
172
|
+
const defaults = agents?.defaults;
|
|
173
|
+
const workspace = defaults?.workspace;
|
|
174
|
+
if (workspace)
|
|
175
|
+
return resolve(workspace.replace(/^~/, homedir()));
|
|
176
|
+
return join(home, 'workspace');
|
|
177
|
+
}
|
|
178
|
+
function cleanupToolsMd(home, configPath) {
|
|
179
|
+
const workspaceDir = resolveWorkspaceDir(home, configPath);
|
|
180
|
+
if (!workspaceDir)
|
|
181
|
+
return;
|
|
182
|
+
const toolsPath = join(workspaceDir, 'TOOLS.md');
|
|
183
|
+
if (!existsSync(toolsPath))
|
|
184
|
+
return;
|
|
185
|
+
let content = readFileSync(toolsPath, 'utf8');
|
|
186
|
+
const serverRe = /^## Server\n[\s\S]*?(?=\n## |\n# |$(?![\s\S]))/m;
|
|
187
|
+
if (!serverRe.test(content))
|
|
188
|
+
return;
|
|
189
|
+
content = content.replace(serverRe, '').replace(/\n{3,}/g, '\n\n');
|
|
190
|
+
content = content.trim() + '\n';
|
|
191
|
+
writeFileSync(toolsPath, content);
|
|
192
|
+
console.log('\u2713 Cleaned up TOOLS.md (removed Server section)');
|
|
193
|
+
}
|
|
194
|
+
const command = process.argv[2];
|
|
195
|
+
switch (command) {
|
|
196
|
+
case 'install':
|
|
197
|
+
install();
|
|
198
|
+
break;
|
|
199
|
+
case 'uninstall':
|
|
200
|
+
uninstall();
|
|
201
|
+
break;
|
|
202
|
+
default:
|
|
203
|
+
console.log('@karmaniverous/jeeves-server-openclaw \u2014 OpenClaw plugin installer');
|
|
204
|
+
console.log();
|
|
205
|
+
console.log('Usage:');
|
|
206
|
+
console.log(' npx @karmaniverous/jeeves-server-openclaw install Install plugin');
|
|
207
|
+
console.log(' npx @karmaniverous/jeeves-server-openclaw uninstall Remove plugin');
|
|
208
|
+
console.log();
|
|
209
|
+
console.log('Environment variables:');
|
|
210
|
+
console.log(' OPENCLAW_CONFIG Path to openclaw.json (overrides all)');
|
|
211
|
+
console.log(' OPENCLAW_HOME Path to .openclaw directory');
|
|
212
|
+
if (command &&
|
|
213
|
+
command !== 'help' &&
|
|
214
|
+
command !== '--help' &&
|
|
215
|
+
command !== '-h') {
|
|
216
|
+
console.error('\nUnknown command: ' + command);
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export { patchConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared types and utility functions for the OpenClaw plugin tool registrations.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_API_URL = 'http://127.0.0.1:1934';
|
|
9
|
+
const PLUGIN_ID = 'jeeves-server-openclaw';
|
|
10
|
+
/** Extract plugin config from the API object */
|
|
11
|
+
function getPluginConfig(api) {
|
|
12
|
+
return api.config?.plugins?.entries?.[PLUGIN_ID]?.config;
|
|
13
|
+
}
|
|
14
|
+
/** Resolve the server API base URL from plugin config. */
|
|
15
|
+
function getApiUrl(api) {
|
|
16
|
+
const url = getPluginConfig(api)?.apiUrl;
|
|
17
|
+
return typeof url === 'string' ? url : DEFAULT_API_URL;
|
|
18
|
+
}
|
|
19
|
+
/** Resolve the plugin key seed from plugin config. */
|
|
20
|
+
function getPluginKey(api) {
|
|
21
|
+
const key = getPluginConfig(api)?.pluginKey;
|
|
22
|
+
return typeof key === 'string' ? key : undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Derive HMAC key from seed. */
|
|
25
|
+
function deriveKey(seed) {
|
|
26
|
+
return createHmac('sha256', seed).update('insider').digest('hex');
|
|
27
|
+
}
|
|
28
|
+
/** Append auth key query param to a URL. */
|
|
29
|
+
function withAuth(url, keySeed) {
|
|
30
|
+
if (!keySeed)
|
|
31
|
+
return url;
|
|
32
|
+
const derived = deriveKey(keySeed);
|
|
33
|
+
const sep = url.includes('?') ? '&' : '?';
|
|
34
|
+
return url + sep + 'key=' + derived;
|
|
35
|
+
}
|
|
36
|
+
/** Format a successful tool result. */
|
|
37
|
+
function ok(data) {
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Format an error tool result. */
|
|
43
|
+
function fail(error) {
|
|
44
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: 'Error: ' + message }],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Format a connection error with actionable guidance. */
|
|
51
|
+
function connectionFail(error, baseUrl) {
|
|
52
|
+
const cause = error instanceof Error ? error.cause : undefined;
|
|
53
|
+
const code = cause && typeof cause === 'object' && 'code' in cause
|
|
54
|
+
? String(cause.code)
|
|
55
|
+
: '';
|
|
56
|
+
const isConnectionError = code === 'ECONNREFUSED' || code === 'ENOTFOUND' || code === 'ETIMEDOUT';
|
|
57
|
+
if (isConnectionError) {
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: [
|
|
63
|
+
'Server not reachable at ' + baseUrl + '.',
|
|
64
|
+
'Either start the jeeves-server service, or if it runs on a different port,',
|
|
65
|
+
'set plugins.entries.jeeves-server-openclaw.config.apiUrl in openclaw.json.',
|
|
66
|
+
].join('\n'),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return fail(error);
|
|
73
|
+
}
|
|
74
|
+
/** Fetch JSON from a URL, throwing on non-OK responses. */
|
|
75
|
+
async function fetchJson(url, init) {
|
|
76
|
+
const res = await fetch(url, init);
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
throw new Error('HTTP ' + String(res.status) + ': ' + (await res.text()));
|
|
79
|
+
}
|
|
80
|
+
return res.json();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Server tool registrations (server_* tools) for the OpenClaw plugin.
|
|
85
|
+
*/
|
|
86
|
+
/** Normalize a browse path param: strip leading slash. */
|
|
87
|
+
function normalizePath(params) {
|
|
88
|
+
return String(params.path).replace(/^\//, '');
|
|
89
|
+
}
|
|
90
|
+
/** Register a single API tool with standard try/catch + ok/connectionFail. */
|
|
91
|
+
function registerApiTool(api, baseUrl, keySeed, config) {
|
|
92
|
+
api.registerTool({
|
|
93
|
+
name: config.name,
|
|
94
|
+
description: config.description,
|
|
95
|
+
parameters: config.parameters,
|
|
96
|
+
execute: async (_id, params) => {
|
|
97
|
+
try {
|
|
98
|
+
const [endpoint, method, body] = config.buildRequest(params);
|
|
99
|
+
const url = withAuth(baseUrl + endpoint, keySeed);
|
|
100
|
+
const init = {};
|
|
101
|
+
if (method)
|
|
102
|
+
init.method = method;
|
|
103
|
+
if (body !== undefined) {
|
|
104
|
+
init.method = method ?? 'POST';
|
|
105
|
+
init.headers = { 'Content-Type': 'application/json' };
|
|
106
|
+
init.body = JSON.stringify(body);
|
|
107
|
+
}
|
|
108
|
+
const data = await fetchJson(url, Object.keys(init).length > 0 ? init : undefined);
|
|
109
|
+
return ok(data);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return connectionFail(error, baseUrl);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
}, { optional: true });
|
|
116
|
+
}
|
|
117
|
+
/** Register all server_* tools with the OpenClaw plugin API. */
|
|
118
|
+
function registerServerTools(api, baseUrl) {
|
|
119
|
+
const keySeed = getPluginKey(api);
|
|
120
|
+
const tools = [
|
|
121
|
+
{
|
|
122
|
+
name: 'server_status',
|
|
123
|
+
description: 'Get jeeves-server health: version, uptime, port, Chrome availability, export formats, connected services.',
|
|
124
|
+
parameters: { type: 'object', properties: {} },
|
|
125
|
+
buildRequest: () => ['/api/status'],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'server_link_info',
|
|
129
|
+
description: 'Query available link types for a path (exists, page URL, raw URL, export links for PDF/DOCX/SVG/PNG).',
|
|
130
|
+
parameters: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
path: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: 'Browse path (e.g. "j/domains/projects/readme.md")',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
required: ['path'],
|
|
139
|
+
},
|
|
140
|
+
buildRequest: (params) => {
|
|
141
|
+
const p = normalizePath(params);
|
|
142
|
+
return ['/api/link-info/' + p];
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'server_browse',
|
|
147
|
+
description: 'Get file or directory metadata. For files: size, mtime, content type, rendered HTML availability. For directories: listing of entries.',
|
|
148
|
+
parameters: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {
|
|
151
|
+
path: {
|
|
152
|
+
type: 'string',
|
|
153
|
+
description: 'Browse path (e.g. "j/domains/projects")',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
required: ['path'],
|
|
157
|
+
},
|
|
158
|
+
buildRequest: (params) => {
|
|
159
|
+
const p = normalizePath(params);
|
|
160
|
+
return ['/api/directory/' + p];
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'server_share',
|
|
165
|
+
description: 'Generate a share link for a path. Returns an HMAC-signed URL with optional expiry and directory depth.',
|
|
166
|
+
parameters: {
|
|
167
|
+
type: 'object',
|
|
168
|
+
properties: {
|
|
169
|
+
path: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
description: 'Browse path to share',
|
|
172
|
+
},
|
|
173
|
+
expiryDays: {
|
|
174
|
+
type: 'number',
|
|
175
|
+
description: 'Link expiry in days (default: 30)',
|
|
176
|
+
},
|
|
177
|
+
depth: {
|
|
178
|
+
type: 'number',
|
|
179
|
+
description: 'Directory depth for deep shares (0 = file only)',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
required: ['path'],
|
|
183
|
+
},
|
|
184
|
+
buildRequest: (params) => {
|
|
185
|
+
const p = normalizePath(params);
|
|
186
|
+
const qs = [];
|
|
187
|
+
if (params.expiryDays !== undefined)
|
|
188
|
+
qs.push('exp=' + String(params.expiryDays));
|
|
189
|
+
if (params.depth !== undefined)
|
|
190
|
+
qs.push('d=' + String(params.depth));
|
|
191
|
+
const query = qs.length > 0 ? '?' + qs.join('&') : '';
|
|
192
|
+
return ['/api/share/' + p + query];
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'server_export',
|
|
197
|
+
description: 'Trigger an export of a file or directory. Returns a download URL. Supported formats depend on file type and server capabilities (Chrome for PDF).',
|
|
198
|
+
parameters: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
path: {
|
|
202
|
+
type: 'string',
|
|
203
|
+
description: 'Browse path to export',
|
|
204
|
+
},
|
|
205
|
+
format: {
|
|
206
|
+
type: 'string',
|
|
207
|
+
description: 'Export format: pdf, docx, svg, png, zip',
|
|
208
|
+
enum: ['pdf', 'docx', 'svg', 'png', 'zip'],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
required: ['path', 'format'],
|
|
212
|
+
},
|
|
213
|
+
buildRequest: (params) => {
|
|
214
|
+
const p = normalizePath(params);
|
|
215
|
+
const fmt = String(params.format);
|
|
216
|
+
return ['/export/' + p + '.' + fmt];
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'server_event_status',
|
|
221
|
+
description: 'Query event gateway status: active schemas, recent event log entries, and event counts.',
|
|
222
|
+
parameters: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
limit: {
|
|
226
|
+
type: 'number',
|
|
227
|
+
description: 'Maximum number of recent events to return (default: 20)',
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
buildRequest: (params) => {
|
|
232
|
+
const limit = params.limit ? String(params.limit) : '20';
|
|
233
|
+
return ['/api/status?events=' + limit];
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
for (const tool of tools) {
|
|
238
|
+
registerApiTool(api, baseUrl, keySeed, tool);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Generates the Server menu string for TOOLS.md injection.
|
|
244
|
+
*/
|
|
245
|
+
/**
|
|
246
|
+
* Fetch server status and generate a Markdown menu string.
|
|
247
|
+
*/
|
|
248
|
+
async function generateServerMenu(apiUrl) {
|
|
249
|
+
let status;
|
|
250
|
+
try {
|
|
251
|
+
status = (await fetchJson(apiUrl + '/api/status', {
|
|
252
|
+
signal: AbortSignal.timeout(5000),
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return `> **ACTION REQUIRED: jeeves-server is unreachable.**
|
|
257
|
+
> The server API at ${apiUrl} is down or not configured.
|
|
258
|
+
>
|
|
259
|
+
> **Troubleshooting:**
|
|
260
|
+
> - Check if the JeevesServer service is running
|
|
261
|
+
> - Verify the apiUrl in plugins.entries.jeeves-server-openclaw.config
|
|
262
|
+
> - Try: \`jeeves-server service start\``;
|
|
263
|
+
}
|
|
264
|
+
const lines = [
|
|
265
|
+
`jeeves-server v${status.version ?? 'unknown'} running on port ${String(status.port ?? 'unknown')}.`,
|
|
266
|
+
'',
|
|
267
|
+
];
|
|
268
|
+
// Export formats
|
|
269
|
+
if (status.exportFormats && status.exportFormats.length > 0) {
|
|
270
|
+
lines.push('### Export Formats');
|
|
271
|
+
lines.push('Available: ' + status.exportFormats.join(', '));
|
|
272
|
+
if (!status.chrome) {
|
|
273
|
+
lines.push('> **Note:** Chrome not detected — PDF export unavailable.');
|
|
274
|
+
}
|
|
275
|
+
lines.push('');
|
|
276
|
+
}
|
|
277
|
+
// Diagram support
|
|
278
|
+
if (status.diagrams && status.diagrams.length > 0) {
|
|
279
|
+
lines.push('### Diagram Support');
|
|
280
|
+
lines.push('Supported languages: ' + status.diagrams.join(', '));
|
|
281
|
+
lines.push('');
|
|
282
|
+
}
|
|
283
|
+
// Connected services
|
|
284
|
+
if (status.services) {
|
|
285
|
+
lines.push('### Connected Services');
|
|
286
|
+
for (const [name, svc] of Object.entries(status.services)) {
|
|
287
|
+
const icon = svc.reachable ? '\u2705' : '\u274c';
|
|
288
|
+
lines.push(`* ${icon} **${name}**: ${svc.url}`);
|
|
289
|
+
}
|
|
290
|
+
lines.push('');
|
|
291
|
+
}
|
|
292
|
+
// Event gateway
|
|
293
|
+
if (status.events && status.events.length > 0) {
|
|
294
|
+
lines.push('### Event Gateway');
|
|
295
|
+
lines.push('Active schemas:');
|
|
296
|
+
for (const evt of status.events) {
|
|
297
|
+
lines.push('* **' +
|
|
298
|
+
evt.name +
|
|
299
|
+
'**' +
|
|
300
|
+
(evt.pattern ? ' — pattern: `' + evt.pattern + '`' : ''));
|
|
301
|
+
}
|
|
302
|
+
lines.push('');
|
|
303
|
+
}
|
|
304
|
+
// Insider count
|
|
305
|
+
if (status.insiderCount !== undefined) {
|
|
306
|
+
lines.push('### Access');
|
|
307
|
+
lines.push(String(status.insiderCount) + ' insider(s) configured.');
|
|
308
|
+
lines.push('');
|
|
309
|
+
}
|
|
310
|
+
// Sharing guidance
|
|
311
|
+
lines.push('### Sharing');
|
|
312
|
+
lines.push('Use `server_share` to generate links. Insiders authenticate via Google; outsiders use HMAC share links.');
|
|
313
|
+
lines.push('Use `server_link_info` to check available export formats for a path before exporting.');
|
|
314
|
+
return lines.join('\n');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Writes the Server menu section directly to TOOLS.md on disk.
|
|
319
|
+
*/
|
|
320
|
+
const REFRESH_INTERVAL_MS = 60_000;
|
|
321
|
+
let intervalHandle = null;
|
|
322
|
+
let lastWrittenMenu = '';
|
|
323
|
+
/**
|
|
324
|
+
* Resolve the workspace TOOLS.md path.
|
|
325
|
+
*/
|
|
326
|
+
function resolveToolsPath(api) {
|
|
327
|
+
if (api.resolvePath) {
|
|
328
|
+
return api.resolvePath('TOOLS.md');
|
|
329
|
+
}
|
|
330
|
+
return resolve(process.cwd(), 'TOOLS.md');
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Upsert the server section in TOOLS.md content.
|
|
334
|
+
*/
|
|
335
|
+
function upsertServerContent(existing, serverMenu) {
|
|
336
|
+
const section = '## Server\n\n' + serverMenu;
|
|
337
|
+
// Replace existing server section
|
|
338
|
+
const re = /^## Server\n[\s\S]*?(?=\n## |\n# |$(?![\s\S]))/m;
|
|
339
|
+
if (re.test(existing)) {
|
|
340
|
+
return existing.replace(re, section);
|
|
341
|
+
}
|
|
342
|
+
// No existing section — insert under platform tools H1
|
|
343
|
+
const platformH1 = '# Jeeves Platform Tools';
|
|
344
|
+
if (existing.includes(platformH1)) {
|
|
345
|
+
// Find end of H1 line, insert after any existing ## sections
|
|
346
|
+
// Place after ## Watcher if it exists, otherwise after H1
|
|
347
|
+
const watcherEnd = existing.match(/^## Watcher\n[\s\S]*?(?=\n## |\n# |$(?![\s\S]))/m);
|
|
348
|
+
if (watcherEnd) {
|
|
349
|
+
const idx = existing.indexOf(watcherEnd[0]) + watcherEnd[0].length;
|
|
350
|
+
return existing.slice(0, idx) + '\n\n' + section + existing.slice(idx);
|
|
351
|
+
}
|
|
352
|
+
const idx = existing.indexOf(platformH1) + platformH1.length;
|
|
353
|
+
return existing.slice(0, idx) + '\n\n' + section + existing.slice(idx);
|
|
354
|
+
}
|
|
355
|
+
// No platform header — prepend
|
|
356
|
+
const trimmed = existing.trim();
|
|
357
|
+
if (trimmed.length === 0) {
|
|
358
|
+
return platformH1 + '\n\n' + section + '\n';
|
|
359
|
+
}
|
|
360
|
+
return platformH1 + '\n\n' + section + '\n\n' + trimmed + '\n';
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Fetch the current server menu and write it to TOOLS.md if changed.
|
|
364
|
+
*/
|
|
365
|
+
async function refreshToolsMd(api) {
|
|
366
|
+
const apiUrl = getApiUrl(api);
|
|
367
|
+
const menu = await generateServerMenu(apiUrl);
|
|
368
|
+
if (menu === lastWrittenMenu)
|
|
369
|
+
return false;
|
|
370
|
+
const toolsPath = resolveToolsPath(api);
|
|
371
|
+
let current = '';
|
|
372
|
+
try {
|
|
373
|
+
current = await readFile(toolsPath, 'utf8');
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// File doesn't exist yet
|
|
377
|
+
}
|
|
378
|
+
const updated = upsertServerContent(current, menu);
|
|
379
|
+
if (updated !== current) {
|
|
380
|
+
await writeFile(toolsPath, updated, 'utf8');
|
|
381
|
+
lastWrittenMenu = menu;
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
lastWrittenMenu = menu;
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Start the periodic TOOLS.md writer.
|
|
389
|
+
*/
|
|
390
|
+
function startToolsWriter(api) {
|
|
391
|
+
refreshToolsMd(api).catch((err) => {
|
|
392
|
+
console.error('[jeeves-server] Failed to write TOOLS.md:', err);
|
|
393
|
+
});
|
|
394
|
+
if (intervalHandle)
|
|
395
|
+
clearInterval(intervalHandle);
|
|
396
|
+
intervalHandle = setInterval(() => {
|
|
397
|
+
refreshToolsMd(api).catch((err) => {
|
|
398
|
+
console.error('[jeeves-server] Failed to refresh TOOLS.md:', err);
|
|
399
|
+
});
|
|
400
|
+
}, REFRESH_INTERVAL_MS);
|
|
401
|
+
if (typeof intervalHandle === 'object' && 'unref' in intervalHandle) {
|
|
402
|
+
intervalHandle.unref();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* OpenClaw plugin entry point. Registers all jeeves-server tools.
|
|
408
|
+
*/
|
|
409
|
+
/** Register all jeeves-server tools with the OpenClaw plugin API. */
|
|
410
|
+
function register(api) {
|
|
411
|
+
const baseUrl = getApiUrl(api);
|
|
412
|
+
registerServerTools(api, baseUrl);
|
|
413
|
+
startToolsWriter(api);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export { register as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Jeeves Server Skill
|
|
2
|
+
|
|
3
|
+
Operate and interact with a jeeves-server deployment. Use for file browsing, document sharing, export, link generation, event gateway queries, and server diagnostics.
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
| Tool | Purpose |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| `server_status` | Server health: version, uptime, Chrome availability, export formats, connected services |
|
|
10
|
+
| `server_browse` | Get file/directory metadata and listings for a browse path |
|
|
11
|
+
| `server_link_info` | Query available link types for a path (page URL, raw URL, export links) |
|
|
12
|
+
| `server_share` | Generate share links with optional expiry and directory depth |
|
|
13
|
+
| `server_export` | Trigger export (PDF, DOCX, SVG, PNG, ZIP) and get download URL |
|
|
14
|
+
| `server_event_status` | Query event gateway status, active schemas, and recent event log |
|
|
15
|
+
|
|
16
|
+
## Browse Paths
|
|
17
|
+
|
|
18
|
+
All paths use the jeeves-server browse path format: `{drive}/{path}` (e.g., `j/domains/projects/readme.md`).
|
|
19
|
+
|
|
20
|
+
To convert a Windows file path to a browse path:
|
|
21
|
+
- `J:\domains\projects\readme.md` → `j/domains/projects/readme.md`
|
|
22
|
+
- Strip the colon, lowercase the drive letter, use forward slashes
|
|
23
|
+
|
|
24
|
+
## Sharing
|
|
25
|
+
|
|
26
|
+
- **Insiders** authenticate via Google OAuth — bare URLs work for them
|
|
27
|
+
- **Outsiders** need HMAC share links — use `server_share` to generate them
|
|
28
|
+
- Share links have configurable expiry (default 30 days)
|
|
29
|
+
- Directory shares support depth control for recursive access
|
|
30
|
+
|
|
31
|
+
## Export
|
|
32
|
+
|
|
33
|
+
Available formats depend on file type and server capabilities:
|
|
34
|
+
- **Markdown files:** PDF (requires Chrome), DOCX
|
|
35
|
+
- **Mermaid diagrams:** SVG, PNG, PDF
|
|
36
|
+
- **PlantUML diagrams:** Formats depend on server configuration
|
|
37
|
+
- **Directories:** ZIP (insider-only)
|
|
38
|
+
|
|
39
|
+
Use `server_link_info` first to check which formats are available for a path.
|
|
40
|
+
|
|
41
|
+
## Diagnostics
|
|
42
|
+
|
|
43
|
+
Run `server_status` to check:
|
|
44
|
+
- Server version and uptime
|
|
45
|
+
- Chrome availability (required for PDF export)
|
|
46
|
+
- Connected services (watcher, runner) and their reachability
|
|
47
|
+
- Available export formats and diagram languages
|
|
48
|
+
|
|
49
|
+
## Bootstrap: Full Stack Setup
|
|
50
|
+
|
|
51
|
+
### Prerequisites
|
|
52
|
+
|
|
53
|
+
- **Node.js 20+** and npm
|
|
54
|
+
- **Java 8+** (optional, for local PlantUML rendering)
|
|
55
|
+
- **Chrome/Chromium** (optional, for PDF export)
|
|
56
|
+
- **NSSM** (Windows) or **systemd** (Linux) for service management
|
|
57
|
+
- **Caddy** (recommended) or nginx for reverse proxy with automatic TLS
|
|
58
|
+
|
|
59
|
+
### 1. Install jeeves-server
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install -g @karmaniverous/jeeves-server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 2. Create config
|
|
66
|
+
|
|
67
|
+
Create `jeeves-server.config.json` in the server's working directory:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"port": 1934,
|
|
72
|
+
"roots": {
|
|
73
|
+
"data": "/path/to/data"
|
|
74
|
+
},
|
|
75
|
+
"keys": {
|
|
76
|
+
"_internal": "random-hex-seed-for-puppeteer",
|
|
77
|
+
"_plugin": "random-hex-seed-for-openclaw-plugin"
|
|
78
|
+
},
|
|
79
|
+
"insiders": [
|
|
80
|
+
{ "email": "you@example.com" }
|
|
81
|
+
],
|
|
82
|
+
"google": {
|
|
83
|
+
"clientId": "${GOOGLE_CLIENT_ID}",
|
|
84
|
+
"clientSecret": "${GOOGLE_CLIENT_SECRET}"
|
|
85
|
+
},
|
|
86
|
+
"sessionSecret": "${SESSION_SECRET}",
|
|
87
|
+
"watcherUrl": "http://127.0.0.1:1936"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Validate config
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
jeeves-server config validate
|
|
95
|
+
jeeves-server config show
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 4. Register as system service
|
|
99
|
+
|
|
100
|
+
**Windows (NSSM):**
|
|
101
|
+
```bash
|
|
102
|
+
jeeves-server service install
|
|
103
|
+
jeeves-server service start
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Linux (systemd):**
|
|
107
|
+
```bash
|
|
108
|
+
sudo jeeves-server service install
|
|
109
|
+
sudo jeeves-server service start
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 5. Configure Caddy reverse proxy
|
|
113
|
+
|
|
114
|
+
Add to your Caddyfile:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
your-domain.com {
|
|
118
|
+
reverse_proxy localhost:1934
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Caddy handles TLS certificate provisioning automatically. Ensure DNS A/AAAA records point to your server.
|
|
123
|
+
|
|
124
|
+
### 6. Install OpenClaw plugin
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npx @karmaniverous/jeeves-server-openclaw install
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Configure the plugin in `openclaw.json` with `apiUrl` and `pluginKey` (matching the `_plugin` key seed from server config). Restart the OpenClaw gateway.
|
|
131
|
+
|
|
132
|
+
## Troubleshooting
|
|
133
|
+
|
|
134
|
+
If the server is unreachable:
|
|
135
|
+
1. Is the service running? → `jeeves-server service start`
|
|
136
|
+
2. Is the apiUrl correct? → Default: `http://127.0.0.1:1934`
|
|
137
|
+
3. Is the `_plugin` key configured in both server config and plugin config?
|
|
138
|
+
4. Is Caddy proxying to the correct port? → Check `Caddyfile`
|
|
139
|
+
5. Is the firewall allowing traffic on port 1934? → Only needed for local access; Caddy handles external traffic
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI for installing/uninstalling the jeeves-server OpenClaw plugin.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx \@karmaniverous/jeeves-server-openclaw install
|
|
6
|
+
* npx \@karmaniverous/jeeves-server-openclaw uninstall
|
|
7
|
+
*/
|
|
8
|
+
export declare function patchConfig(config: Record<string, unknown>, mode: 'add' | 'remove'): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and utility functions for the OpenClaw plugin tool registrations.
|
|
3
|
+
*/
|
|
4
|
+
/** Minimal OpenClaw plugin API surface used for tool registration. */
|
|
5
|
+
export interface PluginApi {
|
|
6
|
+
config?: {
|
|
7
|
+
plugins?: {
|
|
8
|
+
entries?: Record<string, {
|
|
9
|
+
config?: Record<string, unknown>;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
resolvePath?: (input: string) => string;
|
|
14
|
+
registerTool(tool: {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
parameters: Record<string, unknown>;
|
|
18
|
+
execute: (id: string, params: Record<string, unknown>) => Promise<ToolResult>;
|
|
19
|
+
}, options?: {
|
|
20
|
+
optional?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
}
|
|
23
|
+
/** Result shape returned by each tool execution. */
|
|
24
|
+
export interface ToolResult {
|
|
25
|
+
content: Array<{
|
|
26
|
+
type: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}>;
|
|
29
|
+
isError?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** Resolve the server API base URL from plugin config. */
|
|
32
|
+
export declare function getApiUrl(api: PluginApi): string;
|
|
33
|
+
/** Resolve the plugin key seed from plugin config. */
|
|
34
|
+
export declare function getPluginKey(api: PluginApi): string | undefined;
|
|
35
|
+
/** Derive HMAC key from seed. */
|
|
36
|
+
export declare function deriveKey(seed: string): string;
|
|
37
|
+
/** Append auth key query param to a URL. */
|
|
38
|
+
export declare function withAuth(url: string, keySeed: string | undefined): string;
|
|
39
|
+
/** Format a successful tool result. */
|
|
40
|
+
export declare function ok(data: unknown): ToolResult;
|
|
41
|
+
/** Format an error tool result. */
|
|
42
|
+
export declare function fail(error: unknown): ToolResult;
|
|
43
|
+
/** Format a connection error with actionable guidance. */
|
|
44
|
+
export declare function connectionFail(error: unknown, baseUrl: string): ToolResult;
|
|
45
|
+
/** Fetch JSON from a URL, throwing on non-OK responses. */
|
|
46
|
+
export declare function fetchJson(url: string, init?: RequestInit): Promise<unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server tool registrations (server_* tools) for the OpenClaw plugin.
|
|
3
|
+
*/
|
|
4
|
+
import { type PluginApi } from './helpers.js';
|
|
5
|
+
/** Register all server_* tools with the OpenClaw plugin API. */
|
|
6
|
+
export declare function registerServerTools(api: PluginApi, baseUrl: string): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "jeeves-server-openclaw",
|
|
3
|
+
"name": "Jeeves Server",
|
|
4
|
+
"description": "File browsing, document sharing, export, and event gateway tools for jeeves-server.",
|
|
5
|
+
"version": "0.1.0-0",
|
|
6
|
+
"skills": [
|
|
7
|
+
"dist/skills/jeeves-server"
|
|
8
|
+
],
|
|
9
|
+
"configSchema": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"properties": {
|
|
13
|
+
"apiUrl": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "jeeves-server API base URL",
|
|
16
|
+
"default": "http://127.0.0.1:1934"
|
|
17
|
+
},
|
|
18
|
+
"pluginKey": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Server _plugin key seed (for authenticated API calls)"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"uiHints": {
|
|
25
|
+
"apiUrl": {
|
|
26
|
+
"label": "Server API URL",
|
|
27
|
+
"placeholder": "http://127.0.0.1:1934"
|
|
28
|
+
},
|
|
29
|
+
"pluginKey": {
|
|
30
|
+
"label": "Plugin Key Seed",
|
|
31
|
+
"placeholder": "hex string from server config keys._plugin"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@karmaniverous/jeeves-server-openclaw",
|
|
3
|
+
"version": "0.1.0-0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build:plugin": "rimraf dist && cross-env NO_COLOR=1 rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
|
|
8
|
+
"build:skills": "tsx scripts/build-skills.ts",
|
|
9
|
+
"build": "npm run build:plugin && npm run build:skills",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"lint:fix": "eslint --fix .",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"typecheck": "tsc",
|
|
14
|
+
"changelog": "auto-changelog",
|
|
15
|
+
"knip": "knip",
|
|
16
|
+
"release": "dotenvx run -f .env.local -- release-it",
|
|
17
|
+
"release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@dotenvx/dotenvx": "^1.54.1",
|
|
21
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
22
|
+
"auto-changelog": "^2.5.0",
|
|
23
|
+
"cross-env": "^10.1.0",
|
|
24
|
+
"release-it": "^19.2.4",
|
|
25
|
+
"rollup": "^4.59.0",
|
|
26
|
+
"tslib": "^2.8.1",
|
|
27
|
+
"vitest": "^4.0.18"
|
|
28
|
+
},
|
|
29
|
+
"author": "Jason Williscroft",
|
|
30
|
+
"description": "OpenClaw plugin for jeeves-server — file browsing, sharing, export, and event gateway tools",
|
|
31
|
+
"license": "BSD-3-Clause",
|
|
32
|
+
"bin": {
|
|
33
|
+
"jeeves-server-openclaw": "./dist/cli.js"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"default": "./dist/index.js"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"types": "dist/index.d.ts",
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"openclaw.plugin.json"
|
|
47
|
+
],
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/karmaniverous/jeeves-server.git",
|
|
54
|
+
"directory": "packages/openclaw"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/karmaniverous/jeeves-server/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/karmaniverous/jeeves-server#readme",
|
|
60
|
+
"keywords": [
|
|
61
|
+
"openclaw",
|
|
62
|
+
"plugin",
|
|
63
|
+
"jeeves-server"
|
|
64
|
+
],
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=20"
|
|
67
|
+
},
|
|
68
|
+
"openclaw": {
|
|
69
|
+
"extensions": [
|
|
70
|
+
"./dist/index.js"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"release-it": {
|
|
74
|
+
"git": {
|
|
75
|
+
"changelog": "npx auto-changelog --unreleased-only --stdout --template https://raw.githubusercontent.com/release-it/release-it/main/templates/changelog-compact.hbs",
|
|
76
|
+
"commitMessage": "chore: release @karmaniverous/jeeves-server-openclaw v${version}",
|
|
77
|
+
"tagName": "openclaw/${version}",
|
|
78
|
+
"requireBranch": "main"
|
|
79
|
+
},
|
|
80
|
+
"github": {
|
|
81
|
+
"release": true
|
|
82
|
+
},
|
|
83
|
+
"hooks": {
|
|
84
|
+
"after:bump": [
|
|
85
|
+
"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')\""
|
|
86
|
+
],
|
|
87
|
+
"after:init": [
|
|
88
|
+
"npm run lint",
|
|
89
|
+
"npm run typecheck",
|
|
90
|
+
"npm run test",
|
|
91
|
+
"npm run build"
|
|
92
|
+
],
|
|
93
|
+
"before:npm:release": [
|
|
94
|
+
"npx auto-changelog -p",
|
|
95
|
+
"git add -A"
|
|
96
|
+
],
|
|
97
|
+
"after:release": [
|
|
98
|
+
"git switch -c release/openclaw/${version}",
|
|
99
|
+
"git push -u origin release/openclaw/${version}",
|
|
100
|
+
"git switch ${branchName}"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"npm": {
|
|
104
|
+
"publish": true
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|