@openclaw/plugin-inspector 0.3.4 → 0.3.6
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/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/src/advanced.js +5 -0
- package/src/api.js +4 -0
- package/src/artifacts.js +1 -1
- package/src/ci-policy.js +3 -1
- package/src/ci-summary.js +50 -3
- package/src/compatibility-report.js +39 -3
- package/src/config.js +35 -5
- package/src/contract-capture.js +1 -0
- package/src/contract-probes.js +25 -0
- package/src/fixture-summary.js +406 -0
- package/src/import-loop-profile.js +262 -8
- package/src/index.js +7 -0
- package/src/inspector.js +49 -4
- package/src/issues.js +66 -1
- package/src/openclaw-target.js +79 -2
- package/src/platform-probes.js +29 -6
- package/src/process-profile.js +40 -19
- package/src/prune-workspace-dev-deps-cli.js +23 -0
- package/src/report.js +19 -1
- package/src/runtime-profile.js +67 -15
- package/src/runtime-reconciliation.js +124 -0
- package/src/sdk-mock.js +64 -6
- package/src/synthetic-probes.js +51 -0
- package/src/workspace-plan.js +19 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.6 - 2026-05-03
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Report import-loop RSS and CPU as baseline-adjusted plugin deltas alongside raw subprocess metrics so Crabpot dashboards do not treat harness import cost as plugin runtime cost.
|
|
10
|
+
- Include optional OpenClaw loader lifecycle timings for import and full activation when a capture runner provides them.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Accept plugin install minimum-host floors as supported package metadata.
|
|
15
|
+
- Flag unsupported legacy OpenClaw bundle metadata and advertised npm pack blockers.
|
|
16
|
+
- Reconcile runtime capture evidence and harden mocked capture paths for downstream fixture reports.
|
|
17
|
+
|
|
18
|
+
## 0.3.5 - 2026-04-29
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Add immediate/faster subprocess RSS and CPU sampling plus explicit sample counts so short import-loop reports do not silently publish fake zero-memory metrics.
|
|
23
|
+
- Classify `createChatChannelPlugin` as channel factory metadata in synthetic probe plans so channel-core plugins do not fail as unknown registrars.
|
|
24
|
+
- Treat `createChatChannelPlugin` and `defineChannelPluginEntry` as channel registration equivalents when validating fixture expectations.
|
|
25
|
+
- Label runtime profile wall-time summaries as command-median p95 and render missing sampled metrics as `n/a`.
|
|
26
|
+
|
|
5
27
|
## 0.3.4 - 2026-04-29
|
|
6
28
|
|
|
7
29
|
### Fixed
|
package/package.json
CHANGED
package/src/advanced.js
CHANGED
|
@@ -95,6 +95,7 @@ export {
|
|
|
95
95
|
classifyTargetOpenClawCoverage,
|
|
96
96
|
readPackageSummaries,
|
|
97
97
|
readPluginManifests,
|
|
98
|
+
readSecurityManifests,
|
|
98
99
|
summarizePackage,
|
|
99
100
|
} from "./fixture-summary.js";
|
|
100
101
|
export {
|
|
@@ -183,6 +184,10 @@ export {
|
|
|
183
184
|
validateRuntimeProfile,
|
|
184
185
|
writeRuntimeProfile,
|
|
185
186
|
} from "./runtime-profile.js";
|
|
187
|
+
export {
|
|
188
|
+
applyRuntimeExecutionCoverage,
|
|
189
|
+
buildRuntimeExecutionCoverage,
|
|
190
|
+
} from "./runtime-reconciliation.js";
|
|
186
191
|
export {
|
|
187
192
|
buildRuntimeCaptureReport,
|
|
188
193
|
renderRuntimeCaptureMarkdown,
|
package/src/api.js
CHANGED
|
@@ -45,6 +45,7 @@ export async function inspectPluginRoot(options = {}) {
|
|
|
45
45
|
return inspectCompatibilityFixtureSet(config, {
|
|
46
46
|
generatedAt: options.generatedAt,
|
|
47
47
|
openclawPath: options.openclawPath,
|
|
48
|
+
executionResults: options.executionResults,
|
|
48
49
|
targetOpenClaw: options.targetOpenClaw,
|
|
49
50
|
});
|
|
50
51
|
}
|
|
@@ -59,6 +60,7 @@ export async function inspectCompatibilityFixtureSetConfig(options = {}) {
|
|
|
59
60
|
return inspectCompatibilityFixtureSet(config, {
|
|
60
61
|
generatedAt: options.generatedAt,
|
|
61
62
|
openclawPath: options.openclawPath,
|
|
63
|
+
executionResults: options.executionResults,
|
|
62
64
|
targetOpenClaw: options.targetOpenClaw,
|
|
63
65
|
});
|
|
64
66
|
}
|
|
@@ -112,6 +114,7 @@ export async function buildFixtureSetColdImportReadiness(options = {}) {
|
|
|
112
114
|
(await inspectCompatibilityFixtureSet(config, {
|
|
113
115
|
generatedAt: options.generatedAt,
|
|
114
116
|
openclawPath: options.openclawPath,
|
|
117
|
+
executionResults: options.executionResults,
|
|
115
118
|
targetOpenClaw: options.targetOpenClaw,
|
|
116
119
|
}));
|
|
117
120
|
|
|
@@ -143,6 +146,7 @@ export async function buildFixtureSetWorkspacePlan(options = {}) {
|
|
|
143
146
|
(await inspectCompatibilityFixtureSet(config, {
|
|
144
147
|
generatedAt: options.generatedAt,
|
|
145
148
|
openclawPath: options.openclawPath,
|
|
149
|
+
executionResults: options.executionResults,
|
|
146
150
|
targetOpenClaw: options.targetOpenClaw,
|
|
147
151
|
}));
|
|
148
152
|
const rootDir = options.rootDir ?? config?.rootDir ?? options.cwd;
|
package/src/artifacts.js
CHANGED
|
@@ -95,7 +95,7 @@ export function renderPaddedMarkdownTable(rows, headers, options = {}) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export function escapeMarkdownTableCell(value) {
|
|
98
|
-
return value.replace(/\|/g, "\\|").replace(/\n/g, "<br>");
|
|
98
|
+
return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\n/g, "<br>");
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
async function assertFileMatches(filePath, expected) {
|
package/src/ci-policy.js
CHANGED
|
@@ -241,7 +241,9 @@ function executionChecks(executionResults, policy, options) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
function findPolicyMatch(rules, item) {
|
|
244
|
-
return rules.find(
|
|
244
|
+
return rules.find(
|
|
245
|
+
(rule) => (rule.seam === "*" || item.seam === rule.seam) && item.reason?.includes(rule.reasonIncludes),
|
|
246
|
+
);
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
function failedExecutionEvidence(executionResults) {
|
package/src/ci-summary.js
CHANGED
|
@@ -56,8 +56,14 @@ export async function buildCiSummary(options = {}) {
|
|
|
56
56
|
loaderJitiCandidates: reports.platform?.summary?.jitiAlternativeCount ?? 0,
|
|
57
57
|
importLoopP50Ms: reports.importLoop?.summary?.p50WallMs ?? 0,
|
|
58
58
|
importLoopP95Ms: reports.importLoop?.summary?.p95WallMs ?? 0,
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
importLoopOpenClawLifecycleCount: reports.importLoop?.summary?.openClawLifecycleCount ?? 0,
|
|
60
|
+
importLoopOpenClawImportP50Ms: reports.importLoop?.summary?.p50OpenClawImportMs ?? 0,
|
|
61
|
+
importLoopOpenClawActivationP50Ms: reports.importLoop?.summary?.p50OpenClawActivationMs ?? 0,
|
|
62
|
+
importLoopMetricBasis: reports.importLoop?.summary?.maxPluginPeakRssDeltaMb === undefined ? "raw" : "baseline-adjusted",
|
|
63
|
+
importLoopMaxRssMb: reports.importLoop?.summary?.maxPluginPeakRssDeltaMb ?? reports.importLoop?.summary?.maxPeakRssMb ?? 0,
|
|
64
|
+
importLoopMaxCpuMs: reports.importLoop?.summary?.maxPluginCpuDeltaMsEstimate ?? reports.importLoop?.summary?.maxCpuMsEstimate ?? 0,
|
|
65
|
+
importLoopRssSampleCount: metricSampleCount(reports.importLoop, "rss", "maxPeakRssMb"),
|
|
66
|
+
importLoopCpuSampleCount: metricSampleCount(reports.importLoop, "cpu", "maxCpuMsEstimate"),
|
|
61
67
|
},
|
|
62
68
|
topIssues: topIssues(reports.compatibility),
|
|
63
69
|
refRegressions: (reports.refDiff?.regressions ?? []).slice(0, 20),
|
|
@@ -148,7 +154,7 @@ export function renderCiSummaryMarkdown(summary) {
|
|
|
148
154
|
["Jiti loader candidates", summary.summary.loaderJitiCandidates],
|
|
149
155
|
[
|
|
150
156
|
"Import loop",
|
|
151
|
-
|
|
157
|
+
importLoopSummaryLabel(summary.summary),
|
|
152
158
|
],
|
|
153
159
|
],
|
|
154
160
|
["Metric", "Value"],
|
|
@@ -221,3 +227,44 @@ function topIssues(report) {
|
|
|
221
227
|
function markdownTable(rows, headers) {
|
|
222
228
|
return renderPaddedMarkdownTable(rows, headers, { nullValue: "-" });
|
|
223
229
|
}
|
|
230
|
+
|
|
231
|
+
function metricSampleCount(report, kind, maxMetric) {
|
|
232
|
+
const summaryKey = kind === "rss" ? "rssSampleCount" : "cpuSampleCount";
|
|
233
|
+
const summaryCount = report?.summary?.[summaryKey];
|
|
234
|
+
if (Number.isFinite(summaryCount)) {
|
|
235
|
+
return summaryCount;
|
|
236
|
+
}
|
|
237
|
+
const sampleCount = inferSampleCount(report?.samples, kind);
|
|
238
|
+
if (sampleCount > 0) {
|
|
239
|
+
return sampleCount;
|
|
240
|
+
}
|
|
241
|
+
return (report?.summary?.[maxMetric] ?? 0) > 0 ? 1 : 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function inferSampleCount(samples = [], kind) {
|
|
245
|
+
if (!Array.isArray(samples)) {
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
return samples.reduce((sum, sample) => {
|
|
249
|
+
if (kind === "rss") {
|
|
250
|
+
return sum + (sample.rssSampleCount ?? (sample.peakRssMb > 0 ? 1 : 0));
|
|
251
|
+
}
|
|
252
|
+
return sum + (sample.cpuSampleCount ?? 0);
|
|
253
|
+
}, 0);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function importLoopSummaryLabel(summary) {
|
|
257
|
+
const metricLabel = summary.importLoopMetricBasis === "baseline-adjusted" ? "plugin delta" : "raw";
|
|
258
|
+
const lifecycle =
|
|
259
|
+
summary.importLoopOpenClawLifecycleCount > 0
|
|
260
|
+
? ` / OpenClaw import ${summary.importLoopOpenClawImportP50Ms} ms / activate ${summary.importLoopOpenClawActivationP50Ms} ms`
|
|
261
|
+
: "";
|
|
262
|
+
return `p50 ${summary.importLoopP50Ms} ms / p95 ${summary.importLoopP95Ms} ms / ${metricLabel} RSS ${formatSampledMetric(summary.importLoopMaxRssMb, summary.importLoopRssSampleCount)} / ${metricLabel} CPU ${formatSampledMetric(summary.importLoopMaxCpuMs, summary.importLoopCpuSampleCount, "ms")}${lifecycle}`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function formatSampledMetric(value, count, unit = "MB") {
|
|
266
|
+
if ((count ?? 0) <= 0) {
|
|
267
|
+
return "n/a";
|
|
268
|
+
}
|
|
269
|
+
return `${value} ${unit}`;
|
|
270
|
+
}
|
|
@@ -26,13 +26,20 @@ export function renderCompatibilityMarkdownReport(report, options = {}) {
|
|
|
26
26
|
["Warnings", report.summary.warningCount],
|
|
27
27
|
["Compatibility suggestions", report.summary.suggestionCount],
|
|
28
28
|
["Issue findings", report.summary.issueCount],
|
|
29
|
+
["Open issue findings", report.summary.openIssueCount ?? report.summary.issueCount],
|
|
30
|
+
["Runtime-covered findings", report.summary.runtimeCoveredIssueCount ?? 0],
|
|
31
|
+
["Runtime-partial findings", report.summary.runtimePartiallyCoveredIssueCount ?? 0],
|
|
29
32
|
["P0 issues", report.summary.p0IssueCount],
|
|
30
33
|
["P1 issues", report.summary.p1IssueCount],
|
|
34
|
+
["Open P0 issues", report.summary.openP0IssueCount ?? report.summary.p0IssueCount],
|
|
35
|
+
["Open P1 issues", report.summary.openP1IssueCount ?? report.summary.p1IssueCount],
|
|
31
36
|
["Live issues", report.summary.liveIssueCount],
|
|
32
37
|
["Live P0 issues", report.summary.liveP0IssueCount],
|
|
33
38
|
["Compat gaps", report.summary.compatGapCount],
|
|
34
39
|
["Deprecation warnings", report.summary.deprecationWarningCount],
|
|
35
40
|
["Inspector gaps", report.summary.inspectorGapCount],
|
|
41
|
+
["Open inspector gaps", report.summary.openInspectorGapCount ?? report.summary.inspectorGapCount],
|
|
42
|
+
["Runtime coverage artifacts", report.summary.runtimeCoverageArtifactCount ?? 0],
|
|
36
43
|
["Upstream metadata", report.summary.upstreamIssueCount],
|
|
37
44
|
["Contract probes", report.summary.contractProbeCount],
|
|
38
45
|
["Decision rows", report.summary.decisionCount],
|
|
@@ -65,7 +72,11 @@ export function renderCompatibilityMarkdownReport(report, options = {}) {
|
|
|
65
72
|
"",
|
|
66
73
|
"## Inspector Proof Gaps",
|
|
67
74
|
"",
|
|
68
|
-
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap"), options),
|
|
75
|
+
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap" && issue.status !== "runtime-covered"), options),
|
|
76
|
+
"",
|
|
77
|
+
"## Runtime-Covered Inspector Gaps",
|
|
78
|
+
"",
|
|
79
|
+
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap" && issue.status === "runtime-covered"), options),
|
|
69
80
|
"",
|
|
70
81
|
"## Upstream Metadata Issues",
|
|
71
82
|
"",
|
|
@@ -141,13 +152,20 @@ export function renderCompatibilityIssuesReport(report, options = {}) {
|
|
|
141
152
|
markdownTable(
|
|
142
153
|
[
|
|
143
154
|
["Issue findings", report.summary.issueCount],
|
|
155
|
+
["Open issue findings", report.summary.openIssueCount ?? report.summary.issueCount],
|
|
156
|
+
["Runtime-covered findings", report.summary.runtimeCoveredIssueCount ?? 0],
|
|
157
|
+
["Runtime-partial findings", report.summary.runtimePartiallyCoveredIssueCount ?? 0],
|
|
144
158
|
[severityLabel("P0", options), report.summary.p0IssueCount],
|
|
145
159
|
[severityLabel("P1", options), report.summary.p1IssueCount],
|
|
160
|
+
[`Open ${severityLabel("P0", options)}`, report.summary.openP0IssueCount ?? report.summary.p0IssueCount],
|
|
161
|
+
[`Open ${severityLabel("P1", options)}`, report.summary.openP1IssueCount ?? report.summary.p1IssueCount],
|
|
146
162
|
["Live issues", report.summary.liveIssueCount],
|
|
147
163
|
["Live P0 issues", report.summary.liveP0IssueCount],
|
|
148
164
|
["Compat gaps", report.summary.compatGapCount],
|
|
149
165
|
["Deprecation warnings", report.summary.deprecationWarningCount],
|
|
150
166
|
["Inspector gaps", report.summary.inspectorGapCount],
|
|
167
|
+
["Open inspector gaps", report.summary.openInspectorGapCount ?? report.summary.inspectorGapCount],
|
|
168
|
+
["Runtime coverage artifacts", report.summary.runtimeCoverageArtifactCount ?? 0],
|
|
151
169
|
["Upstream metadata", report.summary.upstreamIssueCount],
|
|
152
170
|
["Contract probes", report.summary.contractProbeCount],
|
|
153
171
|
],
|
|
@@ -179,7 +197,11 @@ export function renderCompatibilityIssuesReport(report, options = {}) {
|
|
|
179
197
|
"",
|
|
180
198
|
"## Inspector Proof Gaps",
|
|
181
199
|
"",
|
|
182
|
-
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap"), options),
|
|
200
|
+
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap" && issue.status !== "runtime-covered"), options),
|
|
201
|
+
"",
|
|
202
|
+
"## Runtime-Covered Inspector Gaps",
|
|
203
|
+
"",
|
|
204
|
+
issuesTable(report.issues.filter((issue) => issue.issueClass === "inspector-gap" && issue.status === "runtime-covered"), options),
|
|
183
205
|
"",
|
|
184
206
|
"## Upstream Metadata Issues",
|
|
185
207
|
"",
|
|
@@ -228,6 +250,7 @@ function issueBlock(issue, options) {
|
|
|
228
250
|
` - state: ${issueState(issue)}`,
|
|
229
251
|
" - evidence:",
|
|
230
252
|
...evidenceList(issue.evidence, options).map((item) => ` - ${item}`),
|
|
253
|
+
...runtimeCoverageList(issue, options),
|
|
231
254
|
].join("\n");
|
|
232
255
|
}
|
|
233
256
|
|
|
@@ -235,6 +258,7 @@ function issueState(issue) {
|
|
|
235
258
|
const flags = [
|
|
236
259
|
issue.status,
|
|
237
260
|
`compat:${issue.compatStatus ?? "none"}`,
|
|
261
|
+
issue.runtimeCoverage?.status ? `runtime:${issue.runtimeCoverage.status}` : null,
|
|
238
262
|
issue.live ? "live" : null,
|
|
239
263
|
issue.deprecated ? "deprecated" : null,
|
|
240
264
|
].filter(Boolean);
|
|
@@ -266,7 +290,7 @@ function triageOverview(report) {
|
|
|
266
290
|
"inspector-gap",
|
|
267
291
|
report.summary.inspectorGapCount,
|
|
268
292
|
"-",
|
|
269
|
-
"Plugin Inspector needs stronger capture/probe evidence before making contract judgments.",
|
|
293
|
+
"Plugin Inspector needs stronger capture/probe evidence before making contract judgments. Runtime-covered rows are proof-backed and not open report work.",
|
|
270
294
|
],
|
|
271
295
|
[
|
|
272
296
|
"upstream-metadata",
|
|
@@ -357,3 +381,15 @@ function evidenceList(evidence, options) {
|
|
|
357
381
|
const formatEvidence = options.formatEvidence ?? ((item) => item);
|
|
358
382
|
return items.map((item) => formatEvidence(item));
|
|
359
383
|
}
|
|
384
|
+
|
|
385
|
+
function runtimeCoverageList(issue, options) {
|
|
386
|
+
const runtimeCoverage = issue.runtimeCoverage;
|
|
387
|
+
if (!runtimeCoverage) {
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
return [
|
|
391
|
+
" - runtime coverage:",
|
|
392
|
+
...evidenceList(runtimeCoverage.captured, options).map((item) => ` - captured ${item}`),
|
|
393
|
+
...evidenceList(runtimeCoverage.artifacts, options).map((item) => ` - ${item}`),
|
|
394
|
+
];
|
|
395
|
+
}
|
package/src/config.js
CHANGED
|
@@ -202,13 +202,43 @@ export function packageId(packageName) {
|
|
|
202
202
|
if (!packageName) {
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
205
|
-
|
|
205
|
+
const packageBase = packageName
|
|
206
206
|
.split("/")
|
|
207
207
|
.pop()
|
|
208
|
-
.replace(/^openclaw-/, "")
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
208
|
+
.replace(/^openclaw-/, "");
|
|
209
|
+
return trimHyphenEdges(collapsePackageIdSeparators(packageBase)).toLowerCase();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function collapsePackageIdSeparators(value) {
|
|
213
|
+
let result = "";
|
|
214
|
+
let previousWasHyphen = false;
|
|
215
|
+
for (const char of value) {
|
|
216
|
+
if (isAsciiAlphaNumeric(char)) {
|
|
217
|
+
result += char;
|
|
218
|
+
previousWasHyphen = false;
|
|
219
|
+
} else if (!previousWasHyphen) {
|
|
220
|
+
result += "-";
|
|
221
|
+
previousWasHyphen = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function isAsciiAlphaNumeric(char) {
|
|
228
|
+
const code = char.charCodeAt(0);
|
|
229
|
+
return (code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function trimHyphenEdges(value) {
|
|
233
|
+
let start = 0;
|
|
234
|
+
let end = value.length;
|
|
235
|
+
while (start < end && value[start] === "-") {
|
|
236
|
+
start += 1;
|
|
237
|
+
}
|
|
238
|
+
while (end > start && value[end - 1] === "-") {
|
|
239
|
+
end -= 1;
|
|
240
|
+
}
|
|
241
|
+
return value.slice(start, end);
|
|
212
242
|
}
|
|
213
243
|
|
|
214
244
|
export function inferPluginSeams(pluginManifest, packageJson) {
|
package/src/contract-capture.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "./synthetic-probes.js";
|
|
8
8
|
|
|
9
9
|
export const defaultRegistrationAssertions = {
|
|
10
|
+
createChatChannelPlugin: ["channel plugin id is stable", "channel factory metadata is captured"],
|
|
10
11
|
defineChannelPluginEntry: ["channel id is stable", "setup/config schema can be read", "message envelope metadata is preserved"],
|
|
11
12
|
definePluginEntry: ["entrypoint register function is callable", "entrypoint metadata is preserved"],
|
|
12
13
|
registerChannel: ["channel id is stable", "inbound/outbound envelope shape is captured", "sender metadata is preserved"],
|
package/src/contract-probes.js
CHANGED
|
@@ -74,6 +74,31 @@ export const contractProbeRules = {
|
|
|
74
74
|
contract: "OpenClaw package entrypoints resolve to files in the published or built plugin package.",
|
|
75
75
|
target: "package-loader",
|
|
76
76
|
},
|
|
77
|
+
"package-install-metadata-incomplete": {
|
|
78
|
+
id: "package.metadata.install-release",
|
|
79
|
+
contract: "Release publishing metadata declares canonical ClawHub and npm install specs.",
|
|
80
|
+
target: "package-loader",
|
|
81
|
+
},
|
|
82
|
+
"package-min-host-version-drift": {
|
|
83
|
+
id: "package.metadata.min-host-version",
|
|
84
|
+
contract: "Install minimum host version matches the OpenClaw package surface targeted by the plugin.",
|
|
85
|
+
target: "package-loader",
|
|
86
|
+
},
|
|
87
|
+
"package-npm-pack-entrypoint-missing": {
|
|
88
|
+
id: "package.npm-pack.entrypoints",
|
|
89
|
+
contract: "Advertised npm artifacts include every declared OpenClaw package entrypoint.",
|
|
90
|
+
target: "package-loader",
|
|
91
|
+
},
|
|
92
|
+
"package-npm-pack-metadata-missing": {
|
|
93
|
+
id: "package.npm-pack.metadata",
|
|
94
|
+
contract: "Advertised npm artifacts include OpenClaw manifest and package metadata.",
|
|
95
|
+
target: "package-loader",
|
|
96
|
+
},
|
|
97
|
+
"package-npm-pack-unavailable": {
|
|
98
|
+
id: "package.npm-pack.available",
|
|
99
|
+
contract: "Packages that advertise npm install support can produce an npm pack artifact.",
|
|
100
|
+
target: "package-loader",
|
|
101
|
+
},
|
|
77
102
|
"package-openclaw-entry-missing": {
|
|
78
103
|
id: "package.entrypoint.openclaw-metadata",
|
|
79
104
|
contract: "OpenClaw package metadata declares entrypoints for cold import and registration capture.",
|