@openclaw/plugin-inspector 0.1.2 → 0.1.3

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.3 - 2026-04-27
4
+
5
+ ### Added
6
+
7
+ - Add reserved bundled-plugin SDK import detection so external plugins get explicit compatibility findings for private OpenClaw SDK shims.
8
+ - Add packaged workspace capture and synthetic-probe helper CLIs for generated isolated workspace plans.
9
+
10
+ ### Changed
11
+
12
+ - Make `plugin-inspector ci` write compatibility-backed CI summary artifacts instead of the legacy inventory report.
13
+ - Default packaged helper captures to the mocked OpenClaw SDK while preserving `--real-sdk` opt-in behavior.
14
+ - Detect the default runtime capture artifact at `reports/plugin-inspector-runtime-capture.json`.
15
+ - Report the actual log count in CLI text summaries.
16
+
3
17
  ## 0.1.2 - 2026-04-27
4
18
 
5
19
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/plugin-inspector",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "description": "Offline compatibility inspector for OpenClaw plugins.",
6
6
  "type": "module",
package/src/advanced.js CHANGED
@@ -100,6 +100,7 @@ export {
100
100
  openClawTargetPathCandidates,
101
101
  parseCompatRecordEntries,
102
102
  parseExportedStringArray,
103
+ parsePluginSdkEntrypointSpecifiers,
103
104
  parsePluginSdkExports,
104
105
  parseTypeFields,
105
106
  readOpenClawTargetSurface,
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import { captureEntrypoint, writeArtifacts } from "./advanced.js";
3
+
4
+ const args = process.argv.slice(2);
5
+
6
+ try {
7
+ await run(args);
8
+ } catch (error) {
9
+ console.error(error.message);
10
+ process.exitCode = 1;
11
+ }
12
+
13
+ async function run(commandArgs) {
14
+ const entrypoint = commandArgs.find((arg) => !arg.startsWith("-"));
15
+ const outputPath = readFlag(commandArgs, "--output");
16
+ const pluginRoot = readFlag(commandArgs, "--plugin-root");
17
+ const mockSdk = readMockSdkFlag(commandArgs) ?? true;
18
+
19
+ if (!entrypoint) {
20
+ throw new Error("capture requires an entrypoint path");
21
+ }
22
+ if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
23
+ throw new Error("capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
24
+ }
25
+
26
+ const result = await captureEntrypoint(entrypoint, { mockSdk, pluginRoot });
27
+ const json = `${JSON.stringify(result, null, 2)}\n`;
28
+ if (outputPath) {
29
+ await writeArtifacts([{ path: outputPath, content: json }]);
30
+ } else {
31
+ process.stdout.write(json);
32
+ }
33
+ }
34
+
35
+ function readFlag(commandArgs, name) {
36
+ const index = commandArgs.indexOf(name);
37
+ if (index === -1) {
38
+ return null;
39
+ }
40
+ return commandArgs[index + 1] ?? null;
41
+ }
42
+
43
+ function readMockSdkFlag(commandArgs) {
44
+ const sdk = readFlag(commandArgs, "--sdk");
45
+ if (sdk === "mock") {
46
+ return true;
47
+ }
48
+ if (sdk === "real") {
49
+ return false;
50
+ }
51
+ if (sdk && !["mock", "real"].includes(sdk)) {
52
+ throw new Error("--sdk must be mock or real");
53
+ }
54
+ if (commandArgs.includes("--mock-sdk")) {
55
+ return true;
56
+ }
57
+ if (commandArgs.includes("--real-sdk")) {
58
+ return false;
59
+ }
60
+ return undefined;
61
+ }
package/src/ci-summary.js CHANGED
@@ -5,7 +5,7 @@ import { readOptionalJsonFile } from "./json-file.js";
5
5
 
6
6
  export const defaultCiReportPaths = {
7
7
  compatibility: "reports/plugin-inspector-report.json",
8
- capture: "reports/plugin-inspector-capture.json",
8
+ capture: "reports/plugin-inspector-runtime-capture.json",
9
9
  synthetic: "reports/plugin-inspector-synthetic-probes.json",
10
10
  coldImport: "reports/plugin-inspector-cold-import.json",
11
11
  workspace: "reports/plugin-inspector-workspace-plan.json",
package/src/cli.js CHANGED
@@ -1,12 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import path from "node:path";
2
3
  import {
3
4
  renderTextSummary,
4
5
  runPluginCheck,
5
6
  } from "./index.js";
6
7
  import {
8
+ buildCiSummary,
7
9
  captureEntrypoint,
10
+ inspectCompatibilityFixtureSet,
8
11
  inspectFixtureSet,
9
12
  loadInspectorConfig,
13
+ writeCiSummary,
14
+ writeCompatibilityReport,
10
15
  writePluginInspectorInit,
11
16
  writeArtifacts,
12
17
  writeReport,
@@ -23,8 +28,10 @@ try {
23
28
  await runCheck(commandArgs);
24
29
  } else if (command === "init") {
25
30
  await runInit(commandArgs);
26
- } else if (command === "inspect" || command === "report" || command === "ci") {
31
+ } else if (command === "inspect" || command === "report") {
27
32
  await runReport(command, commandArgs);
33
+ } else if (command === "ci") {
34
+ await runCi(commandArgs);
28
35
  } else if (command === "capture") {
29
36
  await runCapture(commandArgs);
30
37
  } else {
@@ -95,6 +102,62 @@ async function runReport(command, commandArgs) {
95
102
  }
96
103
  }
97
104
 
105
+ async function runCi(commandArgs) {
106
+ const configPath = readFlag(commandArgs, "--config");
107
+ const pluginRoot = readFlag(commandArgs, "--plugin-root") ?? readFlag(commandArgs, "--root");
108
+ const outDir = readFlag(commandArgs, "--out") ?? "reports";
109
+ const openclawPath = commandArgs.includes("--no-openclaw") ? false : readFlag(commandArgs, "--openclaw");
110
+ const json = commandArgs.includes("--json");
111
+ const { report, reportDir } = await runCiCompatibilityReport({
112
+ configPath,
113
+ openclawPath,
114
+ outDir,
115
+ pluginRoot,
116
+ });
117
+
118
+ const summary = await buildCiSummary({
119
+ artifactBaseDir: reportDir,
120
+ reportPaths: {
121
+ compatibility: "plugin-inspector-report.json",
122
+ },
123
+ reports: {
124
+ compatibility: report,
125
+ },
126
+ });
127
+ await writeCiSummary(summary, {
128
+ jsonPath: path.join(reportDir, "plugin-inspector-ci-summary.json"),
129
+ markdownPath: path.join(reportDir, "plugin-inspector-ci-summary.md"),
130
+ });
131
+
132
+ if (json) {
133
+ console.log(JSON.stringify(summary, null, 2));
134
+ } else {
135
+ console.log(renderCiTextSummary(summary));
136
+ }
137
+
138
+ if (summary.status !== "pass") {
139
+ throw new Error("plugin-inspector ci summary failed");
140
+ }
141
+ }
142
+
143
+ async function runCiCompatibilityReport({ configPath, openclawPath, outDir, pluginRoot }) {
144
+ if (configPath) {
145
+ const config = await loadInspectorConfig(configPath, { cwd: pluginRoot });
146
+ const report = await inspectCompatibilityFixtureSet(config, { openclawPath });
147
+ await writeCompatibilityReport(report, { cwd: config.rootDir, outDir });
148
+ return {
149
+ report,
150
+ reportDir: path.resolve(config.rootDir, outDir),
151
+ };
152
+ }
153
+
154
+ const { report } = await runPluginCheck({ pluginRoot, outDir, openclawPath });
155
+ return {
156
+ report,
157
+ reportDir: path.resolve(pluginRoot ?? process.cwd(), outDir),
158
+ };
159
+ }
160
+
98
161
  async function runCapture(commandArgs) {
99
162
  const entrypoint = commandArgs.find((arg) => !arg.startsWith("-"));
100
163
  const outputPath = readFlag(commandArgs, "--output");
@@ -154,6 +217,15 @@ function readMockSdkFlag(commandArgs) {
154
217
  return undefined;
155
218
  }
156
219
 
220
+ function renderCiTextSummary(summary) {
221
+ return [
222
+ `Status: ${summary.status.toUpperCase()}`,
223
+ `Breakages: ${summary.summary.breakages}`,
224
+ `Issues: ${summary.summary.issues}`,
225
+ `Artifacts: ${Object.values(summary.artifacts).filter(Boolean).length}`,
226
+ ].join("\n");
227
+ }
228
+
157
229
  function printHelp() {
158
230
  console.log(`plugin-inspector
159
231
 
@@ -163,7 +235,7 @@ Usage:
163
235
  plugin-inspector init [--plugin-root <path>] [--config <path>] [--ci] [--package-manager npm|pnpm|yarn|bun] [--force]
164
236
  plugin-inspector report --config <path> [--out <dir>] [--check] [--json]
165
237
  plugin-inspector inspect --config <path> [--out <dir>] [--check] [--json]
166
- plugin-inspector ci --config <path> [--out <dir>]
238
+ plugin-inspector ci [--plugin-root <path>] [--config <path>] [--out <dir>] [--openclaw <path>] [--no-openclaw] [--json]
167
239
  PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector capture <entrypoint> [--mock-sdk|--real-sdk] [--plugin-root <path>] [--output <path>]
168
240
 
169
241
  Default check runs from the current plugin root and writes reports/ unless --out is set.
@@ -29,6 +29,11 @@ export const contractProbeRules = {
29
29
  contract: "Every observed OpenClaw plugin SDK import remains exported by the target OpenClaw package.",
30
30
  target: "sdk-alias",
31
31
  },
32
+ "reserved-sdk-import": {
33
+ id: "sdk.import.reserved-bundled-plugin-boundary",
34
+ contract: "External plugins use documented public SDK subpaths instead of reserved bundled-plugin compatibility shims.",
35
+ target: "sdk-import",
36
+ },
32
37
  "provider-auth-env-vars": {
33
38
  id: "manifest.compat.provider-auth-env-vars",
34
39
  contract: "Legacy provider auth env metadata continues to map into config/help surfaces.",
@@ -626,7 +626,12 @@ function classifySdkImportCoverage({ fixture, fixtureReport, targetOpenClaw, war
626
626
 
627
627
  const sdkExports = new Set(targetOpenClaw.sdkExports);
628
628
  const unknownImports = fixtureReport.sdkImportDetails.filter((sdkImport) => !sdkExports.has(sdkImport.specifier));
629
- if (unknownImports.length === 0) {
629
+ const reservedSdkExports = new Set(targetOpenClaw.reservedSdkExports ?? []);
630
+ const reservedImports = fixtureReport.sdkImportDetails.filter((sdkImport) =>
631
+ reservedSdkExports.has(sdkImport.specifier),
632
+ );
633
+
634
+ if (reservedImports.length === 0 && unknownImports.length === 0) {
630
635
  logs.push({
631
636
  fixture: fixture.id,
632
637
  code: "sdk-exports-present",
@@ -637,21 +642,40 @@ function classifySdkImportCoverage({ fixture, fixtureReport, targetOpenClaw, war
637
642
  return;
638
643
  }
639
644
 
640
- warnings.push({
641
- fixture: fixture.id,
642
- code: "sdk-export-missing",
643
- level: "warning",
644
- message: "fixture imports plugin SDK aliases that are not exported by the target OpenClaw package",
645
- evidence: detailEvidence(unknownImports, "specifier"),
646
- compatRecord: "plugin-sdk-export-aliases",
647
- });
648
- decisions.push({
649
- fixture: fixture.id,
650
- decision: "core-compat-adapter",
651
- seam: "sdk-alias",
652
- action: "Restore the package export alias or publish a versioned migration map before cold-importing old plugins.",
653
- evidence: unique(unknownImports.map((sdkImport) => sdkImport.specifier)).join(", "),
654
- });
645
+ if (unknownImports.length > 0) {
646
+ warnings.push({
647
+ fixture: fixture.id,
648
+ code: "sdk-export-missing",
649
+ level: "warning",
650
+ message: "fixture imports plugin SDK aliases that are not exported by the target OpenClaw package",
651
+ evidence: detailEvidence(unknownImports, "specifier"),
652
+ compatRecord: "plugin-sdk-export-aliases",
653
+ });
654
+ decisions.push({
655
+ fixture: fixture.id,
656
+ decision: "core-compat-adapter",
657
+ seam: "sdk-alias",
658
+ action: "Restore the package export alias or publish a versioned migration map before cold-importing old plugins.",
659
+ evidence: unique(unknownImports.map((sdkImport) => sdkImport.specifier)).join(", "),
660
+ });
661
+ }
662
+
663
+ if (reservedImports.length > 0) {
664
+ warnings.push({
665
+ fixture: fixture.id,
666
+ code: "reserved-sdk-import",
667
+ level: "warning",
668
+ message: "fixture imports reserved bundled-plugin SDK compatibility subpaths",
669
+ evidence: detailEvidence(reservedImports, "specifier"),
670
+ });
671
+ decisions.push({
672
+ fixture: fixture.id,
673
+ decision: "plugin-upstream-fix",
674
+ seam: "sdk-import",
675
+ action: "Move the plugin to documented public SDK subpaths or plugin-local helpers before relying on this compatibility shim.",
676
+ evidence: unique(reservedImports.map((sdkImport) => sdkImport.specifier)).join(", "),
677
+ });
678
+ }
655
679
  }
656
680
 
657
681
  function classifyManifestFieldCoverage({ fixture, fixtureReport, targetOpenClaw, warnings, logs, decisions }) {
package/src/issues.js CHANGED
@@ -32,6 +32,7 @@ export const knownIssueCodes = new Set([
32
32
  "provider-auth-env-vars",
33
33
  "registration-capture-gap",
34
34
  "runtime-tool-capture",
35
+ "reserved-sdk-import",
35
36
  "sdk-export-missing",
36
37
  ]);
37
38
 
@@ -78,6 +79,12 @@ export const issueMetadataByCode = {
78
79
  decision: "core-compat-adapter",
79
80
  title: "plugin SDK import aliases are missing from target package exports",
80
81
  },
82
+ "reserved-sdk-import": {
83
+ severity: "P1",
84
+ owner: "plugin",
85
+ decision: "plugin-upstream-fix",
86
+ title: "plugin imports reserved bundled-plugin SDK compatibility subpaths",
87
+ },
81
88
  "missing-compat-record": {
82
89
  severity: "P1",
83
90
  owner: "core",
@@ -310,6 +317,7 @@ function issueClassFor(code, options) {
310
317
  "package-openclaw-entry-missing",
311
318
  "package-openclaw-metadata-missing",
312
319
  "package-plugin-api-compat-missing",
320
+ "reserved-sdk-import",
313
321
  ].includes(code)
314
322
  ) {
315
323
  return "upstream-metadata";
@@ -31,6 +31,7 @@ export async function readOpenClawTargetSurface(options = {}) {
31
31
  const apiBuilderPath = path.join(resolvedPath, "src/plugins/api-builder.ts");
32
32
  const capturedRegistrationPath = path.join(resolvedPath, "src/plugins/captured-registration.ts");
33
33
  const manifestTypesPath = path.join(resolvedPath, "src/plugins/manifest.ts");
34
+ const pluginSdkEntrypointsPath = path.join(resolvedPath, "src/plugin-sdk/entrypoints.ts");
34
35
  const packagePath = path.join(resolvedPath, "package.json");
35
36
 
36
37
  const registrySource = await readFile(registryPath, "utf8");
@@ -48,6 +49,18 @@ export async function readOpenClawTargetSurface(options = {}) {
48
49
  const sdkExports = existsSync(packagePath)
49
50
  ? parsePluginSdkExports(JSON.parse(await readFile(packagePath, "utf8")))
50
51
  : [];
52
+ const pluginSdkEntrypointsSource = existsSync(pluginSdkEntrypointsPath)
53
+ ? await readFile(pluginSdkEntrypointsPath, "utf8")
54
+ : "";
55
+ const reservedSdkExports = pluginSdkEntrypointsSource
56
+ ? parsePluginSdkEntrypointSpecifiers(pluginSdkEntrypointsSource, "reservedBundledPluginSdkEntrypoints")
57
+ : [];
58
+ const supportedFacadeSdkExports = pluginSdkEntrypointsSource
59
+ ? parsePluginSdkEntrypointSpecifiers(pluginSdkEntrypointsSource, "supportedBundledFacadeSdkEntrypoints")
60
+ : [];
61
+ const publicPluginOwnedSdkExports = pluginSdkEntrypointsSource
62
+ ? parsePluginSdkEntrypointSpecifiers(pluginSdkEntrypointsSource, "publicPluginOwnedSdkEntrypoints")
63
+ : [];
51
64
 
52
65
  return {
53
66
  configuredPath: requestedPath,
@@ -69,6 +82,13 @@ export async function readOpenClawTargetSurface(options = {}) {
69
82
  packagePath: existsSync(packagePath) ? relativePath(rootDir, packagePath) : null,
70
83
  sdkExportCount: sdkExports.length,
71
84
  sdkExports,
85
+ pluginSdkEntrypointsPath: existsSync(pluginSdkEntrypointsPath)
86
+ ? relativePath(rootDir, pluginSdkEntrypointsPath)
87
+ : null,
88
+ reservedSdkExportCount: reservedSdkExports.length,
89
+ reservedSdkExports,
90
+ supportedFacadeSdkExports,
91
+ publicPluginOwnedSdkExports,
72
92
  manifestTypesPath: existsSync(manifestTypesPath) ? relativePath(rootDir, manifestTypesPath) : null,
73
93
  manifestFieldCount: manifestFields.length,
74
94
  manifestFields,
@@ -149,11 +169,18 @@ function emptyTargetSurface({ configuredPath, searchedPaths = undefined, status
149
169
  apiRegistrars: [],
150
170
  capturedRegistrars: [],
151
171
  sdkExports: [],
172
+ reservedSdkExports: [],
173
+ supportedFacadeSdkExports: [],
174
+ publicPluginOwnedSdkExports: [],
152
175
  manifestFields: [],
153
176
  manifestContractFields: [],
154
177
  };
155
178
  }
156
179
 
180
+ export function parsePluginSdkEntrypointSpecifiers(source, exportName) {
181
+ return parseExportedStringArray(source, exportName).map((entrypoint) => `openclaw/plugin-sdk/${entrypoint}`).sort();
182
+ }
183
+
157
184
  function parseCapturedRegistrars(source) {
158
185
  return unique([...source.matchAll(/^\s*(register[A-Za-z0-9]+)\s*\(/gm)].map((match) => match[1])).sort();
159
186
  }
package/src/report.js CHANGED
@@ -160,6 +160,7 @@ export async function buildCompatibilityReport(options = {}) {
160
160
  warningCount: warnings.length,
161
161
  suggestionCount: suggestions.length,
162
162
  decisionCount: decisions.length,
163
+ logCount: logs.length,
163
164
  issueCount: issues.length,
164
165
  p0IssueCount: issues.filter((issue) => issue.severity === "P0").length,
165
166
  p1IssueCount: issues.filter((issue) => issue.severity === "P1").length,
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import { register } from "node:module";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ import { captureEntrypoint, runCapturedSyntheticProbes, writeArtifacts } from "./advanced.js";
8
+ import { createMockSdkPackage } from "./sdk-mock.js";
9
+
10
+ const args = process.argv.slice(2);
11
+
12
+ try {
13
+ await run(args);
14
+ } catch (error) {
15
+ console.error(error.message);
16
+ process.exitCode = 1;
17
+ }
18
+
19
+ async function run(commandArgs) {
20
+ const entrypoint = readFlag(commandArgs, "--entrypoint") ?? commandArgs.find((arg) => !arg.startsWith("-"));
21
+ const outputPath = readFlag(commandArgs, "--output");
22
+ const pluginRoot = readFlag(commandArgs, "--plugin-root");
23
+ const includeLifecycle = commandArgs.includes("--include-lifecycle");
24
+ const includeChannelRuntime = commandArgs.includes("--include-channel-runtime");
25
+ const includeProviderCapabilities = commandArgs.includes("--include-provider-capabilities");
26
+ const mockSdk = readMockSdkFlag(commandArgs) ?? true;
27
+
28
+ if (!entrypoint) {
29
+ throw new Error("synthetic probes require --entrypoint <path>");
30
+ }
31
+ if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
32
+ throw new Error("synthetic probes import plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
33
+ }
34
+
35
+ const capture = await captureForSyntheticProbes(entrypoint, {
36
+ mockSdk,
37
+ pluginRoot,
38
+ apiOptions: { retainHandlers: true },
39
+ });
40
+ const results = await runCapturedSyntheticProbes(capture, {
41
+ includeLifecycle,
42
+ includeChannelRuntime,
43
+ includeProviderCapabilities,
44
+ });
45
+ const json = `${JSON.stringify(results, null, 2)}\n`;
46
+
47
+ if (outputPath) {
48
+ await writeArtifacts([{ path: outputPath, content: json }]);
49
+ } else {
50
+ process.stdout.write(json);
51
+ }
52
+ }
53
+
54
+ async function captureForSyntheticProbes(entrypoint, options) {
55
+ if (options.mockSdk !== true) {
56
+ return captureEntrypoint(entrypoint, options);
57
+ }
58
+
59
+ const resolvedEntrypoint = path.resolve(process.cwd(), entrypoint);
60
+ const pluginRoot = path.resolve(process.cwd(), options.pluginRoot ?? path.dirname(resolvedEntrypoint));
61
+ const workspace = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-synthetic-mock-sdk-"));
62
+ try {
63
+ const { loaderPath } = await createMockSdkPackage(workspace, { pluginRoot });
64
+ register(pathToFileURL(loaderPath));
65
+ return captureEntrypoint(entrypoint, {
66
+ ...options,
67
+ mockSdk: false,
68
+ pluginRoot,
69
+ });
70
+ } finally {
71
+ await rm(workspace, { force: true, recursive: true });
72
+ }
73
+ }
74
+
75
+ function readFlag(commandArgs, name) {
76
+ const index = commandArgs.indexOf(name);
77
+ if (index === -1) {
78
+ return null;
79
+ }
80
+ return commandArgs[index + 1] ?? null;
81
+ }
82
+
83
+ function readMockSdkFlag(commandArgs) {
84
+ const sdk = readFlag(commandArgs, "--sdk");
85
+ if (sdk === "mock") {
86
+ return true;
87
+ }
88
+ if (sdk === "real") {
89
+ return false;
90
+ }
91
+ if (sdk && !["mock", "real"].includes(sdk)) {
92
+ throw new Error("--sdk must be mock or real");
93
+ }
94
+ if (commandArgs.includes("--mock-sdk")) {
95
+ return true;
96
+ }
97
+ if (commandArgs.includes("--real-sdk")) {
98
+ return false;
99
+ }
100
+ return undefined;
101
+ }
@@ -1,15 +1,16 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
4
5
  import { renderPaddedMarkdownTable, writeJsonMarkdownArtifacts } from "./artifacts.js";
5
6
  import { buildColdImportReadiness } from "./cold-import-readiness.js";
6
7
  import { normalizeRepoPath, posixJoin, slugForArtifact } from "./path-utils.js";
7
8
 
8
9
  export const defaultWorkspacePlanOptions = {
9
- captureScript: "plugin-inspector-capture",
10
+ captureScript: null,
10
11
  optInEnv: "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1",
11
12
  resultsRoot: ".plugin-inspector/results",
12
- syntheticProbeScript: "plugin-inspector-synthetic-probes",
13
+ syntheticProbeScript: null,
13
14
  workspaceRoot: ".plugin-inspector/workspaces",
14
15
  };
15
16
 
@@ -450,12 +451,23 @@ function runCommand(packageManager, script) {
450
451
 
451
452
  function captureCommand(settings, fixtureId, entrypoint, workspacePath) {
452
453
  const loader = entrypoint.blockers.some((blocker) => blocker.code === "ts-loader-required") ? " --import tsx" : "";
453
- return `${settings.optInEnv} node${loader} ${settings.captureScript} ${entrypoint.specifier} --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "capture")}`;
454
+ const script = helperScript(settings, workspacePath, settings.captureScript, "capture-cli.js");
455
+ return `${settings.optInEnv} node${loader} ${script} ${entrypoint.specifier} --mock-sdk --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "capture")}`;
454
456
  }
455
457
 
456
458
  function syntheticProbeCommand(settings, fixtureId, entrypoint, workspacePath) {
457
459
  const loader = entrypoint.blockers.some((blocker) => blocker.code === "ts-loader-required") ? " --import tsx" : "";
458
- return `${settings.optInEnv} node${loader} ${settings.syntheticProbeScript} --entrypoint ${entrypoint.specifier} --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "synthetic")}`;
460
+ const script = helperScript(settings, workspacePath, settings.syntheticProbeScript, "synthetic-probes-cli.js");
461
+ return `${settings.optInEnv} node${loader} ${script} --entrypoint ${entrypoint.specifier} --mock-sdk --output ${workspaceArtifactPath(settings, fixtureId, entrypoint, workspacePath, "synthetic")}`;
462
+ }
463
+
464
+ function helperScript(settings, workspacePath, configuredScript, helperFileName) {
465
+ if (configuredScript) {
466
+ return configuredScript;
467
+ }
468
+ const helperPath = fileURLToPath(new URL(`./${helperFileName}`, import.meta.url));
469
+ const workspaceFsPath = path.join(settings.rootDir, workspacePath);
470
+ return repoRelative(path.relative(workspaceFsPath, helperPath));
459
471
  }
460
472
 
461
473
  function targetOpenClawWorkspacePath(settings, fixtureId, targetOpenClawPath) {