@ahyi/restart-continuity 0.4.0 → 0.5.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 +15 -60
- package/index.ts +26 -24
- package/openclaw.plugin.json +1 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,80 +1,35 @@
|
|
|
1
1
|
# Restart Continuity Plugin
|
|
2
2
|
|
|
3
|
-
OpenClaw plugin for **gateway restart continuity
|
|
4
|
-
|
|
5
|
-
- runs resumable startup checks when the plugin service starts
|
|
6
|
-
- can health-check and replay selected cron jobs
|
|
7
|
-
- writes a structured continuity state file
|
|
8
|
-
- writes a human-readable daily memory log
|
|
9
|
-
- can hand off a one-shot startup receipt during agent bootstrap
|
|
10
|
-
- works out of the box after `openclaw plugins install ...` + `enable`, with built-in default resumers for this mh instance
|
|
3
|
+
OpenClaw plugin for **gateway restart continuity** with **zero-config behavior on this mh instance**.
|
|
11
4
|
|
|
12
5
|
## Install
|
|
13
6
|
|
|
14
|
-
### npm registry
|
|
15
|
-
|
|
16
7
|
```bash
|
|
17
|
-
openclaw --profile <profile> plugins install @ahyi/restart-continuity@0.
|
|
8
|
+
openclaw --profile <profile> plugins install @ahyi/restart-continuity@0.5.0
|
|
18
9
|
openclaw --profile <profile> plugins enable restart-continuity
|
|
19
10
|
```
|
|
20
11
|
|
|
21
12
|
Then restart the gateway.
|
|
22
13
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
This plugin replaces scattered hook-based restart continuity setups with one installable extension.
|
|
26
|
-
|
|
27
|
-
On plugin service start it can:
|
|
14
|
+
## Zero-config behavior
|
|
28
15
|
|
|
29
|
-
|
|
30
|
-
2. run configured startup resumers
|
|
31
|
-
3. fall back to built-in default resumers when none are configured
|
|
32
|
-
4. write `memory/restart-continuity-state.json`
|
|
33
|
-
5. append a summary to `memory/YYYY-MM-DD.md`
|
|
34
|
-
6. stage a one-time startup receipt for bootstrap delivery
|
|
16
|
+
After install + enable, the plugin will work **without any extra config** on this mh instance.
|
|
35
17
|
|
|
36
|
-
|
|
18
|
+
It automatically:
|
|
37
19
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
- `mh-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
- detects the mh workspace directory
|
|
21
|
+
- assumes profile `mh` unless overridden
|
|
22
|
+
- uses built-in default resumers for:
|
|
23
|
+
- `mh-nightly-learnings-check`
|
|
24
|
+
- `mh-weekly-self-improve`
|
|
25
|
+
- writes `memory/restart-continuity-state.json`
|
|
26
|
+
- writes `memory/restart-continuity-installed.json`
|
|
27
|
+
- appends a summary to the daily memory log
|
|
28
|
+
- stages a one-shot bootstrap receipt
|
|
44
29
|
|
|
45
30
|
## Optional explicit config
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
"plugins": {
|
|
50
|
-
"entries": {
|
|
51
|
-
"restart-continuity": {
|
|
52
|
-
"enabled": true,
|
|
53
|
-
"config": {
|
|
54
|
-
"profile": "mh",
|
|
55
|
-
"workspaceDir": "/root/.openclaw/workspace-mh",
|
|
56
|
-
"logToDailyMemory": true,
|
|
57
|
-
"notifyOnBootstrap": true,
|
|
58
|
-
"resumers": [
|
|
59
|
-
{
|
|
60
|
-
"id": "nightly-learnings",
|
|
61
|
-
"kind": "cron-healthcheck",
|
|
62
|
-
"name": "mh-nightly-learnings-check",
|
|
63
|
-
"jobId": "38a8b8cb-c25a-4bc2-a8a1-d252f9d933ec"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"id": "weekly-self-improve",
|
|
67
|
-
"kind": "cron-healthcheck",
|
|
68
|
-
"name": "mh-weekly-self-improve",
|
|
69
|
-
"jobId": "6e912522-0591-4307-a155-a6ece496be9c"
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
32
|
+
You can still override behavior with `plugins.entries.restart-continuity.config`, but it is not required for this instance.
|
|
78
33
|
|
|
79
34
|
## Uninstall
|
|
80
35
|
|
package/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { promisify } from "node:util";
|
|
|
5
5
|
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
const OPENCLAW_BIN = process.env.OPENCLAW_BIN || "openclaw";
|
|
8
|
+
let bootStarted = false;
|
|
8
9
|
|
|
9
10
|
const BUILTIN_DEFAULT_RESUMERS = [
|
|
10
11
|
{
|
|
@@ -29,14 +30,17 @@ function normalizeString(value, fallback = "") {
|
|
|
29
30
|
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
function
|
|
33
|
+
function detectWorkspaceDir(api) {
|
|
33
34
|
const pluginConfig = api.pluginConfig || {};
|
|
34
35
|
const explicit = normalizeString(pluginConfig.workspaceDir, "");
|
|
35
36
|
if (explicit) return explicit;
|
|
36
|
-
|
|
37
|
+
const cfgWorkspace = normalizeString(api.config?.workspace?.dir, "");
|
|
38
|
+
if (cfgWorkspace) return cfgWorkspace;
|
|
39
|
+
const mhWorkspace = "/root/.openclaw/workspace-mh";
|
|
40
|
+
return mhWorkspace;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
function
|
|
43
|
+
function detectProfile(api) {
|
|
40
44
|
const pluginConfig = api.pluginConfig || {};
|
|
41
45
|
return normalizeString(pluginConfig.profile, "mh");
|
|
42
46
|
}
|
|
@@ -165,9 +169,7 @@ async function runCronHealthcheck(profile, resumer) {
|
|
|
165
169
|
return { status: "resumed", detail: `${resumer.name || resumer.id} => ${normalized}`, latestStatus };
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
async function ensureConfigInitialized(api) {
|
|
169
|
-
const workspaceDir = getWorkspaceDir(api);
|
|
170
|
-
const pluginConfig = api.pluginConfig || {};
|
|
172
|
+
async function ensureConfigInitialized(api, workspaceDir, pluginConfig) {
|
|
171
173
|
const stateFile = resolvePath(workspaceDir, pluginConfig.stateFile, "memory/restart-continuity-state.json");
|
|
172
174
|
const markerFile = resolvePath(workspaceDir, pluginConfig.markerFile, "memory/restart-continuity-installed.json");
|
|
173
175
|
|
|
@@ -193,10 +195,8 @@ async function ensureConfigInitialized(api) {
|
|
|
193
195
|
api.logger.info?.("[restart-continuity] initialized");
|
|
194
196
|
}
|
|
195
197
|
|
|
196
|
-
async function runStartupCheck(api) {
|
|
197
|
-
const
|
|
198
|
-
const profile = getProfile(api);
|
|
199
|
-
const workspaceDir = getWorkspaceDir(api);
|
|
198
|
+
async function runStartupCheck(api, workspaceDir, pluginConfig) {
|
|
199
|
+
const profile = detectProfile(api);
|
|
200
200
|
const stateFile = resolvePath(workspaceDir, pluginConfig.stateFile, "memory/restart-continuity-state.json");
|
|
201
201
|
const receiptFile = resolvePath(workspaceDir, pluginConfig.receiptFile, "memory/restart-continuity-receipt.json");
|
|
202
202
|
const logToDailyMemory = pluginConfig.logToDailyMemory !== false;
|
|
@@ -261,6 +261,20 @@ async function runStartupCheck(api) {
|
|
|
261
261
|
api.logger.info?.(`[restart-continuity] ${summary.receipt}`);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
async function boot(api) {
|
|
265
|
+
if (bootStarted) return;
|
|
266
|
+
bootStarted = true;
|
|
267
|
+
const pluginConfig = api.pluginConfig || {};
|
|
268
|
+
const workspaceDir = detectWorkspaceDir(api);
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
await ensureConfigInitialized(api, workspaceDir, pluginConfig);
|
|
272
|
+
await runStartupCheck(api, workspaceDir, pluginConfig);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
api.logger.warn?.(`[restart-continuity] boot failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
264
278
|
const plugin = {
|
|
265
279
|
id: "restart-continuity",
|
|
266
280
|
name: "Restart Continuity",
|
|
@@ -274,7 +288,6 @@ const plugin = {
|
|
|
274
288
|
workspaceDir: { label: "Workspace Directory" },
|
|
275
289
|
stateFile: { label: "State File" },
|
|
276
290
|
receiptFile: { label: "Receipt File" },
|
|
277
|
-
defaultsFile: { label: "Defaults File" },
|
|
278
291
|
markerFile: { label: "Install Marker File" },
|
|
279
292
|
logToDailyMemory: { label: "Append summary to daily memory" },
|
|
280
293
|
notifyOnBootstrap: { label: "Inject startup receipt into next bootstrap reply" },
|
|
@@ -282,18 +295,7 @@ const plugin = {
|
|
|
282
295
|
},
|
|
283
296
|
},
|
|
284
297
|
register(api) {
|
|
285
|
-
api
|
|
286
|
-
id: "restart-continuity-service",
|
|
287
|
-
start: async () => {
|
|
288
|
-
try {
|
|
289
|
-
await ensureConfigInitialized(api);
|
|
290
|
-
await runStartupCheck(api);
|
|
291
|
-
} catch (err) {
|
|
292
|
-
api.logger.warn?.(`[restart-continuity] service start failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
stop: async () => {},
|
|
296
|
-
});
|
|
298
|
+
void boot(api);
|
|
297
299
|
|
|
298
300
|
api.registerHook(
|
|
299
301
|
"agent:bootstrap",
|
|
@@ -304,7 +306,7 @@ const plugin = {
|
|
|
304
306
|
const bootstrapFiles = Array.isArray(ctx.bootstrapFiles) ? ctx.bootstrapFiles : null;
|
|
305
307
|
if (!bootstrapFiles) return;
|
|
306
308
|
|
|
307
|
-
const workspaceDir =
|
|
309
|
+
const workspaceDir = detectWorkspaceDir(api);
|
|
308
310
|
const receiptFile = resolvePath(workspaceDir, pluginConfig.receiptFile, "memory/restart-continuity-receipt.json");
|
|
309
311
|
const pending = await readJsonSafe(receiptFile, null);
|
|
310
312
|
if (!pending || !pending.receipt) return;
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "restart-continuity",
|
|
3
3
|
"name": "Restart Continuity",
|
|
4
4
|
"description": "Gateway restart continuity plugin with resumable startup checks and receipt handoff.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.5.0",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"workspaceDir": { "type": "string", "default": "" },
|
|
12
12
|
"stateFile": { "type": "string", "default": "memory/restart-continuity-state.json" },
|
|
13
13
|
"receiptFile": { "type": "string", "default": "memory/restart-continuity-receipt.json" },
|
|
14
|
-
"defaultsFile": { "type": "string", "default": "plugins/restart-continuity.defaults.json" },
|
|
15
14
|
"markerFile": { "type": "string", "default": "memory/restart-continuity-installed.json" },
|
|
16
15
|
"logToDailyMemory": { "type": "boolean", "default": true },
|
|
17
16
|
"notifyOnBootstrap": { "type": "boolean", "default": true },
|
|
@@ -45,7 +44,6 @@
|
|
|
45
44
|
"workspaceDir": { "label": "Workspace Directory" },
|
|
46
45
|
"stateFile": { "label": "State File" },
|
|
47
46
|
"receiptFile": { "label": "Receipt File" },
|
|
48
|
-
"defaultsFile": { "label": "Defaults File" },
|
|
49
47
|
"markerFile": { "label": "Install Marker File" },
|
|
50
48
|
"logToDailyMemory": { "label": "Append summary to daily memory" },
|
|
51
49
|
"notifyOnBootstrap": { "label": "Inject startup receipt into next bootstrap reply" },
|