@openclaw/plugin-inspector 0.3.8 → 0.3.10

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
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.10 - 2026-05-03
6
+
7
+ ### Fixed
8
+
9
+ - Accept valid mocked capture output when plugin code leaves `process.exitCode` dirty.
10
+
11
+ ## 0.3.9 - 2026-05-03
12
+
13
+ ### Fixed
14
+
15
+ - Follow bundled channel `loadBundledEntryExportSync` registration exports during mocked runtime capture.
16
+
5
17
  ## 0.3.8 - 2026-05-03
6
18
 
7
19
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/plugin-inspector",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "private": false,
5
5
  "description": "Offline compatibility inspector for OpenClaw plugins.",
6
6
  "type": "module",
package/src/inspector.js CHANGED
@@ -234,10 +234,34 @@ export async function captureEntrypointWithMockSdk(entrypoint, options = {}) {
234
234
  );
235
235
  return JSON.parse(stdout);
236
236
  } catch (error) {
237
+ const captured = parseCaptureResultFromStdout(error?.stdout);
238
+ if (captured) {
239
+ return captured;
240
+ }
237
241
  throw classifyMockSdkCaptureError(error);
238
242
  }
239
243
  }
240
244
 
245
+ function parseCaptureResultFromStdout(stdout) {
246
+ if (!stdout) {
247
+ return null;
248
+ }
249
+ try {
250
+ const parsed = JSON.parse(stdout);
251
+ if (
252
+ parsed &&
253
+ typeof parsed === "object" &&
254
+ typeof parsed.status === "string" &&
255
+ Array.isArray(parsed.captured)
256
+ ) {
257
+ return parsed;
258
+ }
259
+ } catch {
260
+ return null;
261
+ }
262
+ return null;
263
+ }
264
+
241
265
  export function classifyMockSdkCaptureError(error) {
242
266
  const rawMessage = [error?.stderr, error?.stdout, error?.message].filter(Boolean).join("\n");
243
267
  const missingExport = rawMessage.match(/does not provide an export named ['"]([^'"]+)['"]/)?.[1];
package/src/sdk-mock.js CHANGED
@@ -551,6 +551,9 @@ function genericExportStatement(name) {
551
551
  if (name === "defineBundledChannelSetupEntry") {
552
552
  return "export { defineBundledChannelSetupEntry };";
553
553
  }
554
+ if (name === "loadBundledEntryExportSync") {
555
+ return "export { loadBundledEntryExportSync };";
556
+ }
554
557
  if (/^[A-Z].*Schema$/u.test(name)) {
555
558
  return `export const ${name} = createSchema();`;
556
559
  }
@@ -558,7 +561,13 @@ function genericExportStatement(name) {
558
561
  }
559
562
 
560
563
  function genericMockRuntimeSource(options = {}) {
561
- return `${options.includeSdkRuntime ? `function definePluginEntry(entry) {
564
+ return `${options.includeSdkRuntime ? `import { existsSync } from "node:fs";
565
+ import path from "node:path";
566
+ import { fileURLToPath, pathToFileURL } from "node:url";
567
+
568
+ const pendingBundledEntryLoads = new Set();
569
+
570
+ function definePluginEntry(entry) {
562
571
  if (entry && typeof entry === "object" && typeof entry.register === "function") {
563
572
  return entry;
564
573
  }
@@ -572,7 +581,7 @@ function defineBundledChannelEntry(entry = {}) {
572
581
  return {
573
582
  ...entry,
574
583
  kind: "bundled-channel-entry",
575
- register(api) {
584
+ async register(api) {
576
585
  if (api?.registrationMode === "cli-metadata") {
577
586
  return entry.registerCliMetadata?.(api);
578
587
  }
@@ -585,7 +594,12 @@ function defineBundledChannelEntry(entry = {}) {
585
594
  });
586
595
  }
587
596
  entry.registerCliMetadata?.(api);
588
- return entry.registerFull?.(api);
597
+ const result = entry.registerFull?.(api);
598
+ if (result && typeof result.then === "function") {
599
+ await result;
600
+ }
601
+ await drainBundledEntryLoads();
602
+ return result;
589
603
  },
590
604
  };
591
605
  }
@@ -596,6 +610,46 @@ function defineBundledChannelSetupEntry(entry = {}) {
596
610
  kind: "bundled-channel-setup-entry",
597
611
  };
598
612
  }
613
+
614
+ function loadBundledEntryExportSync(importMetaUrl, options = {}) {
615
+ return (...args) => {
616
+ const promise = import(resolveBundledEntryUrl(importMetaUrl, options.specifier)).then((module) => {
617
+ const loaded = module[options.exportName] ?? module.default;
618
+ return typeof loaded === "function" ? loaded(...args) : loaded;
619
+ });
620
+ pendingBundledEntryLoads.add(promise);
621
+ promise.finally(() => pendingBundledEntryLoads.delete(promise));
622
+ return promise;
623
+ };
624
+ }
625
+
626
+ async function drainBundledEntryLoads() {
627
+ while (pendingBundledEntryLoads.size > 0) {
628
+ await Promise.all([...pendingBundledEntryLoads]);
629
+ }
630
+ }
631
+
632
+ function resolveBundledEntryUrl(importMetaUrl, specifier) {
633
+ const basePath = fileURLToPath(importMetaUrl);
634
+ const target = specifier ? path.resolve(path.dirname(basePath), specifier) : basePath;
635
+ const resolved = resolveExistingSourcePath(target);
636
+ return pathToFileURL(resolved).href;
637
+ }
638
+
639
+ function resolveExistingSourcePath(target) {
640
+ if (existsSync(target)) {
641
+ return target;
642
+ }
643
+ const parsed = path.parse(target);
644
+ const withoutJsExtension = [".js", ".mjs", ".cjs"].includes(parsed.ext) ? path.join(parsed.dir, parsed.name) : null;
645
+ const candidates = [
646
+ ...(withoutJsExtension ? [\`\${withoutJsExtension}.ts\`, \`\${withoutJsExtension}.mts\`, \`\${withoutJsExtension}.cts\`] : []),
647
+ \`\${target}.js\`,
648
+ \`\${target}.mjs\`,
649
+ \`\${target}.ts\`,
650
+ ];
651
+ return candidates.find((candidate) => existsSync(candidate)) ?? target;
652
+ }
599
653
  ` : ""}
600
654
  function createMockValue(name) {
601
655
  function fn(...args) {
@@ -1122,16 +1176,36 @@ export function normalizeSecretInputString(value) {
1122
1176
  return String(value ?? "").trim();
1123
1177
  }
1124
1178
 
1179
+ function createSimpleSchema(defaultValue) {
1180
+ return {
1181
+ parse(value) {
1182
+ return value === undefined ? defaultValue : value;
1183
+ },
1184
+ default(value) {
1185
+ return createSimpleSchema(value);
1186
+ },
1187
+ optional() {
1188
+ return this;
1189
+ },
1190
+ nullable() {
1191
+ return this;
1192
+ },
1193
+ nullish() {
1194
+ return this;
1195
+ },
1196
+ };
1197
+ }
1198
+
1125
1199
  export function buildSecretInputSchema() {
1126
- return { type: "string" };
1200
+ return createSimpleSchema();
1127
1201
  }
1128
1202
 
1129
1203
  export function buildOptionalSecretInputSchema() {
1130
- return { anyOf: [buildSecretInputSchema(), { type: "undefined" }] };
1204
+ return createSimpleSchema();
1131
1205
  }
1132
1206
 
1133
1207
  export function buildSecretInputArraySchema() {
1134
- return { type: "array", items: buildSecretInputSchema() };
1208
+ return createSimpleSchema([]);
1135
1209
  }
1136
1210
 
1137
1211
  export function registerPluginHttpRoute(options = {}) {