clawvault 3.0.0 → 3.1.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 +156 -105
- package/bin/clawvault.js +0 -2
- package/bin/register-core-commands.js +20 -2
- package/dist/{chunk-3D6BCTP6.js → chunk-33UGEQRT.js} +70 -145
- package/dist/{chunk-ZVVFWOLW.js → chunk-3WRJEKN4.js} +1 -1
- package/dist/{chunk-DEFFDRVP.js → chunk-3ZIH425O.js} +3 -70
- package/dist/{chunk-K234IDRJ.js → chunk-D2H45LON.js} +1 -0
- package/dist/{chunk-YKTA5JOJ.js → chunk-H62BP7RI.js} +3 -3
- package/dist/{chunk-WGRQ6HDV.js → chunk-LI4O6NVK.js} +1 -1
- package/dist/{chunk-7R7O6STJ.js → chunk-OCGVIN3L.js} +1 -1
- package/dist/{chunk-GAJV4IGR.js → chunk-YCUNCH2I.js} +3 -7
- package/dist/cli/index.cjs +10 -1459
- package/dist/cli/index.js +5 -8
- package/dist/commands/compat.cjs +70 -145
- package/dist/commands/compat.js +1 -1
- package/dist/commands/context.cjs +1 -0
- package/dist/commands/context.js +3 -3
- package/dist/commands/doctor.cjs +68 -144
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/embed.js +2 -2
- package/dist/commands/setup.cjs +2 -69
- package/dist/commands/setup.d.cts +0 -1
- package/dist/commands/setup.d.ts +0 -1
- package/dist/commands/setup.js +2 -2
- package/dist/commands/sleep.cjs +1 -0
- package/dist/commands/sleep.js +2 -2
- package/dist/commands/status.cjs +1 -0
- package/dist/commands/status.js +2 -2
- package/dist/commands/wake.cjs +1 -0
- package/dist/commands/wake.js +2 -2
- package/dist/index.cjs +447 -2600
- package/dist/index.d.cts +0 -4
- package/dist/index.d.ts +0 -4
- package/dist/index.js +8 -69
- package/dist/plugin/index.cjs +3 -3
- package/dist/plugin/index.js +10 -10
- package/package.json +11 -17
- package/bin/register-tailscale-commands.js +0 -106
- package/dist/chunk-IVRIKYFE.js +0 -520
- package/dist/chunk-THRJVD4L.js +0 -373
- package/dist/chunk-TIGW564L.js +0 -628
- package/dist/commands/tailscale.cjs +0 -1532
- package/dist/commands/tailscale.d.cts +0 -52
- package/dist/commands/tailscale.d.ts +0 -52
- package/dist/commands/tailscale.js +0 -26
- package/dist/lib/canvas-layout.cjs +0 -136
- package/dist/lib/canvas-layout.d.cts +0 -31
- package/dist/lib/canvas-layout.d.ts +0 -31
- package/dist/lib/canvas-layout.js +0 -92
- package/dist/lib/tailscale.cjs +0 -1183
- package/dist/lib/tailscale.d.cts +0 -225
- package/dist/lib/tailscale.d.ts +0 -225
- package/dist/lib/tailscale.js +0 -50
- package/dist/lib/webdav.cjs +0 -568
- package/dist/lib/webdav.d.cts +0 -109
- package/dist/lib/webdav.d.ts +0 -109
- package/dist/lib/webdav.js +0 -35
- package/hooks/clawvault/HOOK.md +0 -83
- package/hooks/clawvault/handler.js +0 -879
- package/hooks/clawvault/handler.test.js +0 -354
package/dist/cli/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
registerCliCommands
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-THRJVD4L.js";
|
|
5
|
-
import "../chunk-TIGW564L.js";
|
|
6
|
-
import "../chunk-IVRIKYFE.js";
|
|
3
|
+
} from "../chunk-YCUNCH2I.js";
|
|
7
4
|
import "../chunk-F2JEUD4J.js";
|
|
8
5
|
import "../chunk-P5EPF6MB.js";
|
|
9
6
|
import "../chunk-SJSFRIYS.js";
|
|
@@ -12,7 +9,7 @@ import "../chunk-LNJA2UGL.js";
|
|
|
12
9
|
import "../chunk-3NSBOUT3.js";
|
|
13
10
|
import "../chunk-62YTUT6J.js";
|
|
14
11
|
import "../chunk-HRLWZGMA.js";
|
|
15
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-OCGVIN3L.js";
|
|
16
13
|
import "../chunk-U55BGUAU.js";
|
|
17
14
|
import "../chunk-E7MFQB6D.js";
|
|
18
15
|
import "../chunk-ITPEXLHA.js";
|
|
@@ -22,9 +19,9 @@ import "../chunk-MXSSG3QU.js";
|
|
|
22
19
|
import "../chunk-N2AXRYLC.js";
|
|
23
20
|
import "../chunk-LYHGEHXG.js";
|
|
24
21
|
import "../chunk-7766SIJP.js";
|
|
25
|
-
import "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-
|
|
22
|
+
import "../chunk-3WRJEKN4.js";
|
|
23
|
+
import "../chunk-LI4O6NVK.js";
|
|
24
|
+
import "../chunk-D2H45LON.js";
|
|
28
25
|
import "../chunk-2CDEETQN.js";
|
|
29
26
|
import "../chunk-ZZA73MFY.js";
|
|
30
27
|
import "../chunk-QK3UCXWL.js";
|
package/dist/commands/compat.cjs
CHANGED
|
@@ -41,8 +41,6 @@ var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
|
41
41
|
var import_child_process = require("child_process");
|
|
42
42
|
var import_url = require("url");
|
|
43
43
|
var import_meta = {};
|
|
44
|
-
var REQUIRED_HOOK_EVENTS = ["gateway:startup", "command:new", "session:start"];
|
|
45
|
-
var REQUIRED_HOOK_BIN = "clawvault";
|
|
46
44
|
function readOptionalFile(filePath) {
|
|
47
45
|
try {
|
|
48
46
|
if (!fs.existsSync(filePath)) return null;
|
|
@@ -61,19 +59,6 @@ function findPackageRoot() {
|
|
|
61
59
|
}
|
|
62
60
|
return path.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
63
61
|
}
|
|
64
|
-
function resolveOpenClawHooksDir() {
|
|
65
|
-
const candidates = [
|
|
66
|
-
path.join(process.env.HOME || "", ".openclaw", "hooks", "clawvault"),
|
|
67
|
-
path.join(process.env.OPENCLAW_HOME || "", "hooks", "clawvault"),
|
|
68
|
-
path.join(process.env.OPENCLAW_STATE_DIR || "", "hooks", "clawvault")
|
|
69
|
-
].filter((p) => p && !p.startsWith(path.sep + "hooks"));
|
|
70
|
-
for (const candidate of candidates) {
|
|
71
|
-
if (fs.existsSync(candidate)) {
|
|
72
|
-
return candidate;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
62
|
function resolveProjectFile(relativePath, baseDir) {
|
|
78
63
|
if (baseDir) {
|
|
79
64
|
return path.resolve(baseDir, relativePath);
|
|
@@ -82,20 +67,6 @@ function resolveProjectFile(relativePath, baseDir) {
|
|
|
82
67
|
if (fs.existsSync(fromCwd)) {
|
|
83
68
|
return fromCwd;
|
|
84
69
|
}
|
|
85
|
-
if (relativePath.startsWith("hooks/clawvault/")) {
|
|
86
|
-
const hooksDir = resolveOpenClawHooksDir();
|
|
87
|
-
if (hooksDir) {
|
|
88
|
-
const hookRelative = relativePath.replace("hooks/clawvault/", "");
|
|
89
|
-
const fromHooks = path.resolve(hooksDir, hookRelative);
|
|
90
|
-
if (fs.existsSync(fromHooks)) {
|
|
91
|
-
return fromHooks;
|
|
92
|
-
}
|
|
93
|
-
const fromNestedHooks = path.resolve(hooksDir, "hooks", "clawvault", hookRelative);
|
|
94
|
-
if (fs.existsSync(fromNestedHooks)) {
|
|
95
|
-
return fromNestedHooks;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
70
|
return path.resolve(findPackageRoot(), relativePath);
|
|
100
71
|
}
|
|
101
72
|
function checkOpenClawCli() {
|
|
@@ -105,7 +76,7 @@ function checkOpenClawCli() {
|
|
|
105
76
|
label: "openclaw CLI available",
|
|
106
77
|
status: "warn",
|
|
107
78
|
detail: "openclaw binary not found",
|
|
108
|
-
hint: "Install OpenClaw CLI to enable
|
|
79
|
+
hint: "Install OpenClaw CLI to enable plugin runtime validation."
|
|
109
80
|
};
|
|
110
81
|
}
|
|
111
82
|
if (typeof result.status === "number" && result.status !== 0) {
|
|
@@ -126,152 +97,106 @@ function checkOpenClawCli() {
|
|
|
126
97
|
}
|
|
127
98
|
return { label: "openclaw CLI available", status: "ok" };
|
|
128
99
|
}
|
|
129
|
-
function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (!parsed.openclaw?.hooks) {
|
|
135
|
-
const fallbackPath = path.resolve(findPackageRoot(), "package.json");
|
|
136
|
-
const fallbackRaw = readOptionalFile(fallbackPath);
|
|
137
|
-
if (fallbackRaw) packageRaw = fallbackRaw;
|
|
138
|
-
}
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (!packageRaw) {
|
|
100
|
+
function checkPluginManifest(options) {
|
|
101
|
+
const manifestRaw = readOptionalFile(
|
|
102
|
+
resolveProjectFile("openclaw.plugin.json", options.baseDir)
|
|
103
|
+
);
|
|
104
|
+
if (!manifestRaw) {
|
|
143
105
|
return {
|
|
144
|
-
label: "
|
|
106
|
+
label: "plugin manifest",
|
|
145
107
|
status: "error",
|
|
146
|
-
detail: "
|
|
108
|
+
detail: "openclaw.plugin.json not found",
|
|
109
|
+
hint: "Create openclaw.plugin.json with id, kind, and configSchema fields."
|
|
147
110
|
};
|
|
148
111
|
}
|
|
149
112
|
try {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
113
|
+
const manifest = JSON.parse(manifestRaw);
|
|
114
|
+
const issues = [];
|
|
115
|
+
if (!manifest.id) issues.push("missing id");
|
|
116
|
+
if (!manifest.kind) issues.push("missing kind");
|
|
117
|
+
if (!manifest.configSchema) issues.push("missing configSchema");
|
|
118
|
+
if (issues.length > 0) {
|
|
153
119
|
return {
|
|
154
|
-
label: "
|
|
155
|
-
status: "
|
|
156
|
-
detail: "
|
|
120
|
+
label: "plugin manifest",
|
|
121
|
+
status: "error",
|
|
122
|
+
detail: issues.join(", ")
|
|
157
123
|
};
|
|
158
124
|
}
|
|
159
125
|
return {
|
|
160
|
-
label: "
|
|
161
|
-
status: "
|
|
162
|
-
detail:
|
|
126
|
+
label: "plugin manifest",
|
|
127
|
+
status: "ok",
|
|
128
|
+
detail: `id=${manifest.id} kind=${manifest.kind}`
|
|
163
129
|
};
|
|
164
130
|
} catch (err) {
|
|
165
131
|
return {
|
|
166
|
-
label: "
|
|
132
|
+
label: "plugin manifest",
|
|
167
133
|
status: "error",
|
|
168
|
-
detail: err?.message || "Unable to parse
|
|
134
|
+
detail: err?.message || "Unable to parse openclaw.plugin.json"
|
|
169
135
|
};
|
|
170
136
|
}
|
|
171
137
|
}
|
|
172
|
-
function
|
|
173
|
-
|
|
174
|
-
|
|
138
|
+
function checkPluginExtensions(options) {
|
|
139
|
+
let packageRaw = readOptionalFile(
|
|
140
|
+
resolveProjectFile("package.json", options.baseDir)
|
|
141
|
+
);
|
|
142
|
+
if (packageRaw && !options.baseDir) {
|
|
143
|
+
try {
|
|
144
|
+
const parsed = JSON.parse(packageRaw);
|
|
145
|
+
if (!parsed.openclaw?.extensions) {
|
|
146
|
+
const fallbackPath = path.resolve(findPackageRoot(), "package.json");
|
|
147
|
+
const fallbackRaw = readOptionalFile(fallbackPath);
|
|
148
|
+
if (fallbackRaw) packageRaw = fallbackRaw;
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!packageRaw) {
|
|
175
154
|
return {
|
|
176
|
-
label: "
|
|
155
|
+
label: "plugin extensions registration",
|
|
177
156
|
status: "error",
|
|
178
|
-
detail: "
|
|
157
|
+
detail: "package.json not found"
|
|
179
158
|
};
|
|
180
159
|
}
|
|
181
160
|
try {
|
|
182
|
-
const parsed =
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
const missingEvents = REQUIRED_HOOK_EVENTS.filter((event) => !events.includes(event));
|
|
186
|
-
if (missingEvents.length === 0) {
|
|
161
|
+
const parsed = JSON.parse(packageRaw);
|
|
162
|
+
const extensions = parsed.openclaw?.extensions ?? [];
|
|
163
|
+
if (extensions.length === 0) {
|
|
187
164
|
return {
|
|
188
|
-
label: "
|
|
189
|
-
status: "
|
|
190
|
-
detail:
|
|
165
|
+
label: "plugin extensions registration",
|
|
166
|
+
status: "error",
|
|
167
|
+
detail: "Missing openclaw.extensions in package.json",
|
|
168
|
+
hint: 'Add openclaw.extensions: ["./dist/plugin/index.js"] to package.json.'
|
|
191
169
|
};
|
|
192
170
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
} catch (err) {
|
|
199
|
-
return {
|
|
200
|
-
label: "hook manifest events",
|
|
201
|
-
status: "error",
|
|
202
|
-
detail: err?.message || "Unable to parse HOOK.md frontmatter"
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
function checkHookManifestRequirements(options) {
|
|
207
|
-
const hookRaw = readOptionalFile(resolveProjectFile("hooks/clawvault/HOOK.md", options.baseDir));
|
|
208
|
-
if (!hookRaw) {
|
|
209
|
-
return {
|
|
210
|
-
label: "hook manifest requirements",
|
|
211
|
-
status: "error",
|
|
212
|
-
detail: "HOOK.md not found"
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
try {
|
|
216
|
-
const parsed = (0, import_gray_matter.default)(hookRaw);
|
|
217
|
-
const requiresBins = parsed.data?.metadata?.openclaw?.requires?.bins;
|
|
218
|
-
const bins = Array.isArray(requiresBins) ? requiresBins : [];
|
|
219
|
-
if (bins.includes(REQUIRED_HOOK_BIN)) {
|
|
171
|
+
const baseDir = options.baseDir || findPackageRoot();
|
|
172
|
+
const missing = extensions.filter(
|
|
173
|
+
(ext) => !fs.existsSync(path.resolve(baseDir, ext))
|
|
174
|
+
);
|
|
175
|
+
if (missing.length > 0) {
|
|
220
176
|
return {
|
|
221
|
-
label: "
|
|
222
|
-
status: "
|
|
223
|
-
detail: `
|
|
177
|
+
label: "plugin extensions registration",
|
|
178
|
+
status: "error",
|
|
179
|
+
detail: `Entry file(s) not found: ${missing.join(", ")}`,
|
|
180
|
+
hint: "Run npm run build to generate dist files."
|
|
224
181
|
};
|
|
225
182
|
}
|
|
226
183
|
return {
|
|
227
|
-
label: "
|
|
228
|
-
status: "
|
|
229
|
-
detail:
|
|
230
|
-
hint: 'Add metadata.openclaw.requires.bins: ["clawvault"] to hooks/clawvault/HOOK.md.'
|
|
184
|
+
label: "plugin extensions registration",
|
|
185
|
+
status: "ok",
|
|
186
|
+
detail: extensions.join(", ")
|
|
231
187
|
};
|
|
232
188
|
} catch (err) {
|
|
233
189
|
return {
|
|
234
|
-
label: "
|
|
235
|
-
status: "error",
|
|
236
|
-
detail: err?.message || "Unable to parse HOOK.md frontmatter"
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function checkHookHandlerSafety(options) {
|
|
241
|
-
const handlerRaw = readOptionalFile(resolveProjectFile("hooks/clawvault/handler.js", options.baseDir));
|
|
242
|
-
if (!handlerRaw) {
|
|
243
|
-
return {
|
|
244
|
-
label: "hook handler script",
|
|
190
|
+
label: "plugin extensions registration",
|
|
245
191
|
status: "error",
|
|
246
|
-
detail: "
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
const usesExecFileSync = handlerRaw.includes("execFileSync");
|
|
250
|
-
const usesExecSync = /\bexecSync\b/.test(handlerRaw);
|
|
251
|
-
const enablesShell = /\bshell\s*:\s*true\b/.test(handlerRaw);
|
|
252
|
-
const delegatesAutoProfile = /['"]--profile['"]\s*,\s*['"]auto['"]/.test(handlerRaw);
|
|
253
|
-
const violations = [];
|
|
254
|
-
if (!usesExecFileSync || usesExecSync) {
|
|
255
|
-
violations.push("execFileSync-only execution path");
|
|
256
|
-
}
|
|
257
|
-
if (enablesShell) {
|
|
258
|
-
violations.push("shell:false execution option");
|
|
259
|
-
}
|
|
260
|
-
if (!delegatesAutoProfile) {
|
|
261
|
-
violations.push("shared context profile delegation (--profile auto)");
|
|
262
|
-
}
|
|
263
|
-
if (violations.length > 0) {
|
|
264
|
-
return {
|
|
265
|
-
label: "hook handler safety",
|
|
266
|
-
status: "warn",
|
|
267
|
-
detail: `Missing conventions: ${violations.join(", ")}`,
|
|
268
|
-
hint: "Use execFileSync (no shell), avoid execSync, and delegate profile inference via --profile auto."
|
|
192
|
+
detail: err?.message || "Unable to parse package.json"
|
|
269
193
|
};
|
|
270
194
|
}
|
|
271
|
-
return { label: "hook handler safety", status: "ok" };
|
|
272
195
|
}
|
|
273
196
|
function checkSkillMetadata(options) {
|
|
274
|
-
const skillRaw = readOptionalFile(
|
|
197
|
+
const skillRaw = readOptionalFile(
|
|
198
|
+
resolveProjectFile("SKILL.md", options.baseDir)
|
|
199
|
+
);
|
|
275
200
|
if (!skillRaw) {
|
|
276
201
|
return {
|
|
277
202
|
label: "skill metadata",
|
|
@@ -310,10 +235,8 @@ function checkSkillMetadata(options) {
|
|
|
310
235
|
function checkOpenClawCompatibility(options = {}) {
|
|
311
236
|
const checks = [
|
|
312
237
|
checkOpenClawCli(),
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
checkHookManifestRequirements(options),
|
|
316
|
-
checkHookHandlerSafety(options),
|
|
238
|
+
checkPluginManifest(options),
|
|
239
|
+
checkPluginExtensions(options),
|
|
317
240
|
checkSkillMetadata(options)
|
|
318
241
|
];
|
|
319
242
|
const warnings = checks.filter((check) => check.status === "warn").length;
|
|
@@ -333,7 +256,9 @@ function formatCompatibilityReport(report) {
|
|
|
333
256
|
lines.push("");
|
|
334
257
|
for (const check of report.checks) {
|
|
335
258
|
const prefix = check.status === "ok" ? "\u2713" : check.status === "warn" ? "\u26A0" : "\u2717";
|
|
336
|
-
lines.push(
|
|
259
|
+
lines.push(
|
|
260
|
+
`${prefix} ${check.label}${check.detail ? ` \u2014 ${check.detail}` : ""}`
|
|
261
|
+
);
|
|
337
262
|
if (check.hint) {
|
|
338
263
|
lines.push(` ${check.hint}`);
|
|
339
264
|
}
|
package/dist/commands/compat.js
CHANGED
|
@@ -354,6 +354,7 @@ function stripQmdNoise(raw) {
|
|
|
354
354
|
function parseQmdOutput(raw) {
|
|
355
355
|
const trimmed = stripQmdNoise(raw).trim();
|
|
356
356
|
if (!trimmed) return [];
|
|
357
|
+
if (trimmed.startsWith("No results") || trimmed.startsWith("No matches")) return [];
|
|
357
358
|
const direct = tryParseJson(trimmed);
|
|
358
359
|
const extracted = direct ? null : extractJsonPayload(trimmed);
|
|
359
360
|
const parsed = direct ?? (extracted ? tryParseJson(extracted) : null);
|
package/dist/commands/context.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
contextCommand,
|
|
4
4
|
formatContextMarkdown,
|
|
5
5
|
registerContextCommand
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-3WRJEKN4.js";
|
|
7
|
+
import "../chunk-LI4O6NVK.js";
|
|
8
|
+
import "../chunk-D2H45LON.js";
|
|
9
9
|
import "../chunk-2CDEETQN.js";
|
|
10
10
|
import "../chunk-ZZA73MFY.js";
|
|
11
11
|
import "../chunk-QK3UCXWL.js";
|
package/dist/commands/doctor.cjs
CHANGED
|
@@ -145,6 +145,7 @@ function stripQmdNoise(raw) {
|
|
|
145
145
|
function parseQmdOutput(raw) {
|
|
146
146
|
const trimmed = stripQmdNoise(raw).trim();
|
|
147
147
|
if (!trimmed) return [];
|
|
148
|
+
if (trimmed.startsWith("No results") || trimmed.startsWith("No matches")) return [];
|
|
148
149
|
const direct = tryParseJson(trimmed);
|
|
149
150
|
const extracted = direct ? null : extractJsonPayload(trimmed);
|
|
150
151
|
const parsed = direct ?? (extracted ? tryParseJson(extracted) : null);
|
|
@@ -2466,8 +2467,6 @@ var import_gray_matter7 = __toESM(require("gray-matter"), 1);
|
|
|
2466
2467
|
var import_child_process2 = require("child_process");
|
|
2467
2468
|
var import_url2 = require("url");
|
|
2468
2469
|
var import_meta2 = {};
|
|
2469
|
-
var REQUIRED_HOOK_EVENTS = ["gateway:startup", "command:new", "session:start"];
|
|
2470
|
-
var REQUIRED_HOOK_BIN = "clawvault";
|
|
2471
2470
|
function readOptionalFile(filePath) {
|
|
2472
2471
|
try {
|
|
2473
2472
|
if (!fs7.existsSync(filePath)) return null;
|
|
@@ -2486,19 +2485,6 @@ function findPackageRoot() {
|
|
|
2486
2485
|
}
|
|
2487
2486
|
return path8.dirname((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
2488
2487
|
}
|
|
2489
|
-
function resolveOpenClawHooksDir() {
|
|
2490
|
-
const candidates = [
|
|
2491
|
-
path8.join(process.env.HOME || "", ".openclaw", "hooks", "clawvault"),
|
|
2492
|
-
path8.join(process.env.OPENCLAW_HOME || "", "hooks", "clawvault"),
|
|
2493
|
-
path8.join(process.env.OPENCLAW_STATE_DIR || "", "hooks", "clawvault")
|
|
2494
|
-
].filter((p) => p && !p.startsWith(path8.sep + "hooks"));
|
|
2495
|
-
for (const candidate of candidates) {
|
|
2496
|
-
if (fs7.existsSync(candidate)) {
|
|
2497
|
-
return candidate;
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
return null;
|
|
2501
|
-
}
|
|
2502
2488
|
function resolveProjectFile(relativePath, baseDir) {
|
|
2503
2489
|
if (baseDir) {
|
|
2504
2490
|
return path8.resolve(baseDir, relativePath);
|
|
@@ -2507,20 +2493,6 @@ function resolveProjectFile(relativePath, baseDir) {
|
|
|
2507
2493
|
if (fs7.existsSync(fromCwd)) {
|
|
2508
2494
|
return fromCwd;
|
|
2509
2495
|
}
|
|
2510
|
-
if (relativePath.startsWith("hooks/clawvault/")) {
|
|
2511
|
-
const hooksDir = resolveOpenClawHooksDir();
|
|
2512
|
-
if (hooksDir) {
|
|
2513
|
-
const hookRelative = relativePath.replace("hooks/clawvault/", "");
|
|
2514
|
-
const fromHooks = path8.resolve(hooksDir, hookRelative);
|
|
2515
|
-
if (fs7.existsSync(fromHooks)) {
|
|
2516
|
-
return fromHooks;
|
|
2517
|
-
}
|
|
2518
|
-
const fromNestedHooks = path8.resolve(hooksDir, "hooks", "clawvault", hookRelative);
|
|
2519
|
-
if (fs7.existsSync(fromNestedHooks)) {
|
|
2520
|
-
return fromNestedHooks;
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
2496
|
return path8.resolve(findPackageRoot(), relativePath);
|
|
2525
2497
|
}
|
|
2526
2498
|
function checkOpenClawCli() {
|
|
@@ -2530,7 +2502,7 @@ function checkOpenClawCli() {
|
|
|
2530
2502
|
label: "openclaw CLI available",
|
|
2531
2503
|
status: "warn",
|
|
2532
2504
|
detail: "openclaw binary not found",
|
|
2533
|
-
hint: "Install OpenClaw CLI to enable
|
|
2505
|
+
hint: "Install OpenClaw CLI to enable plugin runtime validation."
|
|
2534
2506
|
};
|
|
2535
2507
|
}
|
|
2536
2508
|
if (typeof result.status === "number" && result.status !== 0) {
|
|
@@ -2551,152 +2523,106 @@ function checkOpenClawCli() {
|
|
|
2551
2523
|
}
|
|
2552
2524
|
return { label: "openclaw CLI available", status: "ok" };
|
|
2553
2525
|
}
|
|
2554
|
-
function
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
if (!parsed.openclaw?.hooks) {
|
|
2560
|
-
const fallbackPath = path8.resolve(findPackageRoot(), "package.json");
|
|
2561
|
-
const fallbackRaw = readOptionalFile(fallbackPath);
|
|
2562
|
-
if (fallbackRaw) packageRaw = fallbackRaw;
|
|
2563
|
-
}
|
|
2564
|
-
} catch {
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
if (!packageRaw) {
|
|
2526
|
+
function checkPluginManifest(options) {
|
|
2527
|
+
const manifestRaw = readOptionalFile(
|
|
2528
|
+
resolveProjectFile("openclaw.plugin.json", options.baseDir)
|
|
2529
|
+
);
|
|
2530
|
+
if (!manifestRaw) {
|
|
2568
2531
|
return {
|
|
2569
|
-
label: "
|
|
2532
|
+
label: "plugin manifest",
|
|
2570
2533
|
status: "error",
|
|
2571
|
-
detail: "
|
|
2534
|
+
detail: "openclaw.plugin.json not found",
|
|
2535
|
+
hint: "Create openclaw.plugin.json with id, kind, and configSchema fields."
|
|
2572
2536
|
};
|
|
2573
2537
|
}
|
|
2574
2538
|
try {
|
|
2575
|
-
const
|
|
2576
|
-
const
|
|
2577
|
-
if (
|
|
2539
|
+
const manifest = JSON.parse(manifestRaw);
|
|
2540
|
+
const issues = [];
|
|
2541
|
+
if (!manifest.id) issues.push("missing id");
|
|
2542
|
+
if (!manifest.kind) issues.push("missing kind");
|
|
2543
|
+
if (!manifest.configSchema) issues.push("missing configSchema");
|
|
2544
|
+
if (issues.length > 0) {
|
|
2578
2545
|
return {
|
|
2579
|
-
label: "
|
|
2580
|
-
status: "
|
|
2581
|
-
detail: "
|
|
2546
|
+
label: "plugin manifest",
|
|
2547
|
+
status: "error",
|
|
2548
|
+
detail: issues.join(", ")
|
|
2582
2549
|
};
|
|
2583
2550
|
}
|
|
2584
2551
|
return {
|
|
2585
|
-
label: "
|
|
2586
|
-
status: "
|
|
2587
|
-
detail:
|
|
2552
|
+
label: "plugin manifest",
|
|
2553
|
+
status: "ok",
|
|
2554
|
+
detail: `id=${manifest.id} kind=${manifest.kind}`
|
|
2588
2555
|
};
|
|
2589
2556
|
} catch (err) {
|
|
2590
2557
|
return {
|
|
2591
|
-
label: "
|
|
2558
|
+
label: "plugin manifest",
|
|
2592
2559
|
status: "error",
|
|
2593
|
-
detail: err?.message || "Unable to parse
|
|
2560
|
+
detail: err?.message || "Unable to parse openclaw.plugin.json"
|
|
2594
2561
|
};
|
|
2595
2562
|
}
|
|
2596
2563
|
}
|
|
2597
|
-
function
|
|
2598
|
-
|
|
2599
|
-
|
|
2564
|
+
function checkPluginExtensions(options) {
|
|
2565
|
+
let packageRaw = readOptionalFile(
|
|
2566
|
+
resolveProjectFile("package.json", options.baseDir)
|
|
2567
|
+
);
|
|
2568
|
+
if (packageRaw && !options.baseDir) {
|
|
2569
|
+
try {
|
|
2570
|
+
const parsed = JSON.parse(packageRaw);
|
|
2571
|
+
if (!parsed.openclaw?.extensions) {
|
|
2572
|
+
const fallbackPath = path8.resolve(findPackageRoot(), "package.json");
|
|
2573
|
+
const fallbackRaw = readOptionalFile(fallbackPath);
|
|
2574
|
+
if (fallbackRaw) packageRaw = fallbackRaw;
|
|
2575
|
+
}
|
|
2576
|
+
} catch {
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
if (!packageRaw) {
|
|
2600
2580
|
return {
|
|
2601
|
-
label: "
|
|
2581
|
+
label: "plugin extensions registration",
|
|
2602
2582
|
status: "error",
|
|
2603
|
-
detail: "
|
|
2583
|
+
detail: "package.json not found"
|
|
2604
2584
|
};
|
|
2605
2585
|
}
|
|
2606
2586
|
try {
|
|
2607
|
-
const parsed =
|
|
2608
|
-
const
|
|
2609
|
-
|
|
2610
|
-
const missingEvents = REQUIRED_HOOK_EVENTS.filter((event) => !events.includes(event));
|
|
2611
|
-
if (missingEvents.length === 0) {
|
|
2587
|
+
const parsed = JSON.parse(packageRaw);
|
|
2588
|
+
const extensions = parsed.openclaw?.extensions ?? [];
|
|
2589
|
+
if (extensions.length === 0) {
|
|
2612
2590
|
return {
|
|
2613
|
-
label: "
|
|
2614
|
-
status: "
|
|
2615
|
-
detail:
|
|
2591
|
+
label: "plugin extensions registration",
|
|
2592
|
+
status: "error",
|
|
2593
|
+
detail: "Missing openclaw.extensions in package.json",
|
|
2594
|
+
hint: 'Add openclaw.extensions: ["./dist/plugin/index.js"] to package.json.'
|
|
2616
2595
|
};
|
|
2617
2596
|
}
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
} catch (err) {
|
|
2624
|
-
return {
|
|
2625
|
-
label: "hook manifest events",
|
|
2626
|
-
status: "error",
|
|
2627
|
-
detail: err?.message || "Unable to parse HOOK.md frontmatter"
|
|
2628
|
-
};
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
function checkHookManifestRequirements(options) {
|
|
2632
|
-
const hookRaw = readOptionalFile(resolveProjectFile("hooks/clawvault/HOOK.md", options.baseDir));
|
|
2633
|
-
if (!hookRaw) {
|
|
2634
|
-
return {
|
|
2635
|
-
label: "hook manifest requirements",
|
|
2636
|
-
status: "error",
|
|
2637
|
-
detail: "HOOK.md not found"
|
|
2638
|
-
};
|
|
2639
|
-
}
|
|
2640
|
-
try {
|
|
2641
|
-
const parsed = (0, import_gray_matter7.default)(hookRaw);
|
|
2642
|
-
const requiresBins = parsed.data?.metadata?.openclaw?.requires?.bins;
|
|
2643
|
-
const bins = Array.isArray(requiresBins) ? requiresBins : [];
|
|
2644
|
-
if (bins.includes(REQUIRED_HOOK_BIN)) {
|
|
2597
|
+
const baseDir = options.baseDir || findPackageRoot();
|
|
2598
|
+
const missing = extensions.filter(
|
|
2599
|
+
(ext) => !fs7.existsSync(path8.resolve(baseDir, ext))
|
|
2600
|
+
);
|
|
2601
|
+
if (missing.length > 0) {
|
|
2645
2602
|
return {
|
|
2646
|
-
label: "
|
|
2647
|
-
status: "
|
|
2648
|
-
detail: `
|
|
2603
|
+
label: "plugin extensions registration",
|
|
2604
|
+
status: "error",
|
|
2605
|
+
detail: `Entry file(s) not found: ${missing.join(", ")}`,
|
|
2606
|
+
hint: "Run npm run build to generate dist files."
|
|
2649
2607
|
};
|
|
2650
2608
|
}
|
|
2651
2609
|
return {
|
|
2652
|
-
label: "
|
|
2653
|
-
status: "
|
|
2654
|
-
detail:
|
|
2655
|
-
hint: 'Add metadata.openclaw.requires.bins: ["clawvault"] to hooks/clawvault/HOOK.md.'
|
|
2610
|
+
label: "plugin extensions registration",
|
|
2611
|
+
status: "ok",
|
|
2612
|
+
detail: extensions.join(", ")
|
|
2656
2613
|
};
|
|
2657
2614
|
} catch (err) {
|
|
2658
2615
|
return {
|
|
2659
|
-
label: "
|
|
2660
|
-
status: "error",
|
|
2661
|
-
detail: err?.message || "Unable to parse HOOK.md frontmatter"
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
function checkHookHandlerSafety(options) {
|
|
2666
|
-
const handlerRaw = readOptionalFile(resolveProjectFile("hooks/clawvault/handler.js", options.baseDir));
|
|
2667
|
-
if (!handlerRaw) {
|
|
2668
|
-
return {
|
|
2669
|
-
label: "hook handler script",
|
|
2616
|
+
label: "plugin extensions registration",
|
|
2670
2617
|
status: "error",
|
|
2671
|
-
detail: "
|
|
2672
|
-
};
|
|
2673
|
-
}
|
|
2674
|
-
const usesExecFileSync = handlerRaw.includes("execFileSync");
|
|
2675
|
-
const usesExecSync = /\bexecSync\b/.test(handlerRaw);
|
|
2676
|
-
const enablesShell = /\bshell\s*:\s*true\b/.test(handlerRaw);
|
|
2677
|
-
const delegatesAutoProfile = /['"]--profile['"]\s*,\s*['"]auto['"]/.test(handlerRaw);
|
|
2678
|
-
const violations = [];
|
|
2679
|
-
if (!usesExecFileSync || usesExecSync) {
|
|
2680
|
-
violations.push("execFileSync-only execution path");
|
|
2681
|
-
}
|
|
2682
|
-
if (enablesShell) {
|
|
2683
|
-
violations.push("shell:false execution option");
|
|
2684
|
-
}
|
|
2685
|
-
if (!delegatesAutoProfile) {
|
|
2686
|
-
violations.push("shared context profile delegation (--profile auto)");
|
|
2687
|
-
}
|
|
2688
|
-
if (violations.length > 0) {
|
|
2689
|
-
return {
|
|
2690
|
-
label: "hook handler safety",
|
|
2691
|
-
status: "warn",
|
|
2692
|
-
detail: `Missing conventions: ${violations.join(", ")}`,
|
|
2693
|
-
hint: "Use execFileSync (no shell), avoid execSync, and delegate profile inference via --profile auto."
|
|
2618
|
+
detail: err?.message || "Unable to parse package.json"
|
|
2694
2619
|
};
|
|
2695
2620
|
}
|
|
2696
|
-
return { label: "hook handler safety", status: "ok" };
|
|
2697
2621
|
}
|
|
2698
2622
|
function checkSkillMetadata(options) {
|
|
2699
|
-
const skillRaw = readOptionalFile(
|
|
2623
|
+
const skillRaw = readOptionalFile(
|
|
2624
|
+
resolveProjectFile("SKILL.md", options.baseDir)
|
|
2625
|
+
);
|
|
2700
2626
|
if (!skillRaw) {
|
|
2701
2627
|
return {
|
|
2702
2628
|
label: "skill metadata",
|
|
@@ -2735,10 +2661,8 @@ function checkSkillMetadata(options) {
|
|
|
2735
2661
|
function checkOpenClawCompatibility(options = {}) {
|
|
2736
2662
|
const checks = [
|
|
2737
2663
|
checkOpenClawCli(),
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
checkHookManifestRequirements(options),
|
|
2741
|
-
checkHookHandlerSafety(options),
|
|
2664
|
+
checkPluginManifest(options),
|
|
2665
|
+
checkPluginExtensions(options),
|
|
2742
2666
|
checkSkillMetadata(options)
|
|
2743
2667
|
];
|
|
2744
2668
|
const warnings = checks.filter((check) => check.status === "warn").length;
|