@openclaw/plugin-inspector 0.1.0 → 0.1.2

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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 - 2026-04-27
4
+
5
+ ### Added
6
+
7
+ - Add public SDK subpath mocks, registrar return profiles, richer lifecycle capture probes, and plugin-root `init`/`--plugin-root` CLI flows.
8
+
9
+ ### Changed
10
+
11
+ - Harden runtime capture for TypeScript entrypoints, extensionless local imports, mocked external packages, namespace imports, async output capture, and explicit mock/real SDK lanes.
12
+ - Refresh README and CI examples around `npx @openclaw/plugin-inspector check --no-openclaw` and opt-in runtime capture.
13
+
14
+ ## 0.1.1 - 2026-04-27
15
+
16
+ ### Changed
17
+
18
+ - Refresh npm package docs with the simplified CLI-first README and public API surface cleanup.
19
+
3
20
  ## 0.1.0 - 2026-04-27
4
21
 
5
22
  Initial public package release for `@openclaw/plugin-inspector`.
package/README.md CHANGED
@@ -1,39 +1,46 @@
1
- # plugin-inspector
1
+ <img src="docs/plugin-inspector-banner.jpg" alt="openclaw plugin inspector banner"/>
2
2
 
3
- `plugin-inspector` is the reusable OpenClaw plugin compatibility inspector. It
4
- wraps the static inspection, registration capture, and report model prototyped
5
- in crabpot into an npm-publishable package.
3
+ # OpenClaw Plugin Inspector
6
4
 
7
- No npm package has been published yet.
5
+ `plugin-inspector` is the offline compatibility check for OpenClaw plugins. Run
6
+ it from a plugin root to inspect package metadata, `openclaw.plugin.json`, SDK
7
+ imports, `api.on(...)`, `api.register*`, and optional runtime registration
8
+ capture.
8
9
 
9
- ## Install
10
+ ## Quick Start
10
11
 
11
- During development, use a local checkout or packed tarball:
12
+ From a plugin package directory:
12
13
 
13
14
  ```bash
14
- npm install --save-dev ../plugin-inspector
15
- npx plugin-inspector check --no-openclaw
15
+ npx @openclaw/plugin-inspector
16
16
  ```
17
17
 
18
- After the package is published, plugin repos should install it as a dev
19
- dependency and run it from the plugin root:
18
+ That runs `check`, writes report artifacts to `reports/`, and exits non-zero
19
+ when compatibility breakages are found.
20
+
21
+ Add a local config and GitHub Actions workflow:
20
22
 
21
23
  ```bash
22
- npm install --save-dev @openclaw/plugin-inspector
23
- npx @openclaw/plugin-inspector check
24
+ npx @openclaw/plugin-inspector init --ci
24
25
  ```
25
26
 
26
- ## CLI
27
+ Or install it as a dev dependency:
27
28
 
28
- Run the default plugin-root check from a plugin package directory:
29
+ ```bash
30
+ npm install --save-dev @openclaw/plugin-inspector
31
+ npx plugin-inspector check
32
+ ```
33
+
34
+ ## Commands
29
35
 
30
36
  ```bash
31
- plugin-inspector check
37
+ npx @openclaw/plugin-inspector check
38
+ npx @openclaw/plugin-inspector check --plugin-root ./plugins/weather
39
+ npx @openclaw/plugin-inspector init --ci --package-manager pnpm
32
40
  ```
33
41
 
34
- That command reads the current directory as one plugin, inspects package
35
- metadata, `openclaw.plugin.json`, source imports, `api.on(...)`,
36
- `api.register*`, and writes:
42
+ `check` reads the current directory as one plugin unless `--plugin-root` is set.
43
+ It writes:
37
44
 
38
45
  - `reports/plugin-inspector-report.json`
39
46
  - `reports/plugin-inspector-report.md`
@@ -46,8 +53,8 @@ checkout:
46
53
  plugin-inspector check --no-openclaw
