@karmaniverous/jeeves 0.6.0-1 → 0.6.0-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 +4 -2
- package/dist/cli/jeeves/index.js +70 -6
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,9 +227,9 @@ OpenClaw must already be installed; `jeeves` checks for it and never installs it
|
|
|
227
227
|
1. Renders the SOUL.md/AGENTS.md managed blocks (your content outside the markers is kept) and the core config if it's missing. It never writes TOOLS.md, HEARTBEAT.md, anything under `skills/` or the spec templates (those ship with the jeeves-design skill in jeeves-tools).
|
|
228
228
|
2. For each plugin (default: `runner`, `watcher`, `server`, `meta` at `latest`), resolves an exact version with `npm view`, then runs `openclaw plugins install npm:<pkg>@<version> --pin --accept-capabilities --force`. `--force` is required for any non-ClawHub source, and it also overwrites an existing install, which is how updates land. The install is skipped when that exact version is already installed. The CLI reads OpenClaw's install records once with `openclaw plugins inspect --all --json` (no plugin code is loaded) and skips a plugin only if its record has `source: "npm"`, names the same package, and records the same version, and the loaded plugin reports that version too. A v0.x path install, a leftover legacy copy, or any record it cannot read means a reinstall. `--force-reinstall` always reinstalls. Steps 3 and 4 run either way.
|
|
229
229
|
3. Removes any legacy `<openclaw dir>/extensions/<id>` copy left by the v0.x installer, but only if its `package.json` names the expected package.
|
|
230
|
-
4.
|
|
230
|
+
4. Runs `openclaw plugins inspect --all --json` once (a migration sweep, see below; its output is not shown and a failure is only logged), then sets `plugins.entries.<id>.hooks.allowConversationAccess: true` for plugins that [declare conversation hooks](#declaring-conversation-hooks), and the plugin config (`plugins.entries.<id>.config.<key>`, see [Plugin config](#plugin-config)), with one `openclaw config set --batch-file <file>` call. The file is created owner-only in a fresh temp directory (mode `0600` in a `0700` directory on Linux/macOS; on Windows the directory ACL is reduced to the current user with `icacls`) and deleted afterwards, so no value, secret or not, appears on a command line. Every write targets a leaf path, so unrelated keys are kept. `plugins.installs` is never written.
|
|
231
231
|
|
|
232
|
-
Right after an install, OpenClaw can refuse to edit a plugin's config until it finishes that plugin's data/settings upgrade (`Plugin "<id>" data/settings upgrade is unfinished: ... has not converged`). Only that refusal is retried: the same batch file is resubmitted after 2s, 4s, 8s, 16s, then every 30s, for up to 120s of waiting in total, with one log line per retry. If the plugin still hasn't converged, the command fails and names the plugin; wait and rerun it (the writes are idempotent). Any other error fails at once. The `openclaw config unset` repairs after an uninstall follow the same rule. A dry run never retries.
|
|
232
|
+
Right after an install, OpenClaw can refuse to edit a plugin's config until it finishes that plugin's data/settings upgrade (`Plugin "<id>" data/settings upgrade is unfinished: ... has not converged`). This happens when the gateway started with `plugins.entries.<id>` configured before the package was installed: OpenClaw records a pending migration for that plugin, installing it does not clear the record, and a refused `openclaw config set` doesn't either. OpenClaw resolves such records in the startup preflight of ordinary CLI commands (not `config`, and not `plugins list`), which is why the sweep runs `plugins inspect` before the batch. Only that refusal is retried: the sweep runs again, then the same batch file is resubmitted after 2s, 4s, 8s, 16s, then every 30s, for up to 120s of waiting in total, with one log line per retry. If the plugin still hasn't converged, the command fails and names the plugin; wait and rerun it (the writes are idempotent). Any other error fails at once. The `openclaw config unset` repairs after an uninstall follow the same rule. A dry run never retries.
|
|
233
233
|
|
|
234
234
|
Plugin specs can be short (`watcher`, `watcher@1.2.3`, `runner@^1`) or full (`@karmaniverous/jeeves-watcher-openclaw@1.2.3`). Only `@karmaniverous/jeeves-*-openclaw` packages are accepted. `--content-only` skips the plugins.
|
|
235
235
|
|
|
@@ -305,6 +305,7 @@ $ jeeves install watcher --dry-run
|
|
|
305
305
|
…
|
|
306
306
|
[dry-run] openclaw plugins install npm:@karmaniverous/jeeves-watcher-openclaw@0.16.0 --pin --accept-capabilities --force
|
|
307
307
|
[dry-run] remove legacy plugin copy: /home/jeeves/.openclaw/extensions/jeeves-watcher-openclaw
|
|
308
|
+
[dry-run] openclaw plugins inspect --all --json (lets OpenClaw clear pending plugin migrations)
|
|
308
309
|
[dry-run] openclaw config set --batch-file <private temp file>
|
|
309
310
|
[dry-run] batch file content: [{"path":"plugins.entries.jeeves-watcher-openclaw.hooks.allowConversationAccess","value":true}]
|
|
310
311
|
```
|
|
@@ -322,6 +323,7 @@ Plugin config:
|
|
|
322
323
|
…
|
|
323
324
|
[dry-run] set keys._plugin = <redacted> in /srv/jeeves/config/jeeves-server/config.json (currently unset; backup /srv/jeeves/config/jeeves-server/config.json.bak-<timestamp> first, then atomic write; restart jeeves-server afterwards)
|
|
324
325
|
…
|
|
326
|
+
[dry-run] openclaw plugins inspect --all --json (lets OpenClaw clear pending plugin migrations)
|
|
325
327
|
[dry-run] openclaw config set --batch-file <private temp file>
|
|
326
328
|
[dry-run] batch file content: [{"path":"plugins.entries.jeeves-server-openclaw.config.configRoot","value":"/srv/jeeves/config"},{"path":"plugins.entries.jeeves-server-openclaw.config.apiUrl","value":"http://127.0.0.1:1934"},{"path":"plugins.entries.jeeves-server-openclaw.config.pluginKey","value":"<redacted>"}]
|
|
327
329
|
```
|
package/dist/cli/jeeves/index.js
CHANGED
|
@@ -140,14 +140,14 @@ const DEFAULT_PORTS = {
|
|
|
140
140
|
* Core library version, inlined at build time.
|
|
141
141
|
*
|
|
142
142
|
* @remarks
|
|
143
|
-
* The `0.6.0-
|
|
143
|
+
* The `0.6.0-1` placeholder is replaced by
|
|
144
144
|
* `@rollup/plugin-replace` during the build with the actual version
|
|
145
145
|
* from `package.json`. This ensures the correct version survives
|
|
146
146
|
* when consumers bundle core into their own dist (where runtime
|
|
147
147
|
* `import.meta.url`-based resolution would find the wrong package.json).
|
|
148
148
|
*/
|
|
149
149
|
/** The core library version from package.json (inlined at build time). */
|
|
150
|
-
const CORE_VERSION = '0.6.0-
|
|
150
|
+
const CORE_VERSION = '0.6.0-1';
|
|
151
151
|
|
|
152
152
|
/**
|
|
153
153
|
* Shared internal utility functions.
|
|
@@ -1639,7 +1639,9 @@ function configuredPluginIds(plugins, isJeeves) {
|
|
|
1639
1639
|
* `Cannot edit retained config at "<path>". Plugin "<id>" data/settings upgrade is unfinished: <reason> ...`
|
|
1640
1640
|
*
|
|
1641
1641
|
* Only that signal is retried, with exponential backoff inside a fixed wait
|
|
1642
|
-
* budget;
|
|
1642
|
+
* budget; before each wait the optional `beforeRetry` hook runs (the plan
|
|
1643
|
+
* executor uses it to let OpenClaw clear pending migration records, see
|
|
1644
|
+
* `migrationSweep.ts`, since a refused `config set` never clears them); any other failure is rethrown at once. Config writes are idempotent
|
|
1643
1645
|
* leaf sets/unsets, so repeating one is safe.
|
|
1644
1646
|
*
|
|
1645
1647
|
* @module
|
|
@@ -1696,7 +1698,7 @@ function retryDelays(policy) {
|
|
|
1696
1698
|
* still converging.
|
|
1697
1699
|
*
|
|
1698
1700
|
* @param action - The write.
|
|
1699
|
-
* @param options - Sleep, logger, policy.
|
|
1701
|
+
* @param options - Sleep, logger, policy, pre-retry hook.
|
|
1700
1702
|
* @throws The original error for any other failure; an `Error` naming the
|
|
1701
1703
|
* plugins still converging once the budget is spent.
|
|
1702
1704
|
*/
|
|
@@ -1717,6 +1719,7 @@ async function withConvergenceRetry(action, options) {
|
|
|
1717
1719
|
throw new Error(`OpenClaw still refuses the config write after ${String(waited / 1000)}s: plugin(s) ${plugins.join(', ')} have not finished converging after install. Wait, then rerun the command (or run "openclaw doctor --fix").`, { cause: error });
|
|
1718
1720
|
}
|
|
1719
1721
|
options.log(`OpenClaw has not finished converging plugin(s) ${plugins.join(', ')}; retrying in ${String(delay / 1000)}s (retry ${String(attempt + 1)}/${String(delays.length)})`);
|
|
1722
|
+
await options.beforeRetry?.();
|
|
1720
1723
|
await options.sleep(delay);
|
|
1721
1724
|
waited += delay;
|
|
1722
1725
|
}
|
|
@@ -1874,6 +1877,57 @@ const npmViewVersionArgs = (packageName, range) => ['view', `${packageName}@${ra
|
|
|
1874
1877
|
*/
|
|
1875
1878
|
const npmViewFieldArgs = (packageName, version, field) => ['view', `${packageName}@${version}`, field, '--json'];
|
|
1876
1879
|
|
|
1880
|
+
/**
|
|
1881
|
+
* Let OpenClaw resolve pending plugin-migration records before config writes.
|
|
1882
|
+
*
|
|
1883
|
+
* @remarks
|
|
1884
|
+
* When the gateway starts with `plugins.entries` for plugins that are not yet
|
|
1885
|
+
* installed, OpenClaw records a pending (deferred) data/settings migration for
|
|
1886
|
+
* each. Installing the plugin does not clear that record, and
|
|
1887
|
+
* `openclaw config set` refuses to edit the plugin's retained config while it
|
|
1888
|
+
* exists. `config` commands never clear it either: OpenClaw v2026.9.6 runs the
|
|
1889
|
+
* startup state-migration preflight (`runDoctorConfigPreflight` with
|
|
1890
|
+
* `migrateState: true`, which resolves finished records through
|
|
1891
|
+
* `recordDeferredPluginMigrations`, see
|
|
1892
|
+
* `src/commands/doctor-config-preflight-plugin-migrations.ts:160`) from
|
|
1893
|
+
* `ensureConfigReady` (`src/cli/program/config-guard.ts:256-328`) for every
|
|
1894
|
+
* guarded command except `config`, `health`, `logs`, `sessions` and a few
|
|
1895
|
+
* others. `plugins list` skips the guard (`configGuard: "skip"`,
|
|
1896
|
+
* `src/cli/command-catalog.ts:570-577`); `plugins inspect` has no catalog
|
|
1897
|
+
* entry, so it takes the default `configGuard: "run"`
|
|
1898
|
+
* (`src/cli/command-path-policy.ts:14`) and sweeps.
|
|
1899
|
+
*
|
|
1900
|
+
* The sweep is best effort: a failure is logged and never fails the plan (the
|
|
1901
|
+
* config write that follows reports any real problem).
|
|
1902
|
+
*
|
|
1903
|
+
* @module
|
|
1904
|
+
*/
|
|
1905
|
+
/** Dry-run/log description of the sweep. */
|
|
1906
|
+
const MIGRATION_SWEEP_LINE = `${formatCommand(OPENCLAW_BIN, pluginsInspectAllArgs())} (lets OpenClaw clear pending plugin migrations)`;
|
|
1907
|
+
const warn = (log, reason) => {
|
|
1908
|
+
log(`plugin migration sweep failed (continuing): ${reason}`);
|
|
1909
|
+
};
|
|
1910
|
+
/**
|
|
1911
|
+
* Run `openclaw plugins inspect --all --json` so OpenClaw's startup preflight
|
|
1912
|
+
* resolves pending plugin-migration records. Output is not echoed.
|
|
1913
|
+
*
|
|
1914
|
+
* @param runner - Command runner.
|
|
1915
|
+
* @param log - Line logger.
|
|
1916
|
+
*/
|
|
1917
|
+
async function runMigrationSweep(runner, log) {
|
|
1918
|
+
const args = pluginsInspectAllArgs();
|
|
1919
|
+
log(`$ ${MIGRATION_SWEEP_LINE}`);
|
|
1920
|
+
try {
|
|
1921
|
+
const result = await runner(OPENCLAW_BIN, args);
|
|
1922
|
+
if (result.exitCode !== 0) {
|
|
1923
|
+
warn(log, describeExit(OPENCLAW_BIN, args, result.exitCode));
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
catch (error) {
|
|
1927
|
+
warn(log, String(error));
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1877
1931
|
/**
|
|
1878
1932
|
* Human-readable lines for plan steps: the exact command lines, batch file
|
|
1879
1933
|
* contents with secrets redacted, and conditional repairs. Pure; used for
|
|
@@ -1918,6 +1972,8 @@ function describeStep(step) {
|
|
|
1918
1972
|
return [formatCommand(step.command, step.args)];
|
|
1919
1973
|
case 'configSetBatch':
|
|
1920
1974
|
return describeConfigBatchLines(step.ops, step.redact);
|
|
1975
|
+
case 'migrationSweep':
|
|
1976
|
+
return [MIGRATION_SWEEP_LINE];
|
|
1921
1977
|
case 'removeDir':
|
|
1922
1978
|
return [`remove legacy plugin copy: ${step.path}`];
|
|
1923
1979
|
case 'serverKeyWrite':
|
|
@@ -2146,8 +2202,9 @@ function createNodePrivateTempFiles(runner, platform = process.platform, baseDir
|
|
|
2146
2202
|
* temp file, passed with `--batch-file`, and deleted afterwards. Config
|
|
2147
2203
|
* writes (batches and unsets) are retried with bounded backoff only while
|
|
2148
2204
|
* OpenClaw reports that a freshly installed plugin has not converged yet
|
|
2149
|
-
* (see {@link withConvergenceRetry});
|
|
2150
|
-
* and
|
|
2205
|
+
* (see {@link withConvergenceRetry}); before each wait the migration sweep
|
|
2206
|
+
* runs again (see {@link runMigrationSweep}), and the batch file is kept for
|
|
2207
|
+
* the retries and deleted once.
|
|
2151
2208
|
*
|
|
2152
2209
|
* @module
|
|
2153
2210
|
*/
|
|
@@ -2155,6 +2212,7 @@ function createNodePrivateTempFiles(runner, platform = process.platform, baseDir
|
|
|
2155
2212
|
const retryingConfigWrite = (ctx, action) => withConvergenceRetry(action, {
|
|
2156
2213
|
sleep: ctx.sleep ?? timerSleep,
|
|
2157
2214
|
log: ctx.log,
|
|
2215
|
+
beforeRetry: () => runMigrationSweep(ctx.runner, ctx.log),
|
|
2158
2216
|
});
|
|
2159
2217
|
/** Run one command (echoing its output), logging its command line first. */
|
|
2160
2218
|
async function runLogged(ctx, command, args) {
|
|
@@ -2186,6 +2244,9 @@ async function executeStep(step, ctx) {
|
|
|
2186
2244
|
case 'configSetBatch':
|
|
2187
2245
|
await runConfigBatch(ctx, step.ops, step.redact);
|
|
2188
2246
|
return;
|
|
2247
|
+
case 'migrationSweep':
|
|
2248
|
+
await runMigrationSweep(ctx.runner, ctx.log);
|
|
2249
|
+
return;
|
|
2189
2250
|
case 'removeDir':
|
|
2190
2251
|
if (ctx.fs.isDirectory(step.path)) {
|
|
2191
2252
|
ctx.fs.removeDir(step.path);
|
|
@@ -3144,6 +3205,8 @@ const openclaw = (args) => ({
|
|
|
3144
3205
|
* @returns The server `keys._plugin` write (if planned; first, so a failure
|
|
3145
3206
|
* there, e.g. a held lock, leaves OpenClaw untouched), then install steps
|
|
3146
3207
|
* (targets not yet installed at their version), then legacy removals, then
|
|
3208
|
+
* (when there is config to write) a migration sweep so OpenClaw clears the
|
|
3209
|
+
* pending migration records it keeps for freshly installed plugins, then
|
|
3147
3210
|
* one config batch with hook access (only for targets that declare
|
|
3148
3211
|
* conversation hooks) and plugin config. Re-running after a later failure
|
|
3149
3212
|
* converges: the server then has the key and the plugin side copies it.
|
|
@@ -3169,6 +3232,7 @@ function buildInstallPlan(targets, plugins, config) {
|
|
|
3169
3232
|
];
|
|
3170
3233
|
if (ops.length > 0) {
|
|
3171
3234
|
const secrets = config?.secrets ?? [];
|
|
3235
|
+
steps.push({ kind: 'migrationSweep' });
|
|
3172
3236
|
steps.push({
|
|
3173
3237
|
kind: 'configSetBatch',
|
|
3174
3238
|
ops,
|
package/dist/index.js
CHANGED
|
@@ -142,14 +142,14 @@ const DEFAULT_PORTS = {
|
|
|
142
142
|
* Core library version, inlined at build time.
|
|
143
143
|
*
|
|
144
144
|
* @remarks
|
|
145
|
-
* The `0.6.0-
|
|
145
|
+
* The `0.6.0-1` placeholder is replaced by
|
|
146
146
|
* `@rollup/plugin-replace` during the build with the actual version
|
|
147
147
|
* from `package.json`. This ensures the correct version survives
|
|
148
148
|
* when consumers bundle core into their own dist (where runtime
|
|
149
149
|
* `import.meta.url`-based resolution would find the wrong package.json).
|
|
150
150
|
*/
|
|
151
151
|
/** The core library version from package.json (inlined at build time). */
|
|
152
|
-
const CORE_VERSION = '0.6.0-
|
|
152
|
+
const CORE_VERSION = '0.6.0-1';
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* Workspace and config root initialization.
|