@openclaw/plugin-inspector 0.3.5 → 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 +12 -1
- 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 +16 -3
- package/src/compatibility-report.js +39 -3
- package/src/config.js +35 -5
- package/src/contract-probes.js +25 -0
- package/src/fixture-summary.js +406 -0
- package/src/import-loop-profile.js +227 -5
- package/src/index.js +7 -0
- package/src/inspector.js +35 -4
- package/src/issues.js +66 -1
- package/src/openclaw-target.js +79 -2
- package/src/platform-probes.js +29 -6
- package/src/prune-workspace-dev-deps-cli.js +23 -0
- package/src/report.js +19 -1
- package/src/runtime-reconciliation.js +124 -0
- package/src/sdk-mock.js +64 -6
- package/src/synthetic-probes.js +45 -0
- package/src/workspace-plan.js +19 -4
package/src/platform-probes.js
CHANGED
|
@@ -55,8 +55,11 @@ export function validatePlatformProbes(report, options = {}) {
|
|
|
55
55
|
errors.push("all TypeScript loader entrypoints must track a Jiti fallback candidate");
|
|
56
56
|
}
|
|
57
57
|
for (const entrypoint of report.entrypoints) {
|
|
58
|
-
if (
|
|
59
|
-
|
|
58
|
+
if (
|
|
59
|
+
entrypoint.loaderPrimary === "tsx" &&
|
|
60
|
+
(!entrypoint.captureUsesTypeScriptLoader || !entrypoint.syntheticUsesTypeScriptLoader)
|
|
61
|
+
) {
|
|
62
|
+
errors.push(`${entrypoint.id}: TypeScript loader strategy is not reflected in capture and synthetic commands`);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
return errors;
|
|
@@ -94,9 +97,21 @@ export function renderPlatformProbesMarkdown(report, options = {}) {
|
|
|
94
97
|
entrypoint.loaderAlternatives.join(", ") || "-",
|
|
95
98
|
entrypoint.captureUsesTsx ? "yes" : "no",
|
|
96
99
|
entrypoint.syntheticUsesTsx ? "yes" : "no",
|
|
100
|
+
entrypoint.captureUsesMockSdk ? "yes" : "no",
|
|
101
|
+
entrypoint.syntheticUsesMockSdk ? "yes" : "no",
|
|
97
102
|
entrypoint.entrypoint,
|
|
98
103
|
]),
|
|
99
|
-
[
|
|
104
|
+
[
|
|
105
|
+
"Fixture",
|
|
106
|
+
"Status",
|
|
107
|
+
"Primary",
|
|
108
|
+
"Alternatives",
|
|
109
|
+
"Capture TSX",
|
|
110
|
+
"Synthetic TSX",
|
|
111
|
+
"Capture Mock SDK",
|
|
112
|
+
"Synthetic Mock SDK",
|
|
113
|
+
"Entrypoint",
|
|
114
|
+
],
|
|
100
115
|
),
|
|
101
116
|
"",
|
|
102
117
|
"## Portability Findings",
|
|
@@ -137,6 +152,10 @@ export function renderPlatformProbesMarkdown(report, options = {}) {
|
|
|
137
152
|
function summarizeEntrypoint(fixtureId, entrypoint) {
|
|
138
153
|
const captureStep = entrypoint.steps.find((step) => step.kind === "capture");
|
|
139
154
|
const syntheticStep = entrypoint.steps.find((step) => step.kind === "synthetic-probe");
|
|
155
|
+
const captureUsesTsx = Boolean(captureStep?.command.includes("--import tsx"));
|
|
156
|
+
const syntheticUsesTsx = Boolean(syntheticStep?.command.includes("--import tsx"));
|
|
157
|
+
const captureUsesMockSdk = Boolean(captureStep?.command.includes("--mock-sdk"));
|
|
158
|
+
const syntheticUsesMockSdk = Boolean(syntheticStep?.command.includes("--mock-sdk"));
|
|
140
159
|
return {
|
|
141
160
|
fixture: fixtureId,
|
|
142
161
|
id: entrypoint.id,
|
|
@@ -148,8 +167,12 @@ function summarizeEntrypoint(fixtureId, entrypoint) {
|
|
|
148
167
|
loaderAlternatives: entrypoint.loaderStrategy.alternatives,
|
|
149
168
|
capturePlanned: Boolean(captureStep),
|
|
150
169
|
syntheticProbePlanned: Boolean(syntheticStep),
|
|
151
|
-
captureUsesTsx
|
|
152
|
-
syntheticUsesTsx
|
|
170
|
+
captureUsesTsx,
|
|
171
|
+
syntheticUsesTsx,
|
|
172
|
+
captureUsesMockSdk,
|
|
173
|
+
syntheticUsesMockSdk,
|
|
174
|
+
captureUsesTypeScriptLoader: captureUsesTsx || captureUsesMockSdk,
|
|
175
|
+
syntheticUsesTypeScriptLoader: syntheticUsesTsx || syntheticUsesMockSdk,
|
|
153
176
|
};
|
|
154
177
|
}
|
|
155
178
|
|
|
@@ -260,7 +283,7 @@ function buildRecommendations(portabilityFindings, entrypoints) {
|
|
|
260
283
|
if (entrypoints.some((entrypoint) => entrypoint.loaderPrimary === "tsx")) {
|
|
261
284
|
recommendations.push({
|
|
262
285
|
area: "loader",
|
|
263
|
-
action: "keep
|
|
286
|
+
action: "keep mock-SDK TypeScript capture green, add a real host-loader/Jiti lane before treating TS plugin source compatibility as covered",
|
|
264
287
|
});
|
|
265
288
|
}
|
|
266
289
|
if (portabilityFindings.some((finding) => finding.riskCodes.includes("rsync-required"))) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
const packageJsonPath = path.resolve(process.cwd(), "package.json");
|
|
6
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
7
|
+
let changed = false;
|
|
8
|
+
|
|
9
|
+
for (const [name, specifier] of Object.entries(packageJson.devDependencies ?? {})) {
|
|
10
|
+
if (typeof specifier === "string" && specifier.startsWith("workspace:")) {
|
|
11
|
+
delete packageJson.devDependencies[name];
|
|
12
|
+
changed = true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (packageJson.devDependencies && Object.keys(packageJson.devDependencies).length === 0) {
|
|
17
|
+
delete packageJson.devDependencies;
|
|
18
|
+
changed = true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (changed) {
|
|
22
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
|
|
23
|
+
}
|
package/src/report.js
CHANGED
|
@@ -5,6 +5,7 @@ import { buildContractProbes } from "./contract-probes.js";
|
|
|
5
5
|
import { classifyCompatibilityFixture } from "./fixture-summary.js";
|
|
6
6
|
import { buildIssues, summarizeIssueClasses } from "./issues.js";
|
|
7
7
|
import { sanitizeReportArtifact } from "./report-sanitizer.js";
|
|
8
|
+
import { applyRuntimeExecutionCoverage } from "./runtime-reconciliation.js";
|
|
8
9
|
|
|
9
10
|
export function buildReport({ config, inspections, failures = [], generatedAt = "deterministic" }) {
|
|
10
11
|
const inspectionById = new Map(inspections.map((inspection) => [inspection.id, inspection]));
|
|
@@ -140,6 +141,10 @@ export async function buildCompatibilityReport(options = {}) {
|
|
|
140
141
|
decisions,
|
|
141
142
|
});
|
|
142
143
|
|
|
144
|
+
const runtimeCoverage = applyRuntimeExecutionCoverage({
|
|
145
|
+
findings: [...warnings, ...suggestions],
|
|
146
|
+
executionResults: options.executionResults,
|
|
147
|
+
});
|
|
143
148
|
const issues = buildIssues({
|
|
144
149
|
breakages,
|
|
145
150
|
warnings,
|
|
@@ -149,6 +154,8 @@ export async function buildCompatibilityReport(options = {}) {
|
|
|
149
154
|
});
|
|
150
155
|
const contractProbes = buildContractProbes({ warnings, suggestions, fixtures: fixtureReports });
|
|
151
156
|
const issueSummary = summarizeIssueClasses(issues);
|
|
157
|
+
const openIssues = issues.filter((issue) => issue.status !== "runtime-covered");
|
|
158
|
+
const openIssueSummary = summarizeIssueClasses(openIssues);
|
|
152
159
|
|
|
153
160
|
return {
|
|
154
161
|
generatedAt: options.generatedAt ?? "deterministic",
|
|
@@ -163,8 +170,11 @@ export async function buildCompatibilityReport(options = {}) {
|
|
|
163
170
|
decisionCount: decisions.length,
|
|
164
171
|
logCount: logs.length,
|
|
165
172
|
issueCount: issues.length,
|
|
173
|
+
openIssueCount: openIssues.length,
|
|
166
174
|
p0IssueCount: issues.filter((issue) => issue.severity === "P0").length,
|
|
167
175
|
p1IssueCount: issues.filter((issue) => issue.severity === "P1").length,
|
|
176
|
+
openP0IssueCount: openIssues.filter((issue) => issue.severity === "P0").length,
|
|
177
|
+
openP1IssueCount: openIssues.filter((issue) => issue.severity === "P1").length,
|
|
168
178
|
liveIssueCount: issueSummary["live-issue"],
|
|
169
179
|
liveP0IssueCount: issues.filter((issue) => issue.issueClass === "live-issue" && issue.severity === "P0").length,
|
|
170
180
|
compatGapCount: issueSummary["compat-gap"],
|
|
@@ -172,6 +182,10 @@ export async function buildCompatibilityReport(options = {}) {
|
|
|
172
182
|
inspectorGapCount: issueSummary["inspector-gap"],
|
|
173
183
|
upstreamIssueCount: issueSummary["upstream-metadata"],
|
|
174
184
|
fixtureRegressionCount: issueSummary["fixture-regression"],
|
|
185
|
+
openInspectorGapCount: openIssueSummary["inspector-gap"],
|
|
186
|
+
runtimeCoveredIssueCount: runtimeCoverage.coveredFindingCount,
|
|
187
|
+
runtimePartiallyCoveredIssueCount: runtimeCoverage.partiallyCoveredFindingCount,
|
|
188
|
+
runtimeCoverageArtifactCount: runtimeCoverage.coverage.artifactCount,
|
|
175
189
|
contractProbeCount: contractProbes.length,
|
|
176
190
|
},
|
|
177
191
|
fixtures: fixtureReports,
|
|
@@ -308,7 +322,11 @@ function topTextFindings(report, limit) {
|
|
|
308
322
|
return [
|
|
309
323
|
...(report.breakages ?? []).map((finding) => formatTextFinding(finding, "breakage")),
|
|
310
324
|
...(report.issues ?? [])
|
|
311
|
-
.filter(
|
|
325
|
+
.filter(
|
|
326
|
+
(issue) =>
|
|
327
|
+
issue.status !== "runtime-covered" &&
|
|
328
|
+
(issue.status === "blocking" || issue.severity === "P0" || issue.severity === "P1"),
|
|
329
|
+
)
|
|
312
330
|
.map((issue) => formatTextFinding(issue, issue.severity ?? "issue")),
|
|
313
331
|
...(report.warnings ?? []).map((finding) => formatTextFinding(finding, "warning")),
|
|
314
332
|
].slice(0, limit);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export function applyRuntimeExecutionCoverage({ findings = [], executionResults } = {}) {
|
|
2
|
+
const coverage = buildRuntimeExecutionCoverage(executionResults);
|
|
3
|
+
let coveredFindingCount = 0;
|
|
4
|
+
let partiallyCoveredFindingCount = 0;
|
|
5
|
+
|
|
6
|
+
for (const finding of findings) {
|
|
7
|
+
const findingCoverage = runtimeCoverageForFinding(finding, coverage);
|
|
8
|
+
if (!findingCoverage) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
finding.runtimeCoverage = findingCoverage;
|
|
13
|
+
if (findingCoverage.status === "covered") {
|
|
14
|
+
finding.status = "runtime-covered";
|
|
15
|
+
coveredFindingCount += 1;
|
|
16
|
+
} else {
|
|
17
|
+
partiallyCoveredFindingCount += 1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
coverage,
|
|
23
|
+
coveredFindingCount,
|
|
24
|
+
partiallyCoveredFindingCount,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function buildRuntimeExecutionCoverage(executionResults) {
|
|
29
|
+
const fixtures = new Map();
|
|
30
|
+
for (const artifact of executionResults?.artifacts ?? []) {
|
|
31
|
+
if (artifact.kind !== "capture") {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const fixture = String(artifact.fixture ?? "unknown");
|
|
36
|
+
const fixtureCoverage = ensureFixtureCoverage(fixtures, fixture);
|
|
37
|
+
if (artifact.artifactPath) {
|
|
38
|
+
fixtureCoverage.artifacts.add(artifact.artifactPath);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const captured of normalizeCaptured(artifact.captured)) {
|
|
42
|
+
fixtureCoverage.captured.add(captured);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
fixtures,
|
|
48
|
+
artifactCount: [...fixtures.values()].reduce((sum, fixture) => sum + fixture.artifacts.size, 0),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function runtimeCoverageForFinding(finding, coverage) {
|
|
53
|
+
const fixtureCoverage = coverage.fixtures.get(finding.fixture);
|
|
54
|
+
if (!fixtureCoverage || fixtureCoverage.captured.size === 0) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const expected = expectedRuntimeCaptureKeys(finding);
|
|
59
|
+
if (expected.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const captured = expected.filter((item) => fixtureCoverage.captured.has(item));
|
|
64
|
+
if (captured.length === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
status: captured.length === expected.length ? "covered" : "partial",
|
|
70
|
+
captured,
|
|
71
|
+
expected,
|
|
72
|
+
artifacts: [...fixtureCoverage.artifacts].sort(),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function expectedRuntimeCaptureKeys(finding) {
|
|
77
|
+
const names = evidenceNames(finding.evidence);
|
|
78
|
+
if (finding.code === "registration-capture-gap") {
|
|
79
|
+
return names.map((name) => `registration:${name}`);
|
|
80
|
+
}
|
|
81
|
+
if (finding.code === "runtime-tool-capture") {
|
|
82
|
+
return ["registration:registerTool"];
|
|
83
|
+
}
|
|
84
|
+
if (finding.code === "conversation-access-hook") {
|
|
85
|
+
return names.map((name) => `hook:${name}`);
|
|
86
|
+
}
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function normalizeCaptured(captured) {
|
|
91
|
+
return (captured ?? [])
|
|
92
|
+
.map((item) => {
|
|
93
|
+
if (typeof item === "string") {
|
|
94
|
+
return item;
|
|
95
|
+
}
|
|
96
|
+
if (item && typeof item === "object" && item.kind && item.name) {
|
|
97
|
+
return `${item.kind}:${item.name}`;
|
|
98
|
+
}
|
|
99
|
+
return "";
|
|
100
|
+
})
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function evidenceNames(evidence) {
|
|
105
|
+
return [
|
|
106
|
+
...new Set(
|
|
107
|
+
(evidence ?? [])
|
|
108
|
+
.map((item) => String(item).split(" @ ")[0]?.trim())
|
|
109
|
+
.filter(Boolean),
|
|
110
|
+
),
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function ensureFixtureCoverage(fixtures, fixture) {
|
|
115
|
+
let fixtureCoverage = fixtures.get(fixture);
|
|
116
|
+
if (!fixtureCoverage) {
|
|
117
|
+
fixtureCoverage = {
|
|
118
|
+
artifacts: new Set(),
|
|
119
|
+
captured: new Set(),
|
|
120
|
+
};
|
|
121
|
+
fixtures.set(fixture, fixtureCoverage);
|
|
122
|
+
}
|
|
123
|
+
return fixtureCoverage;
|
|
124
|
+
}
|
package/src/sdk-mock.js
CHANGED
|
@@ -254,9 +254,20 @@ export async function createMockSdkPackage(rootDir, options = {}) {
|
|
|
254
254
|
)}\n`,
|
|
255
255
|
"utf8",
|
|
256
256
|
);
|
|
257
|
-
|
|
257
|
+
const rootExportNames = new Set([
|
|
258
|
+
...mockSdkExportNames,
|
|
259
|
+
...(imports.bySpecifier.get("openclaw/plugin-sdk") ?? []),
|
|
260
|
+
]);
|
|
261
|
+
await writeFile(path.join(pluginSdkDir, "index.js"), mockSdkSource(rootExportNames), "utf8");
|
|
258
262
|
for (const [subpath, exportNames] of Object.entries(mockSdkSubpathExports)) {
|
|
259
|
-
|
|
263
|
+
const specifier = `openclaw/plugin-sdk/${subpath}`;
|
|
264
|
+
await writeFile(
|
|
265
|
+
path.join(pluginSdkDir, `${subpath}.js`),
|
|
266
|
+
mockSdkSubpathSource(exportNames, imports.bySpecifier.get(specifier) ?? new Set(), {
|
|
267
|
+
zod: subpath === "zod",
|
|
268
|
+
}),
|
|
269
|
+
"utf8",
|
|
270
|
+
);
|
|
260
271
|
}
|
|
261
272
|
for (const specifier of imports.openclawSdkSpecifiers) {
|
|
262
273
|
if (specifier === "openclaw/plugin-sdk") {
|
|
@@ -428,6 +439,9 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
428
439
|
const subpath = specifier.slice("openclaw/plugin-sdk/".length);
|
|
429
440
|
return moduleUrl(path.join(pluginSdkDir, \`\${subpath}.js\`));
|
|
430
441
|
}
|
|
442
|
+
if (externalMap.has(specifier)) {
|
|
443
|
+
return moduleUrl(externalMap.get(specifier));
|
|
444
|
+
}
|
|
431
445
|
try {
|
|
432
446
|
return await nextResolve(specifier, context);
|
|
433
447
|
} catch (error) {
|
|
@@ -531,6 +545,12 @@ function genericExportStatement(name) {
|
|
|
531
545
|
if (["createChatChannelPlugin", "createPlugin", "defineChannelPluginEntry", "definePlugin", "definePluginEntry", "defineSetupPluginEntry"].includes(name)) {
|
|
532
546
|
return name === "definePluginEntry" ? "export { definePluginEntry };" : `export const ${name} = definePluginEntry;`;
|
|
533
547
|
}
|
|
548
|
+
if (name === "defineBundledChannelEntry") {
|
|
549
|
+
return "export { defineBundledChannelEntry };";
|
|
550
|
+
}
|
|
551
|
+
if (name === "defineBundledChannelSetupEntry") {
|
|
552
|
+
return "export { defineBundledChannelSetupEntry };";
|
|
553
|
+
}
|
|
534
554
|
if (/^[A-Z].*Schema$/u.test(name)) {
|
|
535
555
|
return `export const ${name} = createSchema();`;
|
|
536
556
|
}
|
|
@@ -547,9 +567,41 @@ function genericMockRuntimeSource(options = {}) {
|
|
|
547
567
|
}
|
|
548
568
|
return typeof entry === "function" ? { register: entry } : entry;
|
|
549
569
|
}
|
|
570
|
+
|
|
571
|
+
function defineBundledChannelEntry(entry = {}) {
|
|
572
|
+
return {
|
|
573
|
+
...entry,
|
|
574
|
+
kind: "bundled-channel-entry",
|
|
575
|
+
register(api) {
|
|
576
|
+
if (api?.registrationMode === "cli-metadata") {
|
|
577
|
+
return entry.registerCliMetadata?.(api);
|
|
578
|
+
}
|
|
579
|
+
if (api?.registrationMode !== "tool-discovery") {
|
|
580
|
+
api?.registerChannel?.({
|
|
581
|
+
id: entry.id,
|
|
582
|
+
name: entry.name,
|
|
583
|
+
description: entry.description,
|
|
584
|
+
plugin: { id: entry.id, name: entry.name },
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
entry.registerCliMetadata?.(api);
|
|
588
|
+
return entry.registerFull?.(api);
|
|
589
|
+
},
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function defineBundledChannelSetupEntry(entry = {}) {
|
|
594
|
+
return {
|
|
595
|
+
...entry,
|
|
596
|
+
kind: "bundled-channel-setup-entry",
|
|
597
|
+
};
|
|
598
|
+
}
|
|
550
599
|
` : ""}
|
|
551
600
|
function createMockValue(name) {
|
|
552
601
|
function fn(...args) {
|
|
602
|
+
if (name === "resolvePreferredOpenClawTmpDir") {
|
|
603
|
+
return process.env.TMPDIR || "/tmp";
|
|
604
|
+
}
|
|
553
605
|
if (name.startsWith("normalize")) {
|
|
554
606
|
return typeof args[0] === "string" ? args[0] : "";
|
|
555
607
|
}
|
|
@@ -728,7 +780,8 @@ function createTypeNamespace() {
|
|
|
728
780
|
`;
|
|
729
781
|
}
|
|
730
782
|
|
|
731
|
-
function mockSdkSource() {
|
|
783
|
+
function mockSdkSource(exportNames = mockSdkExportNames) {
|
|
784
|
+
const dynamicExportNames = [...exportNames].filter((name) => !mockSdkExportNames.includes(name));
|
|
732
785
|
return `function normalizeEntry(entry) {
|
|
733
786
|
return typeof entry === "function" ? { register: entry } : entry;
|
|
734
787
|
}
|
|
@@ -1538,15 +1591,20 @@ export const OPENAI_RESPONSES_STREAM_HOOKS = buildProviderStreamFamilyHooks("ope
|
|
|
1538
1591
|
export const OPENROUTER_THINKING_STREAM_HOOKS = buildProviderStreamFamilyHooks("openrouter-thinking");
|
|
1539
1592
|
export const TOOL_STREAM_DEFAULT_ON_HOOKS = buildProviderStreamFamilyHooks("tool-stream-default");
|
|
1540
1593
|
export const pluginSdkMock = true;
|
|
1594
|
+
${dynamicExportNames.map(genericExportStatement).join("\n")}
|
|
1541
1595
|
|
|
1542
1596
|
export default {
|
|
1543
|
-
${
|
|
1597
|
+
${[...exportNames].map((name) => ` ${name},`).join("\n")}
|
|
1544
1598
|
};
|
|
1545
1599
|
`;
|
|
1546
1600
|
}
|
|
1547
1601
|
|
|
1548
|
-
function mockSdkSubpathSource(
|
|
1549
|
-
|
|
1602
|
+
function mockSdkSubpathSource(staticExportNames, importedExportNames, options = {}) {
|
|
1603
|
+
const staticNames = new Set(staticExportNames);
|
|
1604
|
+
const dynamicNames = [...importedExportNames].filter((name) => !staticNames.has(name));
|
|
1605
|
+
return `${[...staticNames].map((name) => `export { ${name} } from "./index.js";`).join("\n")}
|
|
1606
|
+
${dynamicNames.length > 0 ? genericMockRuntimeSource({ includeSdkRuntime: true, zod: options.zod }) : ""}
|
|
1607
|
+
${dynamicNames.map(genericExportStatement).join("\n")}
|
|
1550
1608
|
export { default } from "./index.js";
|
|
1551
1609
|
`;
|
|
1552
1610
|
}
|
package/src/synthetic-probes.js
CHANGED
|
@@ -11,6 +11,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
11
11
|
callableProperties: [],
|
|
12
12
|
reason: "entry wrapper metadata is captured before channel runtime execution",
|
|
13
13
|
},
|
|
14
|
+
defineBundledChannelEntry: {
|
|
15
|
+
mode: "metadata-only",
|
|
16
|
+
callableProperties: [],
|
|
17
|
+
reason: "bundled channel entry metadata is captured before channel runtime execution",
|
|
18
|
+
},
|
|
14
19
|
definePluginEntry: {
|
|
15
20
|
mode: "metadata-only",
|
|
16
21
|
callableProperties: [],
|
|
@@ -26,6 +31,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
26
31
|
callableProperties: [],
|
|
27
32
|
reason: "agent harness factories are captured as registration metadata; agent runtime execution remains isolated opt-in",
|
|
28
33
|
},
|
|
34
|
+
registerAgentEventSubscription: {
|
|
35
|
+
mode: "metadata-only",
|
|
36
|
+
callableProperties: [],
|
|
37
|
+
reason: "agent event subscriptions are captured as registration metadata before agent event dispatch",
|
|
38
|
+
},
|
|
29
39
|
registerAgentToolResultMiddleware: {
|
|
30
40
|
mode: "metadata-only",
|
|
31
41
|
callableProperties: [],
|
|
@@ -69,6 +79,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
69
79
|
callableProperties: [],
|
|
70
80
|
reason: "context engine factories are captured as registration metadata; engine startup remains isolated opt-in",
|
|
71
81
|
},
|
|
82
|
+
registerControlUiDescriptor: {
|
|
83
|
+
mode: "metadata-only",
|
|
84
|
+
callableProperties: [],
|
|
85
|
+
reason: "control UI descriptors are captured as registration metadata before UI composition",
|
|
86
|
+
},
|
|
72
87
|
registerDetachedTaskRuntime: {
|
|
73
88
|
mode: "metadata-only",
|
|
74
89
|
callableProperties: [],
|
|
@@ -156,6 +171,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
156
171
|
callableProperties: [],
|
|
157
172
|
reason: "node host commands are captured as registration metadata before host process execution",
|
|
158
173
|
},
|
|
174
|
+
registerNodeInvokePolicy: {
|
|
175
|
+
mode: "metadata-only",
|
|
176
|
+
callableProperties: [],
|
|
177
|
+
reason: "node invoke policies are captured as registration metadata before host authorization checks",
|
|
178
|
+
},
|
|
159
179
|
registerProvider: {
|
|
160
180
|
mode: "metadata-only",
|
|
161
181
|
callableProperties: [],
|
|
@@ -176,6 +196,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
176
196
|
callableProperties: [],
|
|
177
197
|
reason: "reload handlers are captured as registration metadata before runtime reload execution",
|
|
178
198
|
},
|
|
199
|
+
registerRuntimeLifecycle: {
|
|
200
|
+
mode: "metadata-only",
|
|
201
|
+
callableProperties: [],
|
|
202
|
+
reason: "runtime lifecycle handlers are captured as registration metadata before lifecycle dispatch",
|
|
203
|
+
},
|
|
179
204
|
registerSecurityAuditCollector: {
|
|
180
205
|
mode: "metadata-only",
|
|
181
206
|
callableProperties: [],
|
|
@@ -186,6 +211,16 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
186
211
|
callableProperties: ["start", "stop", "dispose"],
|
|
187
212
|
option: "includeLifecycle",
|
|
188
213
|
},
|
|
214
|
+
registerSessionExtension: {
|
|
215
|
+
mode: "metadata-only",
|
|
216
|
+
callableProperties: [],
|
|
217
|
+
reason: "session extensions are captured as registration metadata before session runtime execution",
|
|
218
|
+
},
|
|
219
|
+
registerSessionSchedulerJob: {
|
|
220
|
+
mode: "metadata-only",
|
|
221
|
+
callableProperties: [],
|
|
222
|
+
reason: "session scheduler jobs are captured as registration metadata before scheduler execution",
|
|
223
|
+
},
|
|
189
224
|
registerSpeechProvider: {
|
|
190
225
|
mode: "provider-opt-in",
|
|
191
226
|
callableProperties: ["speak", "synthesize", "tts"],
|
|
@@ -195,6 +230,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
195
230
|
mode: "direct",
|
|
196
231
|
callableProperties: ["run", "handler", "execute"],
|
|
197
232
|
},
|
|
233
|
+
registerToolMetadata: {
|
|
234
|
+
mode: "metadata-only",
|
|
235
|
+
callableProperties: [],
|
|
236
|
+
reason: "tool metadata descriptors are captured as registration metadata before tool runtime execution",
|
|
237
|
+
},
|
|
198
238
|
registerTextTransforms: {
|
|
199
239
|
mode: "metadata-only",
|
|
200
240
|
callableProperties: [],
|
|
@@ -205,6 +245,11 @@ export const syntheticRegistrationExecutionProfiles = {
|
|
|
205
245
|
callableProperties: [],
|
|
206
246
|
reason: "video generation providers are captured as registration metadata before provider runtime execution",
|
|
207
247
|
},
|
|
248
|
+
registerTrustedToolPolicy: {
|
|
249
|
+
mode: "metadata-only",
|
|
250
|
+
callableProperties: [],
|
|
251
|
+
reason: "trusted tool policies are captured as registration metadata before trust-policy enforcement",
|
|
252
|
+
},
|
|
208
253
|
registerWebFetchProvider: {
|
|
209
254
|
mode: "metadata-only",
|
|
210
255
|
callableProperties: [],
|
package/src/workspace-plan.js
CHANGED
|
@@ -71,6 +71,7 @@ export async function buildWorkspacePlan(options = {}) {
|
|
|
71
71
|
installStepCount: allSteps.filter((step) => step.kind === "install").length,
|
|
72
72
|
auditStepCount: allSteps.filter((step) => step.kind === "audit").length,
|
|
73
73
|
buildStepCount: allSteps.filter((step) => step.kind === "build").length,
|
|
74
|
+
pruneDevWorkspaceDependencyStepCount: allSteps.filter((step) => step.kind === "prune-dev-workspace-deps").length,
|
|
74
75
|
artifactStepCount: allSteps.filter((step) => step.kind === "prepare-artifacts").length,
|
|
75
76
|
captureStepCount: allSteps.filter((step) => step.kind === "capture").length,
|
|
76
77
|
syntheticProbeStepCount: allSteps.filter((step) => step.kind === "synthetic-probe").length,
|
|
@@ -179,6 +180,7 @@ export function renderWorkspacePlanMarkdown(plan, options = {}) {
|
|
|
179
180
|
["Artifact dirs", plan.summary.artifactStepCount],
|
|
180
181
|
["Install steps", plan.summary.installStepCount],
|
|
181
182
|
["Audit steps", plan.summary.auditStepCount],
|
|
183
|
+
["Prune dev workspace dependency steps", plan.summary.pruneDevWorkspaceDependencyStepCount],
|
|
182
184
|
["Build steps", plan.summary.buildStepCount],
|
|
183
185
|
["Capture steps", plan.summary.captureStepCount],
|
|
184
186
|
["Synthetic probe steps", plan.summary.syntheticProbeStepCount],
|
|
@@ -248,6 +250,14 @@ async function buildEntrypointPlan({ fixtureId, entrypoint, packageSummary, pack
|
|
|
248
250
|
}
|
|
249
251
|
|
|
250
252
|
if (requiredCapabilities.includes("dependency-install")) {
|
|
253
|
+
if (hasWorkspaceProtocolDevDependencies(packageJson)) {
|
|
254
|
+
steps.push({
|
|
255
|
+
kind: "prune-dev-workspace-deps",
|
|
256
|
+
command: `node ${helperScript(settings, workspacePath, settings.pruneWorkspaceDevDepsScript, "prune-workspace-dev-deps-cli.js")}`,
|
|
257
|
+
cwd: workspacePath,
|
|
258
|
+
reason: "remove workspace: devDependencies from the isolated runtime install; the mock SDK supplies OpenClaw host imports",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
251
261
|
steps.push({
|
|
252
262
|
kind: "install",
|
|
253
263
|
command: installCommand(packageManager),
|
|
@@ -319,6 +329,7 @@ function workspaceSettings(options) {
|
|
|
319
329
|
resultsRoot: repoRelative(options.resultsRoot ?? defaultWorkspacePlanOptions.resultsRoot),
|
|
320
330
|
rootDir: path.resolve(options.rootDir ?? process.cwd()),
|
|
321
331
|
syntheticProbeScript: options.syntheticProbeScript ?? defaultWorkspacePlanOptions.syntheticProbeScript,
|
|
332
|
+
pruneWorkspaceDevDepsScript: options.pruneWorkspaceDevDepsScript,
|
|
322
333
|
workspaceRoot: repoRelative(options.workspaceRoot ?? defaultWorkspacePlanOptions.workspaceRoot),
|
|
323
334
|
};
|
|
324
335
|
}
|
|
@@ -377,6 +388,12 @@ function hasHostLinkedOpenClawDependency(packageSummary) {
|
|
|
377
388
|
].includes("openclaw");
|
|
378
389
|
}
|
|
379
390
|
|
|
391
|
+
function hasWorkspaceProtocolDevDependencies(packageJson) {
|
|
392
|
+
return Object.values(packageJson.devDependencies ?? {}).some(
|
|
393
|
+
(value) => typeof value === "string" && value.startsWith("workspace:"),
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
380
397
|
function detectPackageManager(rootDir, packageDir, packageJson) {
|
|
381
398
|
const declared = typeof packageJson.packageManager === "string" ? packageJson.packageManager.split("@")[0] : null;
|
|
382
399
|
if (declared) {
|
|
@@ -458,15 +475,13 @@ function runCommand(packageManager, script) {
|
|
|
458
475
|
}
|
|
459
476
|
|
|
460
477
|
function captureCommand(settings, fixtureId, entrypoint, workspacePath) {
|
|
461
|
-
const loader = entrypoint.blockers.some((blocker) => blocker.code === "ts-loader-required") ? " --import tsx" : "";
|
|
462
478
|
const script = helperScript(settings, workspacePath, settings.captureScript, "capture-cli.js");
|
|
463
|
-
return `${settings.optInEnv} node
|
|
479
|
+
return `${settings.optInEnv} node ${script} ${entrypoint.specifier} --mock-sdk --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "capture")}`;
|
|
464
480
|
}
|
|
465
481
|
|
|
466
482
|
function syntheticProbeCommand(settings, fixtureId, entrypoint, workspacePath) {
|
|
467
|
-
const loader = entrypoint.blockers.some((blocker) => blocker.code === "ts-loader-required") ? " --import tsx" : "";
|
|
468
483
|
const script = helperScript(settings, workspacePath, settings.syntheticProbeScript, "synthetic-probes-cli.js");
|
|
469
|
-
return `${settings.optInEnv} node
|
|
484
|
+
return `${settings.optInEnv} node ${script} --entrypoint ${entrypoint.specifier} --mock-sdk --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "synthetic")}`;
|
|
470
485
|
}
|
|
471
486
|
|
|
472
487
|
function helperScript(settings, workspacePath, configuredScript, helperFileName) {
|