47
54
  ```
48
55
 
49
- Use a simple plugin-root config when you want stable fixture metadata or
50
- expected seams:
56
+ Use `plugin-inspector.config.json` when CI needs stable fixture metadata,
57
+ expected seams, or runtime capture defaults:
51
58
 
52
59
  ```json
53
60
  {
@@ -61,6 +68,9 @@ expected seams:
61
68
  "registrations": ["registerTool"]
62
69
  }
63
70
  },
71
+ "capture": {
72
+ "mockSdk": true
73
+ },
64
74
  "openclaw": {
65
75
  "defaultCheckoutPath": "../openclaw"
66
76
  }
@@ -73,48 +83,51 @@ Then run:
73
83
  plugin-inspector check --config plugin-inspector.config.json
74
84
  ```
75
85
 
76
- Copy-ready examples live in `examples/plugin-inspector.config.json` and
86
+ `init --ci` writes this shape for you, plus
87
+ `.github/workflows/plugin-inspector.yml`. Copy-ready examples also live in
88
+ `examples/plugin-inspector.config.json` and
77
89
  `examples/github-actions-plugin-inspector.yml`.
78
90
 
79
- Fixture-set configs are still supported for crabpot-style compatibility suites:
80
-
81
- ```bash
82
- plugin-inspector report --config crabpot.config.json --out reports
83
- ```
91
+ ## Runtime Capture
84
92
 
85
- Capture a plugin entrypoint in an explicitly isolated execution lane:
93
+ Runtime capture imports plugin entrypoints in an isolated subprocess and records
94
+ the registrations made during `register(api)`. It is opt-in because it executes
95
+ plugin code:
86
96
 
87
97
  ```bash
88
- PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector capture ./dist/index.js --mock-sdk
98
+ PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector check --runtime --mock-sdk
89
99
  ```
90
100
 
91
- Run the optional runtime capture smoke during `check`:
101
+ By default, runtime capture uses a generated mock for `openclaw/plugin-sdk` and
102
+ common external packages so plugin code can load in clean CI without OpenClaw
103
+ installed. Use `--real-sdk` only when the plugin workspace already has real SDK
104
+ dependencies installed and you intentionally want to test that path.
92
105
 
93
- ```bash
94
- PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector check --no-openclaw --capture
95
- ```
96
-
97
- Runtime capture creates a temporary mock `openclaw/plugin-sdk` package, imports
98
- declared OpenClaw package entrypoints, calls their `register(api)` function with
99
- the capture API, and writes:
106
+ Runtime capture writes:
100
107
 
101
108
  - `reports/plugin-inspector-runtime-capture.json`
102
109
  - `reports/plugin-inspector-runtime-capture.md`
103
110
 
104
- ### CI
111
+ You can also capture one entrypoint directly:
112
+
113
+ ```bash
114
+ PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector capture ./dist/index.js --mock-sdk
115
+ ```
116
+
117
+ ## CI
105
118
 
106
- With a dev dependency:
119
+ Minimal package scripts:
107
120
 
108
121
  ```json
109
122
  {
110
123
  "scripts": {
111
124
  "plugin:check": "plugin-inspector check --no-openclaw",
112
- "plugin:check:runtime": "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector check --no-openclaw --capture"
125
+ "plugin:check:runtime": "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector check --no-openclaw --runtime --mock-sdk"
113
126
  }
114
127
  }
115
128
  ```
116
129
 
117
- GitHub Actions:
130
+ GitHub Actions without a local dev dependency:
118
131
 
119
132
  ```yaml
120
133
  name: plugin-inspector
@@ -134,8 +147,8 @@ jobs:
134
147
  node-version: 24
135
148
  cache: npm
136
149
  - run: npm ci
137
- - run: npm run plugin:check
138
- - run: npm run plugin:check:runtime
150
+ - run: npx @openclaw/plugin-inspector check --no-openclaw
151
+ - run: PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector check --no-openclaw --runtime --mock-sdk
139
152
  - uses: actions/upload-artifact@v5
