@karmaniverous/jeeves-watcher-openclaw 0.16.1 → 0.17.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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module plugin/apiTool
3
- * Generic HTTP-backed watcher tool registration: config shape, request helpers, and ok/connectionFail wrapping.
3
+ * Generic HTTP-backed watcher tool registration: config shape, request helpers, and ok/connectionFail wrapping. Requests carry the bearer key (if configured) via `requestJson`.
4
4
  */
5
5
  import { type PluginApi, type ToolDescriptor } from '@karmaniverous/jeeves';
6
6
  /**
@@ -29,8 +29,16 @@ export interface ApiToolConfig {
29
29
  /** Build the request: return [endpoint, body?]. No body = GET. */
30
30
  buildRequest: (params: Record<string, unknown>) => [string, unknown?];
31
31
  }
32
- /** Register a single API tool with standard try/catch + ok/connectionFail. */
33
- export declare function registerApiTool(api: PluginApi, baseUrl: string, config: ApiToolConfig): void;
32
+ /** API base URL, or a resolver evaluated on every call. */
33
+ export type BaseUrlSource = string | (() => string);
34
+ /**
35
+ * Register a single API tool with standard try/catch + ok/connectionFail.
36
+ *
37
+ * @remarks
38
+ * The bearer key is resolved from `api` ({@link getApiKey}) on every call,
39
+ * so a key set after registration takes effect without re-registering.
40
+ */
41
+ export declare function registerApiTool(api: PluginApi, baseUrlSource: BaseUrlSource, config: ApiToolConfig): void;
34
42
  /** Build a query string from defined params. */
35
43
  export declare function buildQuery(params: Record<string, unknown>, keys: string[]): string;
36
44
  /** Pick defined keys from params into a body object. */
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @module plugin/auth.test
3
+ * Plugin-level bearer-key tests through the real entry point: every HTTP tool sends the key when configured and none when unset; the key never reaches logs or tool results.
4
+ */
5
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @module plugin/configTools
3
+ * Watcher-owned `watcher_config` and `watcher_config_apply` tools: same names, parameters and requests as the core toolset's, but sent through the plugin HTTP helper so they carry the bearer key.
4
+ *
5
+ * @remarks
6
+ * Core's `createPluginToolset` cannot attach request headers, so its two
7
+ * authenticated HTTP tools are replaced by these (see {@link CORE_TOOLS_REPLACED}).
8
+ * `watcher_status` stays with core: `GET /status` is always open.
9
+ */
10
+ import type { ApiToolConfig } from './apiTool.js';
11
+ /** Core toolset tools that this module replaces. */
12
+ export declare const CORE_TOOLS_REPLACED: ReadonlySet<string>;
13
+ /** `watcher_config` and `watcher_config_apply`, as API tool configs. */
14
+ export declare const configToolConfigs: ApiToolConfig[];
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @module plugin/configTools.test
3
+ * watcher_config and watcher_config_apply build the same requests as the core tools: GET /config (optional URL-encoded JSONPath) and POST /config/apply with the config wrapped as `patch`; a missing config is rejected before any request.
4
+ */
5
+ export {};
@@ -2,7 +2,7 @@
2
2
  * @module plugin/constants
3
3
  * Shared constants for the OpenClaw plugin package.
4
4
  */
5
- export { COMPONENT_NAME, DEFAULT_PORT, PLUGIN_PACKAGE, SERVICE_PACKAGE, } from '@karmaniverous/jeeves-watcher-core';
5
+ export { API_KEY_ENV_VAR, COMPONENT_NAME, DEFAULT_PORT, PLUGIN_PACKAGE, SERVICE_PACKAGE, } from '@karmaniverous/jeeves-watcher-core';
6
6
  /** Plugin identifier used in OpenClaw config (`plugins.entries.<id>`). */
7
7
  export declare const PLUGIN_ID = "jeeves-watcher-openclaw";
8
8
  /** Default watcher API base URL. */
@@ -2,9 +2,10 @@
2
2
  * Watcher-specific convenience wrappers over `@karmaniverous/jeeves` core SDK.
3
3
  *
4
4
  * @remarks
5
- * Only watcher-specific resolution logic lives here. Core SDK types and
6
- * utilities (`PluginApi`, `ToolResult`, `ok`, `connectionFail`, `fetchJson`,
7
- * `postJson`) should be imported directly from `@karmaniverous/jeeves`.
5
+ * Only watcher-specific resolution logic (API URL, API key, config root)
6
+ * lives here. Core SDK types and utilities (`PluginApi`, `ToolResult`, `ok`,
7
+ * `connectionFail`) should be imported directly from `@karmaniverous/jeeves`;
8
+ * watcher API requests go through `requestJson` (`./http.js`).
8
9
  *
9
10
  * @module plugin/helpers
10
11
  */
@@ -18,6 +19,17 @@ import { type PluginApi } from '@karmaniverous/jeeves';
18
19
  * `DEFAULT_API_URL`. Safe to call per tool invocation.
