@openclaw/plugin-inspector 0.2.0 → 0.3.1

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,43 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.3.1 - 2026-04-28
6
+
7
+ ### Added
8
+
9
+ - Add grouped root facades: `pluginRoot`, `fixtureSuites`, `staticInspection`, `reports`, `contracts`, `ci`, `runtime`, and `synthetic`.
10
+ - Expose contract capture, contract coverage, CI rollup, runtime profile, ref/profile diff, import-loop, and synthetic probe helpers from the root package API.
11
+ - Add a release follow-through guard that fails when Crabpot scripts regress to the legacy `advanced.js` bundle.
12
+ - Add a package-contents release guard for npm tarball entrypoints, examples, and README assets.
13
+
14
+ ### Changed
15
+
16
+ - Move Crabpot integration scripts to the root public API while keeping Crabpot as the fixture corpus and report consumer.
17
+ - Keep generic artifact writing out of the root API; Crabpot-owned runner scripts write their own JSON outputs.
18
+ - Ship the README banner asset in the npm package so the published README does not reference a missing local image.
19
+ - Document the grouped root import path for embedding harnesses without turning the README into a full API dump.
20
+
21
+ ## 0.3.0 - 2026-04-27
22
+
23
+ ### Added
24
+
25
+ - Add `--allow-execute` as a cross-platform runtime capture opt-in flag.
26
+ - Add `plugin-inspector init --dry-run` for setup previews.
27
+ - Add `plugin-inspector init --json` for machine-readable setup summaries.
28
+ - Add `plugin-inspector init --scripts` for `plugin:check` and `plugin:ci` package scripts.
29
+ - Add public fixture-set report helpers and synthetic probe suite helpers for Crabpot and downstream compatibility suites.
30
+ - Add a Crabpot follow-through release checklist for source refs, package pins, and smoke commands.
31
+
32
+ ### Changed
33
+
34
+ - Make generated runtime CI commands use `--allow-execute` instead of shell-specific inline environment syntax.
35
+ - Make `plugin-inspector init --ci` detect `packageManager` and common lockfiles before generating CI install/run commands.
36
+ - Make `plugin-inspector init` output repo-relative file paths and preflight generated files before writing.
37
+ - Make `plugin-inspector init` infer `sourceRoot: "src"` from package export maps like `"./src/index.js"`.
38
+ - Improve CLI failure summaries with report artifact paths and top blocking findings.
39
+ - Harden mock SDK capture by keeping generated loader fixtures available until subprocess exit.
40
+
3
41
  ## 0.2.0 - 2026-04-27
4
42
 
5
43
  ### Added
package/README.md CHANGED
@@ -18,12 +18,25 @@ npx @openclaw/plugin-inspector
18
18
  That runs `check`, writes report artifacts to `reports/`, and exits non-zero
19
19
  when compatibility breakages are found.
20
20
 
21
+ Package-manager equivalents:
22
+
23
+ ```bash
24
+ pnpm dlx @openclaw/plugin-inspector
25
+ yarn dlx @openclaw/plugin-inspector
26
+ bunx @openclaw/plugin-inspector
27
+ ```
28
+
21
29
  Add a local config and GitHub Actions workflow:
22
30
 
23
31
  ```bash
24
32
  npx @openclaw/plugin-inspector init --ci
25
33
  ```
26
34
 
35
+ `init --ci` detects `packageManager` and common lockfiles. Pass
36
+ `--package-manager pnpm`, `npm`, `yarn`, or `bun` when you want to override it.
37
+ Add `--scripts` to write `plugin:check` and `plugin:ci` package scripts.
38
+ Use `--dry-run` to preview the files first.
39
+
27
40
  Or install it as a dev dependency:
28
41
 
29
42
  ```bash
@@ -31,6 +44,18 @@ npm install --save-dev @openclaw/plugin-inspector
31
44
  npx plugin-inspector check
32
45
  ```
33
46
 