140
153
  if: always()
141
154
  with:
@@ -143,101 +156,31 @@ jobs:
143
156
  path: reports/plugin-inspector-*
144
157
  ```
145
158
 
146
- ## API
147
-
148
- ```js
149
- import {
150
- buildCiSummary,
151
- buildCiPolicyReport,
152
- buildColdImportReadiness,
153
- buildContractCapture,
154
- buildExecutionResultsReport,
155
- buildImportLoopProfile,
156
- buildPlatformProbes,
157
- buildProfileDiff,
158
- buildRefDiff,
159
- buildRuntimeProfile,
160
- buildRuntimeCaptureReport,
161
- buildWorkspacePlan,
162
- createCaptureApi,
163
- inspectFixtureSet,
164
- loadInspectorConfig,
165
- readOpenClawTargetSurface,
166
- renderCiPolicyMarkdown,
167
- renderColdImportReadinessMarkdown,
168
- renderContractCaptureMarkdown,
169
- renderExecutionResultsMarkdown,
170
- renderImportLoopProfileMarkdown,
171
- renderPlatformProbesMarkdown,
172
- renderProfileDiffMarkdown,
173
- renderRefDiffMarkdown,
174
- renderRuntimeProfileMarkdown,
175
- renderRuntimeCaptureMarkdown,
176
- renderWorkspacePlanMarkdown,
177
- renderMarkdownReport,
178
- validateCiPolicyReport,
179
- validateContractCoverage,
180
- writeCiSummary,
181
- writeCiPolicyReport,
182
- writeColdImportReadiness,
183
- writeContractCapture,
184
- writeExecutionResultsReport,
185
- writeImportLoopProfile,
186
- writePlatformProbes,
187
- writeProfileDiff,
188
- writeRefDiff,
189
- writeRuntimeProfile,
190
- writeRuntimeCaptureReport,
191
- writeWorkspacePlan,
192
- writeReport,
193
- } from "@openclaw/plugin-inspector";
194
-
195
- const config = await loadInspectorConfig("crabpot.config.json");
196
- const report = await inspectFixtureSet(config);
197
- await writeReport(report, { outDir: "reports" });
198
-
199
- const summary = await buildCiSummary({ reportsDir: "reports" });
200
- await writeCiSummary(summary);
201
-
202
- const policyReport = buildCiPolicyReport({ policy, compatibilityReport: report });
203
- await writeCiPolicyReport(policyReport);
204
-
205
- const capture = buildContractCapture({ report });
206
- await writeContractCapture(capture);
207
- const coverageErrors = validateContractCoverage(report);
208
-
209
- const readiness = buildColdImportReadiness({ report });
210
- await writeColdImportReadiness(readiness);
211
-
212
- const target = await readOpenClawTargetSurface({ manifest: config });
213
-
214
- const workspacePlan = await buildWorkspacePlan({ report, readiness });
215
- await writeWorkspacePlan(workspacePlan);
216
-
217
- const platformProbes = buildPlatformProbes({ plan: workspacePlan });
218
- await writePlatformProbes(platformProbes);
219
-
220
- const executionResults = await buildExecutionResultsReport({ resultsDir: ".plugin-inspector/results" });
221
- await writeExecutionResultsReport(executionResults);
222
-
223
- const importLoop = await buildImportLoopProfile({ entrypoint: "dist/index.js", runs: 3 });
224
- await writeImportLoopProfile(importLoop);
225
-
226
- const runtimeProfile = await buildRuntimeProfile({
227
- commands: [{ id: "node-boot", label: "Node boot", category: "baseline", args: ["-e", "0"] }],
228
- });
229
- await writeRuntimeProfile(runtimeProfile);
230
-
231
- const runtimeCapture = await buildRuntimeCaptureReport({ report, rootDir: process.cwd() });
232
- await writeRuntimeCaptureReport(runtimeCapture);
233
-
234
- const refDiff = await buildRefDiff({ baseReport, headReport });
235
- await writeRefDiff(refDiff);
236
-
237
- const profileDiff = await buildProfileDiff({ current, baseline, policy });
238
- await writeProfileDiff(profileDiff);
159
+ ## Fixture Suites
160
+
161
+ Fixture-set configs are still supported for crabpot-style compatibility suites:
162
+
163
+ ```bash
164
+ plugin-inspector report --config crabpot.config.json --out reports
239
165
  ```