19
20
  */
20
21
  export declare function getApiUrl(api: PluginApi): string;
22
+ /**
23
+ * Resolve the watcher API bearer key, if configured.
24
+ *
25
+ * @remarks
26
+ * Resolution order: plugin-scoped config (`api.pluginConfig.apiKey`), then
27
+ * `plugins.entries.<id>.config.apiKey`, then `JEEVES_WATCHER_API_KEY`. Blank
28
+ * values count as unset. Resolved per request; never logged.
29
+ *
30
+ * @returns The key, or `undefined` when unset (requests carry no header).
31
+ */
32
+ export declare function getApiKey(api: PluginApi): string | undefined;
21
33
  /**
22
34
  * Resolve the platform config root path, if configured.
23
35
  *
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @module plugin/http
3
+ * The plugin's single HTTP helper for watcher API calls: JSON GET/POST via `fetch` with the core bearer header and the core error mapping (errors carry the server `code`; 401 adds key guidance). Never logs the key.
4
+ */
5
+ /** Where the plugin reads its API key from (named in 401 guidance). */
6
+ export declare const PLUGIN_KEY_SOURCES = "plugins.entries.jeeves-watcher-openclaw.config.apiKey or the JEEVES_WATCHER_API_KEY env var";
7
+ /**
8
+ * Call the watcher API and return the parsed JSON body.
9
+ *
10
+ * @param url - Full request URL.
11
+ * @param body - JSON body; `undefined` sends a GET, anything else a POST.
12
+ * @param apiKey - Bearer key; `undefined` sends no `Authorization` header.
13
+ * @returns Parsed JSON response body.
14
+ * @throws On `401` with core `unauthorizedMessage` (naming
15
+ * {@link PLUGIN_KEY_SOURCES}); on any other non-OK status with
16
+ * `HTTP <status> <code>: <message>` (core `httpError`); network errors
17
+ * propagate unchanged.
18
+ */
19
+ export declare function requestJson(url: string, body: unknown, apiKey: string | undefined): Promise<unknown>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @module plugin/http.test
3
+ * Unit tests for the plugin HTTP helper: bearer header presence/absence, unchanged unauthenticated request shape, 401 guidance naming the plugin key sources without the key, other errors carrying the server code.
4
+ */
5
+ export {};
@@ -7,16 +7,20 @@
7
7
  * error only when its implementation actually reads `configRoot`. Tools
8
8
  * that only call the service HTTP API keep working without it.
9
9
  *
10
- * Audit of the core standard toolset (`createPluginToolset`, core 0.6.0-7):
11
- * - `watcher_status`, `watcher_config`, `watcher_config_apply`: HTTP only
12
- * (`{apiUrl}/…`, resolved per call).
13
- * - `watcher_service`: only `install` reads `configRoot`
14
- * (`createServiceManager` → `resolveConfigFilePath` →
10
+ * Audit of the tools the plugin registers:
11
+ * - `watcher_status` (core standard toolset, `createPluginToolset`): HTTP
12
+ * only (`{apiUrl}/status`, resolved per call).
13
+ * - `watcher_config`, `watcher_config_apply`: implemented by the plugin
14
+ * (`configTools.ts`, replacing the core ones so the request carries the
15
+ * `Authorization: Bearer` key); HTTP only.
16
+ * - `watcher_service` (core standard toolset): only `install` reads
17
+ * `configRoot` (`createServiceManager` → `resolveConfigFilePath` →
15
18
  * `getComponentConfigDir`); the other actions query or drive the OS
16
19
  * service manager by service name.
17
20
  *
18
- * The 14 domain tools call `{apiUrl}/…` via `fetchJson`/`postJson` and are
19
- * never gated.
21
+ * The 14 domain tools (7 in `watcherTools.ts`, 7 VCS tools in
22
+ * `vcsTools.ts`) call the service API via `registerApiTool` →
23
+ * `requestJson` and are never gated.
20
24
  */
21
25
  /** Decides, per call, whether a tool invocation reads `configRoot`. */
22
26
  export type ConfigRootPredicate = (params: Record<string, unknown> | undefined) => boolean;
@@ -3,8 +3,10 @@
3
3
  * Jeeves component descriptor for the watcher OpenClaw plugin.
4
4
  *
5
5
  * @remarks
6
- * Feeds `createPluginToolset()` (`watcher_status`, `watcher_config`,
7
- * `watcher_config_apply`, `watcher_service`). The service descriptor
6
+ * Feeds `createPluginToolset()`, of which the plugin registers
7
+ * `watcher_status` and `watcher_service`; its `watcher_config` and
8
+ * `watcher_config_apply` are replaced by the plugin's own (`configTools.ts`,
9
+ * which send the API key). The service descriptor
8
10
  * (`packages/service/src/descriptor.ts`) is the canonical source for the
9
11
  * config schema and CLI commands.
10
12
  */
@@ -3,6 +3,7 @@
3
3
  * Domain-specific watcher tool registrations (14 tools) for the OpenClaw plugin.
