@openclaw/plugin-inspector 0.3.10 → 0.3.12

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/src/sdk-mock.js CHANGED
@@ -377,6 +377,9 @@ function parseModuleImports(text) {
377
377
  ];
378
378
  for (const pattern of patterns) {
379
379
  for (const match of text.matchAll(pattern)) {
380
+ if (isTypeOnlyImportOrExport(match[0], match[1] ?? "")) {
381
+ continue;
382
+ }
380
383
  const specifier = match[2];
381
384
  if (specifier) {
382
385
  entries.push({ specifier, names: parseNamedImports(match[1] ?? "") });
@@ -389,6 +392,10 @@ function parseModuleImports(text) {
389
392
  return entries;
390
393
  }
391
394
 
395
+ function isTypeOnlyImportOrExport(statement, clause) {
396
+ return /^\s*import\s+type\b/u.test(statement) || /^\s*export\s+type\b/u.test(statement) || /^\s*type\b/u.test(clause);
397
+ }
398
+
392
399
  function parseNamedImports(clause) {
393
400
  const names = new Set();
394
401
  const named = /\{([\s\S]*?)\}/.exec(clause)?.[1] ?? clause;
@@ -459,11 +466,22 @@ export async function resolve(specifier, context, nextResolve) {
459
466
  export async function load(url, context, nextLoad) {
460
467
  if (url.startsWith("file:") && /\\.[cm]?ts$/u.test(fileURLToPath(url))) {
461
468
  const rawSource = await readFile(fileURLToPath(url), "utf8");
462
- return { format: "module", source: stripTypeScriptTypes(rawSource, { mode: "transform" }), shortCircuit: true };
469
+ return { format: "module", source: stripPluginTypeScript(rawSource), shortCircuit: true };
463
470
  }
464
471
  return nextLoad(url, context);
465
472
  }
466
473
 
474
+ function stripPluginTypeScript(source) {
475
+ try {
476
+ return stripTypeScriptTypes(source, { mode: "transform" });
477
+ } catch (error) {
478
+ if (error?.code !== "ERR_INVALID_ARG_VALUE") {
479
+ throw error;
480
+ }
481
+ return stripTypeScriptTypes(source, { mode: "strip" });
482
+ }
483
+ }
484
+
467
485
  function moduleUrl(filePath) {
468
486
  return { url: pathToFileURL(filePath).href, shortCircuit: true };
469
487
  }
@@ -653,6 +671,24 @@ function resolveExistingSourcePath(target) {
653
671
  ` : ""}
654
672
  function createMockValue(name) {
655
673
  function fn(...args) {
674
+ if (name === "resolveDefaultAgentDir") {
675
+ return mockAgentDir();
676
+ }
677
+ if (name === "resolveAgentDir") {
678
+ return mockAgentDir(args[1]);
679
+ }
680
+ if (name === "resolveUserPath") {
681
+ return typeof args[0] === "string" ? args[0] : mockAgentDir();
682
+ }
683
+ if (name === "resolveAuthProfileOrder") {
684
+ return [];
685
+ }
686
+ if (name === "resolveWindowsSpawnProgram") {
687
+ return mockWindowsSpawnProgram(args[0]);
688
+ }
689
+ if (name === "materializeWindowsSpawnProgram") {
690
+ return mockWindowsSpawnInvocation(args[0], args[1]);
691
+ }
656
692
  if (name === "resolvePreferredOpenClawTmpDir") {
657
693
  return process.env.TMPDIR || "/tmp";
658
694
  }
@@ -689,6 +725,80 @@ function createMockValue(name) {
689
725
  });
690
726
  }
691
727
 
728
+ function mockAgentDir(agentId = "main") {
729
+ const base = process.env.TMPDIR || process.env.TEMP || process.env.TMP || "/tmp";
730
+ const safeAgentId = String(agentId || "main").replace(/[^a-zA-Z0-9._-]/g, "-");
731
+ return base.replace(/[\\/]+$/, "") + "/plugin-inspector-openclaw/agents/" + safeAgentId + "/agent";
732
+ }
733
+
734
+ function mockWindowsSpawnProgram(params = {}) {
735
+ return {
736
+ command: typeof params.command === "string" && params.command.trim() ? params.command : process.execPath,
737
+ leadingArgv: [],
738
+ resolution: "mock",
739
+ packageName: typeof params.packageName === "string" ? params.packageName : undefined,
740
+ };
741
+ }
742
+
743
+ function mockWindowsSpawnInvocation(program = {}, argv = []) {
744
+ const command = typeof program.command === "string" && program.command.trim() ? program.command : process.execPath;
745
+ if (program.packageName === "@openai/codex") {
746
+ return {
747
+ command: process.execPath,
748
+ argv: ["-e", mockCodexAppServerScript()],
749
+ resolution: program.resolution ?? "mock",
750
+ windowsHide: true,
751
+ };
752
+ }
753
+ return {
754
+ command,
755
+ argv: [...(Array.isArray(program.leadingArgv) ? program.leadingArgv : []), ...(Array.isArray(argv) ? argv : [])],
756
+ resolution: program.resolution ?? "mock",
757
+ shell: program.shell,
758
+ windowsHide: program.windowsHide,
759
+ };
760
+ }
761
+
762
+ function mockCodexAppServerScript() {
763
+ return [
764
+ "const readline = require('node:readline');",
765
+ "const rl = readline.createInterface({ input: process.stdin });",
766
+ "let idleTimer;",
767
+ "function scheduleIdleExit() {",
768
+ " if (idleTimer) clearTimeout(idleTimer);",
769
+ " idleTimer = setTimeout(() => process.exit(0), 1000);",
770
+ "}",
771
+ "function write(id, result) { process.stdout.write(JSON.stringify({ id, result }) + String.fromCharCode(10)); }",
772
+ "rl.on('line', (line) => {",
773
+ " let message;",
774
+ " try { message = JSON.parse(line); } catch { return; }",
775
+ " if (message.id === undefined || message.id === null) return;",
776
+ " switch (message.method) {",
777
+ " case 'initialize':",
778
+ " write(message.id, { userAgent: 'openclaw/999.0.0 (plugin-inspector mock)' });",
779
+ " break;",
780
+ " case 'model/list':",
781
+ " write(message.id, { data: [] });",
782
+ " break;",
783
+ " case 'thread/list':",
784
+ " case 'mcpServerStatus/list':",
785
+ " case 'skills/list':",
786
+ " write(message.id, { data: [] });",
787
+ " break;",
788
+ " case 'account/read':",
789
+ " write(message.id, null);",
790
+ " break;",
791
+ " case 'account/rateLimits/read':",
792
+ " write(message.id, null);",
793
+ " break;",
794
+ " default:",
795
+ " process.stdout.write(JSON.stringify({ id: message.id, error: { code: -32601, message: 'mock method not implemented' } }) + String.fromCharCode(10));",
796
+ " }",
797
+ " scheduleIdleExit();",
798
+ "});",
799
+ ].join("\\n");
800
+ }
801
+
692
802
  function createZNamespace() {
693
803
  const namespace = {
694
804
  any: () => createSchema(),
@@ -1665,11 +1775,53 @@ export const OPENAI_RESPONSES_STREAM_HOOKS = buildProviderStreamFamilyHooks("ope
1665
1775
  export const OPENROUTER_THINKING_STREAM_HOOKS = buildProviderStreamFamilyHooks("openrouter-thinking");
1666
1776
  export const TOOL_STREAM_DEFAULT_ON_HOOKS = buildProviderStreamFamilyHooks("tool-stream-default");
1667
1777
  export const pluginSdkMock = true;
1778
+ ${dynamicExportNames.length > 0 ? mockValueRuntimeSource() : ""}
1668
1779
  ${dynamicExportNames.map(genericExportStatement).join("\n")}
1669
1780
 
1670
1781
  export default {
1671
1782
  ${[...exportNames].map((name) => ` ${name},`).join("\n")}
1672
1783
  };
1784
+ `;
1785
+ }
1786
+
1787
+ function mockValueRuntimeSource() {
1788
+ return `function createMockValue(name) {
1789
+ function fn(...args) {
1790
+ if (name === "resolvePreferredOpenClawTmpDir") {
1791
+ return process.env.TMPDIR || "/tmp";
1792
+ }
1793
+ if (name.startsWith("normalize")) {
1794
+ return typeof args[0] === "string" ? args[0] : "";
1795
+ }
1796
+ if (name === "jsonResult") {
1797
+ return { type: "json", value: args[0] };
1798
+ }
1799
+ if (name === "readStringParam") {
1800
+ return typeof args[0] === "string" ? args[0] : "";
1801
+ }
1802
+ return createMockValue(name);
1803
+ }
1804
+ return new Proxy(fn, {
1805
+ get(_target, property) {
1806
+ if (property === "then") {
1807
+ return undefined;
1808
+ }
1809
+ if (property === Symbol.toPrimitive) {
1810
+ return () => name;
1811
+ }
1812
+ if (property === "toString") {
1813
+ return () => name;
1814
+ }
1815
+ if (property === "valueOf") {
1816
+ return () => name;
1817
+ }
1818
+ return createMockValue(\`\${name}.\${String(property)}\`);
1819
+ },
1820
+ construct() {
1821
+ return createMockValue(name);
1822
+ },
1823
+ });
1824
+ }
1673
1825
  `;
1674
1826
  }
1675
1827
 
@@ -0,0 +1,47 @@
1
+ import { rmSync } from "node:fs";
2
+ import { mkdtemp } 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 } from "./inspector.js";
8
+ import { createMockSdkPackage } from "./sdk-mock.js";
9
+ import { runCapturedSyntheticProbes } from "./synthetic-probes.js";
10
+
11
+ export async function runEntrypointSyntheticProbes(entrypoint, options = {}) {
12
+ const capture = await captureEntrypointForSyntheticProbes(entrypoint, {
13
+ ...options,
14
+ apiOptions: {
15
+ ...(options.apiOptions ?? {}),
16
+ retainHandlers: true,
17
+ },
18
+ });
19
+ return runCapturedSyntheticProbes(capture, options);
20
+ }
21
+
22
+ async function captureEntrypointForSyntheticProbes(entrypoint, options) {
23
+ if (options.mockSdk !== true) {
24
+ return captureEntrypoint(entrypoint, options);
25
+ }
26
+
27
+ const cwd = options.cwd ?? process.cwd();
28
+ const resolvedEntrypoint = path.resolve(cwd, entrypoint);
29
+ const pluginRoot = path.resolve(cwd, options.pluginRoot ?? path.dirname(resolvedEntrypoint));
30
+ const workspace = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-synthetic-mock-sdk-"));
31
+ cleanupTempDirOnExit(workspace);
32
+ const { loaderPath } = await createMockSdkPackage(workspace, { pluginRoot });
33
+ register(pathToFileURL(loaderPath));
34
+
35
+ return captureEntrypoint(entrypoint, {
36
+ ...options,
37
+ cwd,
38
+ mockSdk: false,
39
+ pluginRoot,
40
+ });
41
+ }
42
+
43
+ function cleanupTempDirOnExit(dir) {
44
+ process.once("exit", () => {
45
+ rmSync(dir, { force: true, recursive: true });
46
+ });
47
+ }
@@ -1,12 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { rmSync } from "node:fs";
3
- import { mkdtemp } from "node:fs/promises";
4
- import { register } from "node:module";
5
- import os from "node:os";
6
- import path from "node:path";
7
- import { pathToFileURL } from "node:url";
8
- import { captureEntrypoint, runCapturedSyntheticProbes, writeArtifacts } from "./advanced.js";
9
- import { createMockSdkPackage } from "./sdk-mock.js";
2
+ import { runEntrypointSyntheticProbes, writeArtifacts } from "./advanced.js";
10
3
 
11
4
  const args = process.argv.slice(2);
12
5
 
@@ -33,12 +26,10 @@ async function run(commandArgs) {
33
26
  throw new Error("synthetic probes import plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
34
27
  }
35
28
 
36
- const capture = await captureForSyntheticProbes(entrypoint, {
29
+ const results = await runEntrypointSyntheticProbes(entrypoint, {
37
30
  mockSdk,
38
31
  pluginRoot,
39
32
  apiOptions: { retainHandlers: true },
40
- });
41
- const results = await runCapturedSyntheticProbes(capture, {
42
33
  includeLifecycle,
43
34
  includeChannelRuntime,
44
35
  includeProviderCapabilities,
@@ -52,30 +43,6 @@ async function run(commandArgs) {
52
43
  }
53
44
  }
54
45
 
55
- async function captureForSyntheticProbes(entrypoint, options) {
56
- if (options.mockSdk !== true) {
57
- return captureEntrypoint(entrypoint, options);
58
- }
59
-
60
- const resolvedEntrypoint = path.resolve(process.cwd(), entrypoint);
61
- const pluginRoot = path.resolve(process.cwd(), options.pluginRoot ?? path.dirname(resolvedEntrypoint));
62
- const workspace = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-synthetic-mock-sdk-"));
63
- cleanupTempDirOnExit(workspace);
64
- const { loaderPath } = await createMockSdkPackage(workspace, { pluginRoot });
65
- register(pathToFileURL(loaderPath));
66
- return captureEntrypoint(entrypoint, {
67
- ...options,
68
- mockSdk: false,
69
- pluginRoot,
70
- });
71
- }
72
-
73
- function cleanupTempDirOnExit(dir) {
74
- process.once("exit", () => {
75
- rmSync(dir, { force: true, recursive: true });
76
- });
77
- }
78
-
79
46
  function readFlag(commandArgs, name) {
80
47
  const index = commandArgs.indexOf(name);
81
48
  if (index === -1) {
@@ -89,6 +89,11 @@ export const syntheticRegistrationExecutionProfiles = {
89
89
  callableProperties: [],
90
90
  reason: "detached task runtimes are captured as registration metadata before async task execution",
91
91
  },
92
+ registerEmbeddingProvider: {
93
+ mode: "metadata-only",
94
+ callableProperties: [],
95
+ reason: "embedding providers are captured as registration metadata before provider runtime execution",
96
+ },
92
97
  registerGatewayDiscoveryService: {
93
98
  mode: "metadata-only",
94
99
  callableProperties: [],
@@ -116,11 +121,21 @@ export const syntheticRegistrationExecutionProfiles = {
116
121
  callableProperties: [],
117
122
  reason: "image generation providers are captured as registration metadata before provider runtime execution",
118
123
  },
124
+ registerHostedMediaResolver: {
125
+ mode: "metadata-only",
126
+ callableProperties: [],
127
+ reason: "hosted media resolvers are captured as registration metadata before media URL resolution",
128
+ },
119
129
  registerMemoryPromptSection: {
120
130
  mode: "metadata-only",
121
131
  callableProperties: [],
122
132
  reason: "memory prompt section renderers are captured as metadata before prompt-runtime execution",
123
133
  },
134
+ registerMeetingNotesSourceProvider: {
135
+ mode: "metadata-only",
136
+ callableProperties: [],
137
+ reason: "meeting notes source providers are captured as registration metadata before source discovery",
138
+ },
124
139
  registerMediaUnderstandingProvider: {
125
140
  mode: "metadata-only",
126
141
  callableProperties: [],
@@ -161,11 +176,21 @@ export const syntheticRegistrationExecutionProfiles = {
161
176
  callableProperties: [],
162
177
  reason: "migration providers are captured as registration metadata before migration runtime execution",
163
178
  },
179
+ registerModelCatalogProvider: {
180
+ mode: "metadata-only",
181
+ callableProperties: [],
182
+ reason: "model catalog providers are captured as registration metadata before catalog runtime execution",
183
+ },
164
184
  registerMusicGenerationProvider: {
165
185
  mode: "metadata-only",
166
186
  callableProperties: [],
167
187
  reason: "music generation providers are captured as registration metadata before provider runtime execution",
168
188
  },
189
+ registerNodeCliFeature: {
190
+ mode: "metadata-only",
191
+ callableProperties: [],
192
+ reason: "node CLI features are captured as registration metadata before host CLI integration",
193
+ },
169
194
  registerNodeHostCommand: {
170
195
  mode: "metadata-only",
171
196
  callableProperties: [],
@@ -206,6 +231,11 @@ export const syntheticRegistrationExecutionProfiles = {
206
231
  callableProperties: [],
207
232
  reason: "security audit collectors are captured as registration metadata before filesystem or policy scans",
208
233
  },
234
+ registerSessionAction: {
235
+ mode: "metadata-only",
236
+ callableProperties: [],
237
+ reason: "session actions are captured as registration metadata before session runtime execution",
238
+ },
209
239
  registerService: {
210
240
  mode: "lifecycle-opt-in",
211
241
  callableProperties: ["start", "stop", "dispose"],
@@ -267,12 +297,17 @@ export const defaultSyntheticHookEvents = {
267
297
  runId: "run-fixture",
268
298
  agentId: "agent-fixture",
269
299
  conversationId: "conversation-fixture",
300
+ success: true,
301
+ durationMs: 1,
302
+ error: null,
303
+ messages: [{ role: "assistant", content: "[redacted fixture output]" }],
270
304
  status: "completed",
271
305
  transcript: [{ role: "assistant", content: "[redacted fixture output]" }],
272
306
  },
273
307
  before_agent_start: {
274
308
  agentId: "agent-fixture",
275
309
  runId: "run-fixture",
310
+ prompt: "fixture prompt",
276
311
  config: { source: "plugin-inspector" },
277
312
  },
278
313
  before_prompt_build: {
@@ -303,6 +338,18 @@ export const defaultSyntheticHookEvents = {
303
338
  model: "gpt-5.4",
304
339
  output: { role: "assistant", content: "[redacted fixture output]" },
305
340
  },
341
+ message_received: {
342
+ from: "fixture-user",
343
+ content: "fixture inbound message",
344
+ messageId: "message-fixture",
345
+ },
346
+ message_sent: {
347
+ to: "fixture-user",
348
+ content: "fixture outbound message",
349
+ success: true,
350
+ error: null,
351
+ messageId: "message-fixture-reply",
352
+ },
306
353
  subagent_delivery_target: {
307
354
  childSessionKey: "child-session",
308
355
  agentId: "agent-child",
@@ -361,6 +408,18 @@ export const defaultSyntheticHookContexts = {
361
408
  agentId: "agent-fixture",
362
409
  sessionId: "session-fixture",
363
410
  },
411
+ message_received: {
412
+ runId: "run-fixture",
413
+ agentId: "agent-fixture",
414
+ sessionId: "session-fixture",
415
+ channelId: "fixture-channel",
416
+ },
417
+ message_sent: {
418
+ runId: "run-fixture",
419
+ agentId: "agent-fixture",
420
+ sessionId: "session-fixture",
421
+ channelId: "fixture-channel",
422
+ },
364
423
  subagent_delivery_target: {
365
424
  runId: "run-fixture",
366
425
  parentAgentId: "agent-parent",