240
166
 
167
+ Use fixture suites when one repo wants to inspect many plugins. Use plugin-root
168
+ `check` for normal plugin CI.
169
+
170
+ ## Mocking Model
171
+
172
+ Default inspection is static, offline, and credential-free. Runtime capture is
173
+ the only mode that imports plugin code.
174
+
175
+ When `--mock-sdk` is enabled, the inspector generates temporary modules for
176
+ `openclaw/plugin-sdk` subpaths and unresolved external packages discovered in
177
+ the plugin import graph. The mock SDK captures registrations; it does not call
178
+ network services, launch OpenClaw, run provider SDKs, or emulate service
179
+ lifecycle side effects.
180
+
181
+ Use the mock lane for plugin compatibility CI. Keep live provider/service tests
182
+ in the plugin repo behind their own credentials and explicit opt-in flags.
183
+
241
184
  ## Scope
242
185
 
243
186
  Default inspection is offline and credential-free. It reads manifests, package
@@ -246,5 +189,5 @@ metadata, and source files, then reports observed `api.on(...)`,
246
189
  OpenClaw target checkout parsing is limited to public compatibility registries,
247
190
  SDK package exports, manifest types, hooks, and captured registrar metadata.
248
191
 
249
- Cold import capture and synthetic contract probes are explicit opt-in modes.
250
- Live lanes will stay credential-gated and must never run in default CI.
192
+ Cold import capture, synthetic contract probes, and runtime capture are explicit
193
+ opt-in modes. Live lanes stay credential-gated and must never run in default CI.
@@ -15,8 +15,8 @@ jobs:
15
15
  node-version: 24
16
16
  cache: npm
17
17
  - run: npm ci
18
- - run: npm run plugin:check
19
- - run: npm run plugin:check:runtime
18
+ - run: npx @openclaw/plugin-inspector check --no-openclaw
19
+ - run: PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector check --no-openclaw --runtime --mock-sdk
20
20
  - uses: actions/upload-artifact@v5
21
21
  if: always()
22
22
  with:
@@ -9,6 +9,9 @@
9
9
  "registrations": ["registerTool"]
10
10
  }
11
11
  },