4
4
  */
5
5
  import { type PluginApi } from '@karmaniverous/jeeves';
6
+ import { type BaseUrlSource } from './apiTool.js';
6
7
  /**
7
8
  * Register the 14 domain-specific watcher_* tools with the OpenClaw plugin API.
8
9
  *
@@ -11,5 +12,10 @@ import { type PluginApi } from '@karmaniverous/jeeves';
11
12
  * OpenClaw Tool Search keeps them model-visible: semantic search must be a
12
13
  * direct tool or the model reaches for grep first. All other tools remain
13
14
  * catalog-eligible.
15
+ *
16
+ * @param api - Plugin API.
17
+ * @param baseUrl - API base URL, or a getter resolved on every call (so a
18
+ * changed `apiUrl` takes effect without re-registering, as for the config
19
+ * tools).
14
20
  */
15
- export declare function registerWatcherTools(api: PluginApi, baseUrl: string): void;
21
+ export declare function registerWatcherTools(api: PluginApi, baseUrl: BaseUrlSource): void;
@@ -2,7 +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.16.1",
5
+ "version": "0.17.0",
6
6
  "skills": ["dist/skills/jeeves-watcher"],
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -13,6 +13,10 @@
13
13
  "description": "jeeves-watcher API base URL",
14
14
  "default": "http://127.0.0.1:1936"
15
15
  },
16
+ "apiKey": {
17
+ "type": "string",
18
+ "description": "Bearer key sent as Authorization: Bearer <key> on every watcher API request; must match the service's api.apiKey. Falls back to the JEEVES_WATCHER_API_KEY env var. Unset: no header."
19
+ },
16
20
  "configRoot": {
17
21
  "type": "string",
18
22
  "description": "Platform config root path (e.g. /srv/jeeves/config). No default: set it here (jeeves install --config-root) or via the JEEVES_CONFIG_ROOT env var."
@@ -46,6 +50,11 @@
46
50
  "label": "Watcher API URL",
47
51
  "placeholder": "http://127.0.0.1:1936"
48
52
  },
53
+ "apiKey": {
54
+ "label": "Watcher API key",
55
+ "help": "Sent as a bearer token; matches the service's api.apiKey. Leave unset when the API has no key.",
56
+ "sensitive": true
57
+ },
49
58
  "configRoot": {
50
59
  "label": "Config root",
51
60
  "placeholder": "/path/to/config"
package/package.json CHANGED
@@ -4,22 +4,22 @@
4
4
  "url": "https://github.com/karmaniverous/jeeves-watcher/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@karmaniverous/jeeves": "0.6.0",
8
- "@karmaniverous/jeeves-watcher-core": "^0.3.1"
7
+ "@karmaniverous/jeeves": "0.7.0",
8
+ "@karmaniverous/jeeves-watcher-core": "^0.4.0"
9
9
  },
10
10
  "description": "OpenClaw plugin for jeeves-watcher — semantic search and metadata enrichment tools",
11
11
  "devDependencies": {
12
- "@dotenvx/dotenvx": "^2.30.0",
12
+ "@dotenvx/dotenvx": "^2.35.0",
13
13
  "@rollup/plugin-commonjs": "^29.0.3",
14
14
  "@rollup/plugin-json": "^6.1.0",
15
15
  "@rollup/plugin-node-resolve": "^16.0.3",
16
16
  "@rollup/plugin-typescript": "^12.3.0",
17
17
  "cross-env": "^10.1.0",
18
- "knip": "^6.38.0",
19
- "release-it": "^21.1.0",
20
- "rollup": "^4.63.5",
18
+ "knip": "^6.41.0",
19
+ "release-it": "^21.1.1",
20
+ "rollup": "^4.64.6",
21
21
  "tslib": "^2.8.1",
22
- "vitest": "^5.0.2"
22
+ "vitest": "^5.0.4"
23
23
  },
24
24
  "engines": {
25
25
  "node": ">=22.13"
@@ -67,7 +67,9 @@
67
67
  "tagName": "openclaw/${version}"
68
68
  },
69
69
  "github": {
70
- "release": true
70
+ "release": true,
71
+ "releaseName": "${name.split('/').pop()}@${version}",
72
+ "releaseNotes": "npx git-cliff --tag openclaw/${version} --unreleased --strip header"
71
73
  },
72
74
  "hooks": {
73
75
  "after:bump": [
@@ -88,7 +90,7 @@
88
90
  "git switch ${branchName}"
89
91
  ],
90
92
  "before:npm:release": [
91
- "npx git-cliff -o CHANGELOG.md",
93
+ "npx git-cliff --tag openclaw/${version} -o CHANGELOG.md",
92
94
  "git add -A"
93
95
  ]
94
96
  },
@@ -115,5 +117,5 @@
115
117
  },
116
118
  "type": "module",
117
119
  "types": "dist/index.d.ts",
118
- "version": "0.16.1"
120
+ "version": "0.17.0"
119
121
  }