47
+ With a local dev dependency, prefer package scripts so CI and local checks use
48
+ the same command:
49
+
50
+ ```json
51
+ {
52
+ "scripts": {
53
+ "plugin:check": "plugin-inspector inspect --no-openclaw",
54
+ "plugin:ci": "plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute"
55
+ }
56
+ }
57
+ ```
58
+
34
59
  ## Commands
35
60
 
36
61
  ```bash
@@ -40,6 +65,8 @@ npx @openclaw/plugin-inspector ci --no-openclaw
40
65
  npx @openclaw/plugin-inspector config
41
66
  npx @openclaw/plugin-inspector check --plugin-root ./plugins/weather
42
67
  npx @openclaw/plugin-inspector init --ci --package-manager pnpm
68
+ npx @openclaw/plugin-inspector init --ci --scripts --dry-run
69
+ npx @openclaw/plugin-inspector init --ci --scripts --dry-run --json
43
70
  ```
44
71
 
45
72
  `check` and `inspect` read the current directory as one plugin unless
@@ -132,7 +159,8 @@ For a single plugin package, the same config can live in `package.json`:
132
159
  `.github/workflows/plugin-inspector.yml`. Copy-ready examples also live in
133
160
  `examples/plugin-inspector.config.json` and
134
161
  `examples/package-json-plugin-inspector.json` and
135
- `examples/github-actions-plugin-inspector.yml`.
162
+ `examples/github-actions-plugin-inspector.yml`. SARIF/JUnit CI consumption
163
+ examples live alongside them.
136
164
 
137
165
  ## Runtime Capture
138
166
 
@@ -141,9 +169,13 @@ the registrations made during `register(api)`. It is opt-in because it executes
141
169
  plugin code:
142
170
 
143
171
  ```bash
144
- PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector check --runtime --mock-sdk
172
+ npx @openclaw/plugin-inspector check --runtime --mock-sdk --allow-execute
145
173
  ```
146
174
 
175
+ `--allow-execute` is the explicit guard for modes that import plugin code. The
176
+ older `PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1` environment guard still works for
177
+ custom harnesses.
178
+
147
179
  By default, runtime capture uses a generated mock for `openclaw/plugin-sdk` and
148
180
  common external packages so plugin code can load in clean CI without OpenClaw
149
181
  installed. Use `--real-sdk` only when the plugin workspace already has real SDK
@@ -157,7 +189,7 @@ Runtime capture writes:
157
189
  You can also capture one entrypoint directly:
158
190
 
159
191
  ```bash
160
- PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector capture ./dist/index.js --mock-sdk
192
+ plugin-inspector capture ./dist/index.js --mock-sdk --allow-execute
161
193
  ```
162
194
 
163
195
  ## CI
@@ -168,7 +200,7 @@ Minimal package scripts:
168
200
  {
169
201
  "scripts": {
170
202
  "plugin:check": "plugin-inspector inspect --no-openclaw",
171
- "plugin:ci": "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector ci --no-openclaw --runtime --mock-sdk"
203
+ "plugin:ci": "plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute"
172
204
  }
173
205
  }