12
+ "capture": {
13
+ "mockSdk": true
14
+ },
12
15
  "openclaw": {
13
16
  "defaultCheckoutPath": "../openclaw"
14
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/plugin-inspector",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "description": "Offline compatibility inspector for OpenClaw plugins.",
6
6
  "type": "module",
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "exports": {
24
24
  ".": "./src/index.js",
25
+ "./advanced": "./src/advanced.js",
25
26
  "./capture-api": "./src/capture-api.js",
26
27
  "./ci-policy": "./src/ci-policy.js",
27
28
  "./cold-import-readiness": "./src/cold-import-readiness.js",
@@ -45,7 +46,7 @@
45
46
  "LICENSE"
46
47
  ],
47
48
  "scripts": {
48
- "check": "npm test && npm pack --dry-run && npm publish --dry-run --access public",
49
+ "check": "npm test && npm pack --dry-run",
49
50
  "release:local": "npm run check",
50
51
  "test": "node --test test/*.test.js"
51
52
  },
@@ -0,0 +1,195 @@
1
+ export {
2
+ escapeMarkdownTableCell,
3
+ renderArtifactContent,
4
+ renderMarkdownTable,
5
+ renderPaddedMarkdownTable,
6
+ writeArtifacts,
7
+ writeJsonMarkdownArtifacts,
8
+ } from "./artifacts.js";
9
+ export {
10
+ normalizeRepoPath,
11
+ posixJoin,
12
+ resolveFromRoot,
13
+ resolveRequiredFromRoot,
14
+ slugForArtifact,
15
+ toRepoPath,
16
+ } from "./path-utils.js";
17
+ export { readJsonFile, readOptionalJsonFile } from "./json-file.js";
18
+ export { assertRunCount, percentile } from "./stats.js";
19
+ export { createCaptureApi } from "./capture-api.js";
20
+ export {
21
+ buildCiPolicyReport,
22
+ defaultCiPolicyReportOptions,
23
+ renderCiPolicyMarkdown,
24
+ validateCiPolicy,
25
+ validateCiPolicyReport,
26
+ writeCiPolicyReport,
27
+ } from "./ci-policy.js";
28
+ export {
29
+ buildCiSummary,
30
+ defaultCiReportPaths,
31
+ deriveCiStatus,
32
+ readCiReports,
33
+ renderCiSummaryMarkdown,
34
+ writeCiSummary,
35
+ } from "./ci-summary.js";
36
+ export {
37
+ buildContractProbes,
38
+ contractProbeRules,
39
+ probePriority,
40
+ } from "./contract-probes.js";
41
+ export {
42
+ buildContractCapture,
43
+ defaultHookAssertions,
44
+ defaultHookContexts,
45
+ defaultHookEvents,
46
+ defaultRegistrationArguments,
47
+ defaultRegistrationAssertions,
48
+ renderContractCaptureMarkdown,
49
+ validateContractCapture,
50
+ writeContractCapture,
51
+ } from "./contract-capture.js";
52
+ export {
53
+ renderCompatibilityIssuesReport,
54
+ renderCompatibilityMarkdownReport,
55
+ } from "./compatibility-report.js";
56
+ export {
57
+ knownIssueClasses,
58
+ validateContractCoverage,
59
+ } from "./contract-coverage.js";
60
+ export {
61
+ buildColdImportReadiness,
62
+ renderColdImportReadinessMarkdown,
63
+ validateColdImportReadiness,
64
+ writeColdImportReadiness,
65
+ } from "./cold-import-readiness.js";
66
+ export {
67
+ buildIssues,
68
+ classifyIssueFinding,
69
+ deprecatedCompatRecords,
70
+ issueId,
71
+ issueMetadata,
72
+ issueMetadataByCode,
73
+ knownIssueCodes,
74
+ summarizeIssueClasses,
75
+ } from "./issues.js";
76
+ export {
77
+ buildExecutionResultsReport,
78
+ defaultExecutionResultsOptions,
79
+ renderExecutionResultsMarkdown,
80
+ writeExecutionResultsReport,
81
+ } from "./execution-results.js";
82
+ export {
83
+ buildCompatibilityFixtureReport,
84
+ classifyCompatibilityFixture,
85
+ classifyPackageContracts,
86
+ classifyTargetOpenClawCoverage,
87
+ readPackageSummaries,
88
+ readPluginManifests,
89
+ summarizePackage,
90
+ } from "./fixture-summary.js";
91
+ export {
92
+ buildImportLoopProfile,
93
+ defaultImportLoopProfileOptions,
94
+ renderImportLoopProfileMarkdown,
95
+ validateImportLoopProfile,
96
+ writeImportLoopProfile,
97
+ } from "./import-loop-profile.js";
98
+ export {
99
+ defaultOpenClawCheckoutPaths,
100
+ openClawTargetPathCandidates,
101
+ parseCompatRecordEntries,
102
+ parseExportedStringArray,
103
+ parsePluginSdkExports,
104
+ parseTypeFields,
105
+ readOpenClawTargetSurface,
106
+ } from "./openclaw-target.js";
107
+ export {
108
+ captureEntrypoint,
109
+ captureEntrypointWithMockSdk,
110
+ inspectCompatibilityFixtureSet,
111
+ inspectFixtureSet,
112
+ inspectPlugin,
113
+ inspectSourceText,
114
+ } from "./inspector.js";
115
+ export {
116
+ defaultPluginRootConfigFiles,
117
+ fixtureCheckoutPath,
118
+ fixtureSourceRoot,
119
+ inferPluginSeams,
120
+ loadInspectorConfig,
121
+ loadPluginRootConfig,
122
+ normalizeInspectorConfig,
123
+ normalizePluginRootConfig,
124
+ packageId,
125
+ validateInspectorConfig,
126
+ } from "./config.js";
127
+ export {
128
+ buildPluginInspectorConfig,
129
+ defaultInitConfigPath,
130
+ defaultInitWorkflowPath,
131
+ renderGithubActionsWorkflow,
132
+ writePluginInspectorInit,
133
+ } from "./init.js";
134
+ export {
135
+ buildPlatformProbes,
136
+ defaultPlatformTargets,
137
+ renderPlatformProbesMarkdown,
138
+ validatePlatformProbes,
139
+ writePlatformProbes,
140
+ } from "./platform-probes.js";
141
+ export {
142
+ buildProfileDiff,
143
+ defaultProfileDiffOptions,
144
+ renderProfileDiffMarkdown,
145
+ validateProfileDiff,
146
+ writeProfileDiff,
147
+ } from "./profile-diff.js";
148
+ export {
149
+ buildRefDiff,
150
+ defaultRefDiffDimensions,
151
+ defaultRefDiffOptions,
152
+ renderRefDiffMarkdown,
153
+ validateRefDiff,
154
+ writeRefDiff,
155
+ } from "./ref-diff.js";
156
+ export {
157
+ buildCompatibilityReport,
158
+ classifyCompatRecordCoverage,
159
+ renderMarkdownReport,
160
+ renderTextSummary,
161
+ writeCompatibilityReport,
162
+ writeReport,
163
+ } from "./report.js";
164
+ export {
165
+ buildRuntimeProfile,
166
+ defaultRuntimeProfileCommands,
167
+ defaultRuntimeProfileOptions,
168
+ renderRuntimeProfileMarkdown,
169
+ validateRuntimeProfile,
170
+ writeRuntimeProfile,
171
+ } from "./runtime-profile.js";
172
+ export {
173
+ buildRuntimeCaptureReport,
174
+ renderRuntimeCaptureMarkdown,
175
+ writeRuntimeCaptureReport,
176
+ } from "./runtime-capture-report.js";
177
+ export { createMockSdkPackage } from "./sdk-mock.js";
178
+ export {
179
+ buildSyntheticProbePlan,
180
+ defaultSyntheticHookContexts,
181
+ defaultSyntheticHookEvents,
182
+ defaultSyntheticRegistrationArguments,
183
+ renderSyntheticProbeMarkdown,
184
+ runCapturedSyntheticProbes,
185
+ syntheticRegistrationExecutionProfiles,
186
+ validateSyntheticProbePlan,
187
+ writeSyntheticProbePlan,
188
+ } from "./synthetic-probes.js";
189
+ export {
190
+ buildWorkspacePlan,
191
+ defaultWorkspacePlanOptions,
192
+ renderWorkspacePlanMarkdown,
193
+ validateWorkspacePlan,
194
+ writeWorkspacePlan,
195
+ } from "./workspace-plan.js";
package/src/api.js ADDED
@@ -0,0 +1,91 @@
1
+ import path from "node:path";
2
+ import { createCaptureApi } from "./capture-api.js";
3
+ import { loadInspectorConfig, loadPluginRootConfig } from "./config.js";
4
+ import { writePluginInspectorInit } from "./init.js";
5
+ import { captureEntrypoint } from "./inspector.js";
6
+ import { renderTextSummary, writeCompatibilityReport } from "./report.js";
7
+ import { buildRuntimeCaptureReport, writeRuntimeCaptureReport } from "./runtime-capture-report.js";
8
+ import { inspectCompatibilityFixtureSet, inspectFixtureSet } from "./inspector.js";
9
+
10
+ export async function loadPluginConfig(options = {}) {
11
+ if (options.config) {
12
+ return options.config;
13
+ }
14
+ const cwd = options.pluginRoot ?? options.cwd;
15
+ if (options.configPath) {
16
+ return options.fixtureSet === true
17
+ ? loadInspectorConfig(options.configPath, { cwd })
18
+ : loadPluginRootConfig(options.configPath, { cwd });
19
+ }
20
+ return loadPluginRootConfig(null, { cwd });
21
+ }
22
+
23
+ export async function inspectPluginRoot(options = {}) {
24
+ const config = await loadPluginConfig(options);
25
+ return inspectCompatibilityFixtureSet(config, {
26
+ generatedAt: options.generatedAt,
27
+ openclawPath: options.openclawPath,
28
+ targetOpenClaw: options.targetOpenClaw,
29
+ });
30
+ }
31
+
32
+ export async function inspectFixtureSetConfig(options = {}) {
33
+ const config = options.config ?? (await loadInspectorConfig(options.configPath, { cwd: options.cwd }));
34
+ return inspectFixtureSet(config, { generatedAt: options.generatedAt });
35
+ }
36
+
37
+ export async function writePluginReports(report, options = {}) {
38
+ return writeCompatibilityReport(report, {
39
+ basename: options.basename,
40
+ check: options.check,
41
+ cwd: options.cwd ?? options.pluginRoot,
42
+ issuesBasename: options.issuesBasename,
43
+ outDir: options.outDir,
44
+ });
45
+ }
46
+
47
+ export async function runPluginCheck(options = {}) {
48
+ const outDir = options.outDir ?? "reports";
49
+ const config = await loadPluginConfig(options);
50
+ const report = await inspectPluginRoot({ ...options, config });
51
+ const paths = await writePluginReports(report, { ...options, pluginRoot: config.rootDir, outDir });
52
+ const result = { report, paths };
53
+ const capture = options.capture ?? config.capture?.runtime ?? false;
54
+ const mockSdk = options.mockSdk ?? config.capture?.mockSdk ?? true;
55
+
56
+ if (capture === true) {
57
+ if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
58
+ throw new Error("runtime capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
59
+ }
60
+ const runtimeCapture = await buildRuntimeCaptureReport({
61
+ mockSdk,
62
+ report,
63
+ rootDir: config.rootDir,
64
+ });
65
+ const runtimeCapturePaths = await writeRuntimeCaptureReport(runtimeCapture, {
66
+ jsonPath: path.resolve(config.rootDir, outDir, "plugin-inspector-runtime-capture.json"),
67
+ markdownPath: path.resolve(config.rootDir, outDir, "plugin-inspector-runtime-capture.md"),
68
+ });
69
+ result.runtimeCapture = runtimeCapture;
70
+ result.runtimeCapturePaths = runtimeCapturePaths;
71
+ if (runtimeCapture.summary.failedCount > 0) {
72
+ throw new Error(`plugin-inspector runtime capture failed for ${runtimeCapture.summary.failedCount} entrypoints`);
73
+ }
74
+ }
75
+
76
+ if (options.failOnBreakages === true && report.status !== "pass") {
77
+ throw new Error(`plugin-inspector found ${report.summary.breakageCount} breakages`);
78
+ }
79
+
80
+ return result;
81
+ }
82
+
83
+ export async function capturePluginEntrypoint(entrypoint, options = {}) {
84
+ return captureEntrypoint(entrypoint, options);
85
+ }
86
+
87
+ export async function setupPluginInspector(options = {}) {
88
+ return writePluginInspectorInit(options);
89
+ }
90
+
91
+ export { createCaptureApi, renderTextSummary };