ocuclaw 1.3.0 → 1.3.1
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 +3 -1
- package/dist/config/runtime-config.js +17 -14
- package/dist/domain/debug-store.js +18 -0
- package/dist/runtime/plugin-version-service.js +23 -0
- package/dist/runtime/relay-core.js +98 -35
- package/dist/runtime/relay-worker-protocol.js +0 -4
- package/dist/runtime/relay-worker-supervisor.js +0 -77
- package/dist/runtime/session-service.js +23 -3
- package/dist/tools/glasses-ui-recipes.js +13 -178
- package/dist/tools/glasses-ui-tool.js +10 -46
- package/dist/version.js +2 -2
- package/package.json +4 -3
- package/skills/glasses-ui/SKILL.md +156 -0
- package/dist/runtime/downstream-server.js +0 -2057
- package/dist/runtime/plugin-update-service.js +0 -216
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { PLUGIN_VERSION, REQUIRES_CLIENT_VERSION } from "../version.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Plugin update service.
|
|
5
|
-
*
|
|
6
|
-
* Exposes the current plugin version (from build-time constant) and two
|
|
7
|
-
* single-flight executors that shell out to the openclaw CLI:
|
|
8
|
-
* - runPluginUpdate: `openclaw plugins update ocuclaw`
|
|
9
|
-
* - runGatewayRestart: `openclaw gateway restart` (detached)
|
|
10
|
-
*
|
|
11
|
-
* Injects child_process.spawn so tests can mock process behaviour.
|
|
12
|
-
*/
|
|
13
|
-
function createPluginUpdateService(deps) {
|
|
14
|
-
const spawn = deps.spawn;
|
|
15
|
-
const logger = deps.logger;
|
|
16
|
-
const nowMs = deps.nowMs;
|
|
17
|
-
const setTimeoutFn = deps.setTimeout;
|
|
18
|
-
const clearTimeoutFn = deps.clearTimeout;
|
|
19
|
-
const updateTimeoutMs = Number.isFinite(deps.updateTimeoutMs)
|
|
20
|
-
? Math.max(1, Math.floor(deps.updateTimeoutMs))
|
|
21
|
-
: 5 * 60 * 1000;
|
|
22
|
-
const killGraceMs = Number.isFinite(deps.killGraceMs)
|
|
23
|
-
? Math.max(1, Math.floor(deps.killGraceMs))
|
|
24
|
-
: 5 * 1000;
|
|
25
|
-
|
|
26
|
-
function getPluginVersion() {
|
|
27
|
-
return typeof PLUGIN_VERSION === "string" && PLUGIN_VERSION.length > 0
|
|
28
|
-
? PLUGIN_VERSION
|
|
29
|
-
: null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function getRequiresClientVersion() {
|
|
33
|
-
return typeof REQUIRES_CLIENT_VERSION === "string" && REQUIRES_CLIENT_VERSION.length > 0
|
|
34
|
-
? REQUIRES_CLIENT_VERSION
|
|
35
|
-
: null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function captureStderrTail(stream, maxBytes) {
|
|
39
|
-
const chunks = [];
|
|
40
|
-
let totalBytes = 0;
|
|
41
|
-
let drained = false;
|
|
42
|
-
const drainCallbacks = [];
|
|
43
|
-
stream.on("data", (chunk) => {
|
|
44
|
-
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
45
|
-
chunks.push(buf);
|
|
46
|
-
totalBytes += buf.length;
|
|
47
|
-
while (totalBytes > maxBytes && chunks.length > 0) {
|
|
48
|
-
const head = chunks[0];
|
|
49
|
-
if (totalBytes - head.length >= maxBytes) {
|
|
50
|
-
// Dropping head still leaves more than maxBytes; drop it entirely.
|
|
51
|
-
chunks.shift();
|
|
52
|
-
totalBytes -= head.length;
|
|
53
|
-
} else {
|
|
54
|
-
// Partial drop: slice head so the total becomes exactly maxBytes.
|
|
55
|
-
const drop = totalBytes - maxBytes;
|
|
56
|
-
chunks[0] = head.subarray(drop);
|
|
57
|
-
totalBytes = maxBytes;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
const onDrained = () => {
|
|
63
|
-
if (drained) return;
|
|
64
|
-
drained = true;
|
|
65
|
-
for (const cb of drainCallbacks) cb();
|
|
66
|
-
};
|
|
67
|
-
stream.on("end", onDrained);
|
|
68
|
-
stream.on("close", onDrained);
|
|
69
|
-
stream.on("error", onDrained);
|
|
70
|
-
return {
|
|
71
|
-
readTail() {
|
|
72
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
73
|
-
},
|
|
74
|
-
whenDrained(cb) {
|
|
75
|
-
if (drained) { cb(); } else { drainCallbacks.push(cb); }
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
let updateInFlight = false;
|
|
81
|
-
let restartStarted = false;
|
|
82
|
-
|
|
83
|
-
async function runPluginUpdate() {
|
|
84
|
-
if (updateInFlight) {
|
|
85
|
-
return { ok: false, reason: "in_progress" };
|
|
86
|
-
}
|
|
87
|
-
updateInFlight = true;
|
|
88
|
-
try {
|
|
89
|
-
return await doRunPluginUpdate();
|
|
90
|
-
} finally {
|
|
91
|
-
updateInFlight = false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function doRunPluginUpdate() {
|
|
96
|
-
return await new Promise((resolve) => {
|
|
97
|
-
const STDERR_MAX_BYTES = 8 * 1024;
|
|
98
|
-
let settled = false;
|
|
99
|
-
let timedOut = false;
|
|
100
|
-
let timeoutTimer = null;
|
|
101
|
-
let killTimer = null;
|
|
102
|
-
let safetyTimer = null;
|
|
103
|
-
const settle = (result) => {
|
|
104
|
-
if (settled) return;
|
|
105
|
-
settled = true;
|
|
106
|
-
if (timeoutTimer !== null) {
|
|
107
|
-
clearTimeoutFn(timeoutTimer);
|
|
108
|
-
timeoutTimer = null;
|
|
109
|
-
}
|
|
110
|
-
if (killTimer !== null) {
|
|
111
|
-
clearTimeoutFn(killTimer);
|
|
112
|
-
killTimer = null;
|
|
113
|
-
}
|
|
114
|
-
if (safetyTimer !== null) {
|
|
115
|
-
clearTimeoutFn(safetyTimer);
|
|
116
|
-
safetyTimer = null;
|
|
117
|
-
}
|
|
118
|
-
resolve(result);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
let child;
|
|
122
|
-
try {
|
|
123
|
-
child = spawn(
|
|
124
|
-
"openclaw",
|
|
125
|
-
["plugins", "update", "ocuclaw"],
|
|
126
|
-
{ env: process.env, stdio: ["ignore", "pipe", "pipe"] },
|
|
127
|
-
);
|
|
128
|
-
} catch (_err) {
|
|
129
|
-
settle({ ok: false, reason: "spawn_failed" });
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const stderrBuf = child.stderr
|
|
134
|
-
? captureStderrTail(child.stderr, STDERR_MAX_BYTES)
|
|
135
|
-
: { readTail: () => "", whenDrained: (cb) => cb() };
|
|
136
|
-
|
|
137
|
-
child.on("error", (err) => {
|
|
138
|
-
const code = err && err.code;
|
|
139
|
-
if (code === "ENOENT") {
|
|
140
|
-
settle({ ok: false, reason: "cli_not_found" });
|
|
141
|
-
} else {
|
|
142
|
-
settle({ ok: false, reason: "spawn_failed" });
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
child.on("exit", (code) => {
|
|
146
|
-
if (timedOut) {
|
|
147
|
-
settle({ ok: false, reason: "timeout" });
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (code === 0) {
|
|
151
|
-
settle({ ok: true });
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
const exitCode = typeof code === "number" ? code : null;
|
|
155
|
-
stderrBuf.whenDrained(() => {
|
|
156
|
-
const tail = stderrBuf.readTail();
|
|
157
|
-
settle({
|
|
158
|
-
ok: false,
|
|
159
|
-
reason: "nonzero_exit",
|
|
160
|
-
exitCode,
|
|
161
|
-
stderrTail: tail.length > 0 ? tail : undefined,
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
timeoutTimer = setTimeoutFn(() => {
|
|
167
|
-
timeoutTimer = null;
|
|
168
|
-
timedOut = true;
|
|
169
|
-
try { child.kill("SIGTERM"); } catch (_) {}
|
|
170
|
-
killTimer = setTimeoutFn(() => {
|
|
171
|
-
killTimer = null;
|
|
172
|
-
try { child.kill("SIGKILL"); } catch (_) {}
|
|
173
|
-
}, killGraceMs);
|
|
174
|
-
// Safety net: if child never emits exit, settle after kill grace + buffer.
|
|
175
|
-
safetyTimer = setTimeoutFn(() => {
|
|
176
|
-
safetyTimer = null;
|
|
177
|
-
settle({ ok: false, reason: "timeout" });
|
|
178
|
-
}, killGraceMs + 50);
|
|
179
|
-
}, updateTimeoutMs);
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function runGatewayRestart() {
|
|
184
|
-
if (restartStarted) {
|
|
185
|
-
return { ok: false, started: false, reason: "in_progress" };
|
|
186
|
-
}
|
|
187
|
-
let child;
|
|
188
|
-
try {
|
|
189
|
-
child = spawn(
|
|
190
|
-
"openclaw",
|
|
191
|
-
["gateway", "restart"],
|
|
192
|
-
{ detached: true, stdio: "ignore", env: process.env },
|
|
193
|
-
);
|
|
194
|
-
} catch (err) {
|
|
195
|
-
const code = err && err.code;
|
|
196
|
-
if (code === "ENOENT") {
|
|
197
|
-
return { ok: false, started: false, reason: "cli_not_found" };
|
|
198
|
-
}
|
|
199
|
-
return { ok: false, started: false, reason: "spawn_failed" };
|
|
200
|
-
}
|
|
201
|
-
try {
|
|
202
|
-
if (typeof child.unref === "function") child.unref();
|
|
203
|
-
} catch (_) {}
|
|
204
|
-
restartStarted = true;
|
|
205
|
-
return { ok: true, started: true };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
getPluginVersion,
|
|
210
|
-
getRequiresClientVersion,
|
|
211
|
-
runPluginUpdate,
|
|
212
|
-
runGatewayRestart,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export { createPluginUpdateService };
|