174
206
  ```
@@ -193,7 +225,7 @@ jobs:
193
225
  node-version: 24
194
226
  cache: npm
195
227
  - run: npm ci
196
- - run: PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk
228
+ - run: npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
197
229
  - uses: actions/upload-artifact@v5
198
230
  if: always()
199
231
  with:
@@ -204,6 +236,15 @@ jobs:
204
236
  `ci` writes the normal report, CI summary, SARIF, and JUnit files by default.
205
237
  Pass `--no-sarif` or `--no-junit` only if your CI surface cannot consume them.
206
238
 
239
+ For GitHub code scanning, use
240
+ `examples/github-actions-code-scanning.yml`; it uploads
241
+ `reports/plugin-inspector.sarif` through CodeQL's SARIF upload action.
242
+
243
+ For CI test-summary UIs, point JUnit ingestion at
244
+ `reports/plugin-inspector.junit.xml`. Copy-ready GitLab and CircleCI examples
245
+ live in `examples/gitlab-ci-plugin-inspector.yml` and
246
+ `examples/circleci-plugin-inspector.yml`.
247
+
207
248
  ## Fixture Suites
208
249
 
209
250
  Fixture-set configs are still supported for crabpot-style compatibility suites:
@@ -215,6 +256,26 @@ plugin-inspector report --config crabpot.config.json --out reports
215
256
  Use fixture suites when one repo wants to inspect many plugins. Use plugin-root
216
257
  `check` for normal plugin CI.
217
258
 
259
+ ## Library Use
260
+
261
+ Most plugin repos should use the CLI. Harnesses can import grouped root helpers
262
+ when they need to embed the inspector:
263
+
264
+ ```js
265
+ import { pluginRoot, fixtureSuites, contracts, ci } from "@openclaw/plugin-inspector";
266
+
267
+ const { report } = await pluginRoot.runCheck({
268
+ pluginRoot: process.cwd(),
269
+ openclawPath: false,
270
+ });
271
+ const capture = contracts.buildCapture({ report });
272
+ const summary = await ci.buildSummary({ reports: { compatibility: report } });
273
+ ```
274
+
275
+ The root package groups stable workflows as `pluginRoot`, `fixtureSuites`,
276
+ `staticInspection`, `reports`, `contracts`, `ci`, `runtime`, and `synthetic`.
277
+ Named exports remain available for existing automation.
278
+
218
279
  ## Mocking Model
219
280
 
220
281
  Default inspection is static, offline, and credential-free. Runtime capture is
Binary file
@@ -0,0 +1,19 @@
1
+ version: 2.1
2
+
3
+ jobs:
4
+ plugin-inspector:
5
+ docker:
6
+ - image: cimg/node:24.0
7
+ steps:
8
+ - checkout
9
+ - run: npm ci
10
+ - run: npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
11
+ - store_test_results:
12
+ path: reports
13
+ - store_artifacts:
14
+ path: reports
15
+
16
+ workflows:
17
+ plugin-inspector:
18
+ jobs:
19
+ - plugin-inspector
@@ -0,0 +1,31 @@
1
+ name: plugin-inspector
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+ security-events: write
11
+
12
+ jobs:
13
+ check:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v5
17
+ - uses: actions/setup-node@v5
18
+ with:
19
+ node-version: 24
20
+ cache: npm
21
+ - run: npm ci
22
+ - run: npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
23
+ - uses: github/codeql-action/upload-sarif@v3
24
+ if: always()
25
+ with:
26
+ sarif_file: reports/plugin-inspector.sarif
27
+ - uses: actions/upload-artifact@v5
28
+ if: always()
29
+ with:
30
+ name: plugin-inspector-reports
31
+ path: reports/plugin-inspector-*
@@ -15,7 +15,7 @@ jobs:
15
15
  node-version: 24
16
16
  cache: npm
17
17
  - run: npm ci
18
- - run: PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk
18
+ - run: npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
19
19
  - uses: actions/upload-artifact@v5
20
20
  if: always()
21
21
  with:
@@ -0,0 +1,11 @@
1
+ plugin_inspector:
2
+ image: node:24
3
+ script:
4
+ - npm ci
5
+ - npx @openclaw/plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute
6
+ artifacts:
7
+ when: always
8
+ paths:
9
+ - reports/plugin-inspector-*
10
+ reports:
11
+ junit: reports/plugin-inspector.junit.xml
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "scripts": {
3
3
  "plugin:check": "plugin-inspector inspect --no-openclaw",
4
- "plugin:ci": "PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 plugin-inspector ci --no-openclaw --runtime --mock-sdk"
4
+ "plugin:ci": "plugin-inspector ci --no-openclaw --runtime --mock-sdk --allow-execute"
5
5
  },
6
6
  "pluginInspector": {
7
7
  "version": 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/plugin-inspector",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Offline compatibility inspector for OpenClaw plugins.",
6
6
  "type": "module",
@@ -36,18 +36,26 @@
36
36
  "./ref-diff": "./src/ref-diff.js",
37
37
  "./runtime-capture-report": "./src/runtime-capture-report.js",
38
38
  "./runtime-profile": "./src/runtime-profile.js",
39
+ "./synthetic-probe-suite": "./src/synthetic-probe-suite.js",
40
+ "./synthetic-probes": "./src/synthetic-probes.js",
39
41
  "./workspace-plan": "./src/workspace-plan.js"
40
42
  },
41
43
  "files": [
42
44
  "src",
43
45
  "examples",
46
+ "docs/plugin-inspector-banner.jpg",
44
47
  "README.md",
45
48
  "CHANGELOG.md",
46
49
  "LICENSE"
47
50
  ],
48
51
  "scripts": {
49
- "check": "npm test && npm pack --dry-run",
52
+ "check": "npm test && npm run release:contents",
53
+ "release:crabpot": "node scripts/check-crabpot-followthrough.mjs",
54
+ "release:contents": "node scripts/check-package-contents.mjs",
55
+ "release:plan": "node scripts/release-plan.mjs",
56
+ "release:readiness": "npm run release:local && npm run release:crabpot",
50
57
  "release:local": "npm run check",
58
+ "release:notes": "node scripts/release-notes.mjs --unreleased",
51
59
  "test": "node --test test/*.test.js"
52
60
  },
53
61
  "keywords": [
package/src/advanced.js CHANGED
@@ -136,8 +136,10 @@ export {
136
136
  } from "./config.js";
137
137
  export {
138
138
  buildPluginInspectorConfig,
139
+ defaultInitPackageScripts,
139
140
  defaultInitConfigPath,
140
141
  defaultInitWorkflowPath,
142
+ detectPackageManager,
141
143
  renderGithubActionsWorkflow,
142
144
  writePluginInspectorInit,
143
145
  } from "./init.js";
@@ -196,6 +198,7 @@ export {
196
198
  validateSyntheticProbePlan,
197
199
  writeSyntheticProbePlan,
198
200
  } from "./synthetic-probes.js";
201
+ export { buildSyntheticProbePlanFromReport } from "./synthetic-probe-suite.js";
199
202
  export {
200
203
  buildWorkspacePlan,
201
204
  defaultWorkspacePlanOptions,
@@ -203,3 +206,10 @@ export {
203
206
  validateWorkspacePlan,
204
207
  writeWorkspacePlan,
205
208
  } from "./workspace-plan.js";
209
+ export {
210
+ inspectCompatibilityFixtureSetConfig,
211
+ renderFixtureSetIssuesReport,
212
+ renderFixtureSetMarkdownReport,
213
+ runFixtureSetReport,
214
+ writeFixtureSetReports,
215
+ } from "./api.js";
package/src/api.js CHANGED
@@ -1,12 +1,31 @@
1
1
  import path from "node:path";
2
2
  import { createCaptureApi } from "./capture-api.js";
3
3
  import { loadInspectorConfig, loadPluginRootConfig } from "./config.js";
4
+ import { renderCompatibilityIssuesReport, renderCompatibilityMarkdownReport } from "./compatibility-report.js";
4
5
  import { writePluginInspectorInit } from "./init.js";
5
6
  import { captureEntrypoint } from "./inspector.js";
6
7
  import { renderTextSummary, writeCompatibilityReport } from "./report.js";
7
8
  import { writeCiOutputArtifacts } from "./ci-outputs.js";
8
9
  import { buildRuntimeCaptureReport, writeRuntimeCaptureReport } from "./runtime-capture-report.js";
9
10
  import { inspectCompatibilityFixtureSet, inspectFixtureSet } from "./inspector.js";
11
+ import {
12
+ buildColdImportReadiness,
13
+ renderColdImportReadinessMarkdown,
14
+ validateColdImportReadiness,
15
+ writeColdImportReadiness,
16
+ } from "./cold-import-readiness.js";
17
+ import {
18
+ buildWorkspacePlan,
19
+ renderWorkspacePlanMarkdown,
20
+ validateWorkspacePlan,
21
+ writeWorkspacePlan,
22
+ } from "./workspace-plan.js";
23
+ import {
24
+ buildPlatformProbes,
25
+ renderPlatformProbesMarkdown,
26
+ validatePlatformProbes,
27
+ writePlatformProbes,
28
+ } from "./platform-probes.js";
10
29
 
11
30
  export async function loadPluginConfig(options = {}) {
12
31
  if (options.config) {
@@ -35,6 +54,15 @@ export async function inspectFixtureSetConfig(options = {}) {
35
54
  return inspectFixtureSet(config, { generatedAt: options.generatedAt });
36
55
  }
37
56
 
57
+ export async function inspectCompatibilityFixtureSetConfig(options = {}) {
58
+ const config = await loadFixtureSetConfig(options);
59
+ return inspectCompatibilityFixtureSet(config, {
60
+ generatedAt: options.generatedAt,
61
+ openclawPath: options.openclawPath,
62
+ targetOpenClaw: options.targetOpenClaw,
63
+ });
64
+ }
65
+
38
66
  export async function writePluginReports(report, options = {}) {
39
67
  return writeCompatibilityReport(report, {
40
68
  basename: options.basename,
@@ -45,6 +73,130 @@ export async function writePluginReports(report, options = {}) {
45
73
  });
46
74
  }
47
75
 
76
+ export async function writeFixtureSetReports(report, options = {}) {
77
+ return writeCompatibilityReport(report, {
78
+ basename: options.basename,
79
+ check: options.check,
80
+ cwd: options.cwd,
81
+ formatEvidence: options.formatEvidence,
82
+ issuesBasename: options.issuesBasename,
83
+ issuesPath: options.issuesPath,
84
+ issuesTitle: options.issuesTitle,
85
+ jsonPath: options.jsonPath,
86
+ markdownPath: options.markdownPath,
87
+ markdownTitle: options.markdownTitle,
88
+ outDir: options.outDir,
89
+ severityLabels: options.severityLabels,
90
+ title: options.title,
91
+ });
92
+ }
93
+
94
+ export function renderFixtureSetMarkdownReport(report, options = {}) {
95
+ return renderCompatibilityMarkdownReport(report, options);
96
+ }
97
+
98
+ export function renderFixtureSetIssuesReport(report, options = {}) {
99
+ return renderCompatibilityIssuesReport(report, options);
100
+ }
101
+
102
+ export async function runFixtureSetReport(options = {}) {
103
+ const report = await inspectCompatibilityFixtureSetConfig(options);
104
+ const paths = options.write === false ? null : await writeFixtureSetReports(report, options);
105
+ return { report, paths };
106
+ }
107
+
108
+ export async function buildFixtureSetColdImportReadiness(options = {}) {
109
+ const config = options.report ? null : await loadFixtureSetConfig(options);
110
+ const report =
111
+ options.report ??
112
+ (await inspectCompatibilityFixtureSet(config, {
113
+ generatedAt: options.generatedAt,
114
+ openclawPath: options.openclawPath,
115
+ targetOpenClaw: options.targetOpenClaw,
116
+ }));
117
+
118
+ return buildColdImportReadiness({
119
+ ...options,
120
+ report,
121
+ rootDir: options.rootDir ?? config?.rootDir ?? options.cwd,
122
+ });
123
+ }
124
+
125
+ export function renderFixtureSetColdImportReadinessMarkdown(readiness, options = {}) {
126
+ return renderColdImportReadinessMarkdown(readiness, options);
127
+ }
128
+
129
+ export async function writeFixtureSetColdImportReadiness(readiness, options = {}) {
130
+ return writeColdImportReadiness(readiness, options);
131
+ }
132
+
133
+ export async function runFixtureSetColdImportReadiness(options = {}) {
134
+ const readiness = await buildFixtureSetColdImportReadiness(options);
135
+ const paths = options.write === false ? null : await writeFixtureSetColdImportReadiness(readiness, options);
136
+ return { readiness, paths };
137
+ }
138
+
139
+ export async function buildFixtureSetWorkspacePlan(options = {}) {
140
+ const config = options.report ? null : await loadFixtureSetConfig(options);
141
+ const report =
142
+ options.report ??
143
+ (await inspectCompatibilityFixtureSet(config, {
144
+ generatedAt: options.generatedAt,
145
+ openclawPath: options.openclawPath,
146
+ targetOpenClaw: options.targetOpenClaw,
147
+ }));
148
+ const rootDir = options.rootDir ?? config?.rootDir ?? options.cwd;
149
+ const readiness = options.readiness ?? buildColdImportReadiness({ ...options, report, rootDir });
150
+
151
+ return buildWorkspacePlan({
152
+ ...options,
153
+ report,
154
+ readiness,
155
+ rootDir,
156
+ });
157
+ }
158
+
159
+ export function renderFixtureSetWorkspacePlanMarkdown(plan, options = {}) {
160
+ return renderWorkspacePlanMarkdown(plan, options);
161
+ }
162
+
163
+ export function validateFixtureSetWorkspacePlan(plan, options = {}) {
164
+ return validateWorkspacePlan(plan, options);
165
+ }
166
+
167
+ export async function writeFixtureSetWorkspacePlan(plan, options = {}) {
168
+ return writeWorkspacePlan(plan, options);
169
+ }
170
+
171
+ export async function runFixtureSetWorkspacePlan(options = {}) {
172
+ const plan = await buildFixtureSetWorkspacePlan(options);
173
+ const paths = options.write === false ? null : await writeFixtureSetWorkspacePlan(plan, options);
174
+ return { plan, paths };
175
+ }
176
+
177
+ export async function buildFixtureSetPlatformProbes(options = {}) {
178
+ const plan = options.plan ?? (await buildFixtureSetWorkspacePlan(options));
179
+ return buildPlatformProbes({ ...options, plan });
180
+ }
181
+
182
+ export function renderFixtureSetPlatformProbesMarkdown(report, options = {}) {
183
+ return renderPlatformProbesMarkdown(report, options);
184
+ }
185
+
186
+ export function validateFixtureSetPlatformProbes(report, options = {}) {
187
+ return validatePlatformProbes(report, options);
188
+ }
189
+
190
+ export async function writeFixtureSetPlatformProbes(report, options = {}) {
191
+ return writePlatformProbes(report, options);
192
+ }
193
+
194
+ export async function runFixtureSetPlatformProbes(options = {}) {
195
+ const report = await buildFixtureSetPlatformProbes(options);
196
+ const paths = options.write === false ? null : await writeFixtureSetPlatformProbes(report, options);
197
+ return { report, paths };
198
+ }
199
+
48
200
  export async function runPluginCheck(options = {}) {
49
201
  const outDir = options.outDir ?? "reports";
50
202
  const config = await loadPluginConfig(options);
@@ -55,8 +207,8 @@ export async function runPluginCheck(options = {}) {
55
207
  const mockSdk = options.mockSdk ?? config.capture?.mockSdk ?? true;
56
208
 
57
209
  if (capture === true) {
58
- if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
59
- throw new Error("runtime capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
210
+ if (!executionAllowed(options)) {
211
+ throw new Error("runtime capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 or --allow-execute in an isolated workspace");
60
212
  }
61
213
  const runtimeCapture = await buildRuntimeCaptureReport({
62
214
  mockSdk,
@@ -89,4 +241,18 @@ export async function setupPluginInspector(options = {}) {
89
241
  return writePluginInspectorInit(options);
90
242
  }
91
243
 
92
- export { createCaptureApi, renderTextSummary, writeCiOutputArtifacts };
244
+ export { createCaptureApi, renderTextSummary, validateColdImportReadiness, writeCiOutputArtifacts };
245
+
246
+ function executionAllowed(options) {
247
+ return options.allowExecution === true || process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED === "1";
248
+ }
249
+
250
+ async function loadFixtureSetConfig(options) {
251
+ if (options.config) {
252
+ return {
253
+ ...options.config,
254
+ rootDir: options.config.rootDir ?? options.rootDir ?? options.cwd ?? process.cwd(),
255
+ };
256
+ }
257
+ return loadInspectorConfig(options.configPath, { cwd: options.cwd ?? options.rootDir });
258
+ }
@@ -1,6 +1,6 @@
1
1
  export const defaultCaptureApiRegistrarProfiles = {
2
2
  registerChannel: {
3
- returnValue: ({ args }) => registrationObject(args, { id: "channel" }),
3
+ returnValue: ({ args }) => channelRegistrationObject(args),
4
4
  },
5
5
  registerCli: {
6
6
  returnValue: ({ args }) => registrationObject(args, { name: "cli" }),
@@ -12,7 +12,7 @@ export const defaultCaptureApiRegistrarProfiles = {
12
12
  returnValue: ({ args }) => registrationObject(args, { id: "context-engine" }),
13
13
  },
14
14
  registerGatewayMethod: {
15
- returnValue: ({ args }) => registrationObject(args, { name: "gateway.method" }),
15
+ returnValue: ({ args }) => gatewayMethodRegistrationObject(args),
16
16
  },
17
17
  registerHook: {
18
18
  returnValue: ({ api }) => api,
@@ -37,9 +37,10 @@ export const defaultCaptureApiRegistrarProfiles = {
37
37
  },
38
38
  registerService: {
39
39
  returnValue: ({ args }) => ({
40
- ...registrationObject(args, { name: "service" }),
40
+ ...registrationObject(args, { id: "service", name: "service" }),
41
41
  start: async () => undefined,
42
42
  stop: async () => undefined,
43
+ dispose: async () => undefined,
43
44
  }),
44
45
  },
45
46
  registerSpeechProvider: {
@@ -125,6 +126,7 @@ export function createCaptureApi(options = {}) {
125
126
 
126
127
  export function createCaptureContext(options = {}) {
127
128
  return {
129
+ registrationMode: options.registrationMode ?? "full",
128
130
  config: options.config ?? {},
129
131
  logger: options.logger ?? console,
130
132
  pluginConfig: options.pluginConfig ?? {},
@@ -142,6 +144,12 @@ export function createCaptureContext(options = {}) {
142
144
  },
143
145
  gateway: options.gateway ?? {
144
146
  baseUrl: "http://127.0.0.1:0",
147
+ async call(method, params) {
148
+ return { ok: true, method, params };
149
+ },
150
+ respond(ok, result, error) {
151
+ return { ok, result, ...(error ? { error } : {}) };
152
+ },
145
153
  registerRoute(route) {
146
154
  return {
147
155
  ...route,
@@ -242,6 +250,36 @@ function registrationObject(args, defaults) {
242
250
  return withCallableDefaults({ ...defaults }, callable);
243
251
  }
244
252
 
253
+ function channelRegistrationObject(args) {
254
+ const first = args[0];
255
+ const registration = registrationObject(args, { id: "channel" });
256
+ if (first?.plugin && typeof first.plugin === "object") {
257
+ return {
258
+ ...registration,
259
+ id: objectId(first.plugin) ?? registration.id,
260
+ plugin: first.plugin,
261
+ };
262
+ }
263
+ return registration;
264
+ }
265
+
266
+ function gatewayMethodRegistrationObject(args) {
267
+ const [method, handler, options] = args;
268
+ const registration = registrationObject(args, { name: "gateway.method" });
269
+ if (typeof method !== "string") {
270
+ return registration;
271
+ }
272
+ return {
273
+ ...registration,
274
+ name: method,
275
+ method,
276
+ handler: typeof handler === "function" ? handler : registration.handler,
277
+ run: typeof handler === "function" ? handler : registration.run,
278
+ execute: typeof handler === "function" ? handler : registration.execute,
279
+ scope: options?.scope ?? registration.scope,
280
+ };
281
+ }
282
+
245
283
  function firstCallable(args) {
246
284
  return args.find((arg) => typeof arg === "function");
247
285
  }