feat(report): find package contract issues

This commit is contained in:
Vincent Koc 2026-04-25 13:01:25 -07:00
parent 9244228f88
commit 7d425df57e
No known key found for this signature in database
4 changed files with 1575 additions and 146 deletions

View File

@ -7,10 +7,10 @@ Status: PASS
| Metric | Value |
| --------------- | ----- |
| Issue findings | 22 |
| Issue findings | 28 |
| P0 | 0 |
| P1 | 7 |
| Contract probes | 22 |
| Contract probes | 28 |
## Issues
@ -24,20 +24,26 @@ Status: PASS
| CRABPOT-0006 | P1 | wecom | inspector | inspector-follow-up | open | wecom: before_tool_call needs terminal/block/approval probes | before_tool_call @ plugins/wecom/index.js:65 |
| CRABPOT-0007 | P1 | wecom | inspector | inspector-follow-up | open | wecom: runtime registrations need capture before contract judgment | registerHttpRoute @ plugins/wecom/index.js:45 |
| CRABPOT-0008 | P2 | a2a-gateway | core | core-compat-adapter | open | a2a-gateway: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 |
| CRABPOT-0009 | P2 | a2a-gateway | inspector | inspector-follow-up | open | a2a-gateway: runtime tool schema needs registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 |
| CRABPOT-0010 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: channel runtime needs envelope/config probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 |
| CRABPOT-0011 | P2 | agentchat | core | core-compat-adapter | open | agentchat: channelEnvVars legacy manifest metadata must stay covered | agentchat |
| CRABPOT-0012 | P2 | apify | core | core-compat-adapter | open | apify: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| CRABPOT-0013 | P2 | apify | inspector | inspector-follow-up | open | apify: runtime tool schema needs registration capture | registerTool @ plugins/apify/src/index.ts:13 |
| CRABPOT-0014 | P2 | codex-app-server | core | core-compat-adapter | open | codex-app-server: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| CRABPOT-0015 | P2 | hasdata | core | core-compat-adapter | open | hasdata: providerAuthEnvVars legacy manifest metadata must stay covered | hasdata |
| CRABPOT-0016 | P2 | inworld-tts | core | core-compat-adapter | open | inworld-tts: providerAuthEnvVars legacy manifest metadata must stay covered | inworld |
| CRABPOT-0017 | P2 | llm-trace-phoenix | core | core-compat-adapter | open | llm-trace-phoenix: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| CRABPOT-0018 | P2 | mcp-adapter | inspector | inspector-follow-up | open | mcp-adapter: runtime tool schema needs registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 |
| CRABPOT-0019 | P2 | web-search-plus | core | core-compat-adapter | open | web-search-plus: providerAuthEnvVars legacy manifest metadata must stay covered | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| CRABPOT-0020 | P2 | web-search-plus | inspector | inspector-follow-up | open | web-search-plus: runtime tool schema needs registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 |
| CRABPOT-0021 | P2 | wecom | inspector | inspector-follow-up | open | wecom: channel runtime needs envelope/config probes | registerChannel @ plugins/wecom/index.js:27 |
| CRABPOT-0022 | P2 | wecom | inspector | inspector-follow-up | open | wecom: runtime tool schema needs registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
| CRABPOT-0009 | P2 | a2a-gateway | plugin | plugin-upstream-fix | open | a2a-gateway: package and manifest versions drift | package:1.4.0, manifest:1.3.0 |
| CRABPOT-0010 | P2 | a2a-gateway | plugin | plugin-upstream-fix | open | a2a-gateway: plugin API compatibility range is missing | plugins/a2a-gateway/package.json |
| CRABPOT-0011 | P2 | a2a-gateway | inspector | inspector-follow-up | open | a2a-gateway: runtime tool schema needs registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 |
| CRABPOT-0012 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: channel runtime needs envelope/config probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 |
| CRABPOT-0013 | P2 | agentchat | core | core-compat-adapter | open | agentchat: channelEnvVars legacy manifest metadata must stay covered | agentchat |
| CRABPOT-0014 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: cold import requires package build output | extension:./dist/index.js -> plugins/agentchat/integrations/openclaw-channel/dist/index.js, setupEntry:./dist/setup-entry.js -> plugins/agentchat/integrations/openclaw-channel/dist/setup-entry.js |
| CRABPOT-0015 | P2 | apify | core | core-compat-adapter | open | apify: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| CRABPOT-0016 | P2 | apify | inspector | inspector-follow-up | open | apify: runtime tool schema needs registration capture | registerTool @ plugins/apify/src/index.ts:13 |
| CRABPOT-0017 | P2 | clawmetry | inspector | inspector-follow-up | open | clawmetry: cold import requires package build output | runtimeExtension:./dist/index.js -> plugins/clawmetry/clawhub-plugin/dist/index.js |
| CRABPOT-0018 | P2 | codex-app-server | core | core-compat-adapter | open | codex-app-server: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| CRABPOT-0019 | P2 | hasdata | core | core-compat-adapter | open | hasdata: providerAuthEnvVars legacy manifest metadata must stay covered | hasdata |
| CRABPOT-0020 | P2 | inworld-tts | core | core-compat-adapter | open | inworld-tts: providerAuthEnvVars legacy manifest metadata must stay covered | inworld |
| CRABPOT-0021 | P2 | llm-trace-phoenix | core | core-compat-adapter | open | llm-trace-phoenix: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| CRABPOT-0022 | P2 | mcp-adapter | plugin | plugin-upstream-fix | open | mcp-adapter: plugin API compatibility range is missing | plugins/mcp-adapter/package.json |
| CRABPOT-0023 | P2 | mcp-adapter | inspector | inspector-follow-up | open | mcp-adapter: runtime tool schema needs registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 |
| CRABPOT-0024 | P2 | web-search-plus | core | core-compat-adapter | open | web-search-plus: providerAuthEnvVars legacy manifest metadata must stay covered | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| CRABPOT-0025 | P2 | web-search-plus | inspector | inspector-follow-up | open | web-search-plus: runtime tool schema needs registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 |
| CRABPOT-0026 | P2 | wecom | inspector | inspector-follow-up | open | wecom: channel runtime needs envelope/config probes | registerChannel @ plugins/wecom/index.js:27 |
| CRABPOT-0027 | P2 | wecom | plugin | plugin-upstream-fix | open | wecom: plugin API compatibility range is missing | plugins/wecom/package.json |
| CRABPOT-0028 | P2 | wecom | inspector | inspector-follow-up | open | wecom: runtime tool schema needs registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
## Contract Probe Backlog
@ -54,6 +60,11 @@ Status: PASS
| channel.runtime.envelope-config-metadata:wecom | P2 | wecom | channel-runtime | Channel setup, message envelope, sender metadata, and config schema remain stable. | registerChannel @ plugins/wecom/index.js:27 |
| manifest.compat.channel-env-vars:agentchat | P2 | agentchat | manifest-loader | Legacy channel env metadata continues to map into channel setup/help surfaces. | agentchat |
| manifest.compat.provider-auth-env-vars:hasdata | P2 | hasdata | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | hasdata |
| package.compat.plugin-api-range:a2a-gateway | P2 | a2a-gateway | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/a2a-gateway/package.json |
| package.compat.plugin-api-range:mcp-adapter | P2 | mcp-adapter | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/mcp-adapter/package.json |
| package.compat.plugin-api-range:wecom | P2 | wecom | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/wecom/package.json |
| package.entrypoint.build-before-cold-import:agentchat | P2 | agentchat | package-loader | Inspector can build or resolve source aliases before cold importing package entrypoints. | extension:./dist/index.js -> plugins/agentchat/integrations/openclaw-channel/dist/index.js, setupEntry:./dist/setup-entry.js -> plugins/agentchat/integrations/openclaw-channel/dist/setup-entry.js |
| package.metadata.version-alignment:a2a-gateway | P2 | a2a-gateway | package-loader | Package and OpenClaw manifest versions stay aligned for release compatibility reporting. | package:1.4.0, manifest:1.3.0 |
| sdk.import.root-barrel-cold-import:a2a-gateway | P2 | a2a-gateway | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 |
| sdk.import.root-barrel-cold-import:llm-trace-phoenix | P2 | llm-trace-phoenix | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| tool.registration.schema-capture:a2a-gateway | P2 | a2a-gateway | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/a2a-gateway/index.ts:777 |
@ -61,6 +72,7 @@ Status: PASS
| tool.registration.schema-capture:wecom | P2 | wecom | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
| manifest.compat.provider-auth-env-vars:inworld-tts | P3 | inworld-tts | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | inworld |
| manifest.compat.provider-auth-env-vars:web-search-plus | P3 | web-search-plus | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| package.entrypoint.build-before-cold-import:clawmetry | P3 | clawmetry | package-loader | Inspector can build or resolve source aliases before cold importing package entrypoints. | runtimeExtension:./dist/index.js -> plugins/clawmetry/clawhub-plugin/dist/index.js |
| sdk.import.root-barrel-cold-import:apify | P3 | apify | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| sdk.import.root-barrel-cold-import:codex-app-server | P3 | codex-app-server | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| tool.registration.schema-capture:apify | P3 | apify | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/apify/src/index.ts:13 |

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,13 @@ Status: PASS
| Fixtures | 11 |
| High-priority fixtures | 6 |
| Hard breakages | 0 |
| Warnings | 9 |
| Compatibility suggestions | 13 |
| Issue findings | 22 |
| Warnings | 13 |
| Compatibility suggestions | 15 |
| Issue findings | 28 |
| P0 issues | 0 |
| P1 issues | 7 |
| Contract probes | 22 |
| Decision rows | 24 |
| Contract probes | 28 |
| Decision rows | 30 |
## Hard Breakages
@ -38,35 +38,41 @@ _none_
## Warnings
| Fixture | Code | Level | Message | Evidence | Compat record |
| ----------------- | ------------------------ | ------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| agentchat | channel-env-vars | warning | manifest uses channelEnvVars legacy compatibility metadata | agentchat | channel-env-vars |
| a2a-gateway | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 | legacy-root-sdk-import |
| hasdata | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | hasdata | provider-auth-env-vars |
| llm-trace-phoenix | conversation-access-hook | warning | fixture observes raw model or conversation content and needs privacy-boundary contract probes | llm_input @ plugins/llm-trace-phoenix/index.ts:154, llm_output @ plugins/llm-trace-phoenix/index.ts:168 | - |
| llm-trace-phoenix | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 | legacy-root-sdk-import |
| codex-app-server | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 | legacy-root-sdk-import |
| web-search-plus | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng | provider-auth-env-vars |
| apify | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 | legacy-root-sdk-import |
| inworld-tts | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | inworld | provider-auth-env-vars |
| Fixture | Code | Level | Message | Evidence | Compat record |
| ----------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| agentchat | channel-env-vars | warning | manifest uses channelEnvVars legacy compatibility metadata | agentchat | channel-env-vars |
| wecom | package-plugin-api-compat-missing | warning | package openclaw metadata does not declare compat.pluginApi | plugins/wecom/package.json | - |
| a2a-gateway | package-manifest-version-drift | warning | package.json and openclaw.plugin.json publish different versions | package:1.4.0, manifest:1.3.0 | - |
| a2a-gateway | package-plugin-api-compat-missing | warning | package openclaw metadata does not declare compat.pluginApi | plugins/a2a-gateway/package.json | - |
| a2a-gateway | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 | legacy-root-sdk-import |
| hasdata | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | hasdata | provider-auth-env-vars |
| mcp-adapter | package-plugin-api-compat-missing | warning | package openclaw metadata does not declare compat.pluginApi | plugins/mcp-adapter/package.json | - |
| llm-trace-phoenix | conversation-access-hook | warning | fixture observes raw model or conversation content and needs privacy-boundary contract probes | llm_input @ plugins/llm-trace-phoenix/index.ts:154, llm_output @ plugins/llm-trace-phoenix/index.ts:168 | - |
| llm-trace-phoenix | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 | legacy-root-sdk-import |
| codex-app-server | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 | legacy-root-sdk-import |
| web-search-plus | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng | provider-auth-env-vars |
| apify | legacy-root-sdk-import | warning | fixture imports the root plugin SDK barrel | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 | legacy-root-sdk-import |
| inworld-tts | provider-auth-env-vars | warning | manifest uses providerAuthEnvVars legacy compatibility metadata | inworld | provider-auth-env-vars |
## Suggestions To OpenClaw Compat Layer
| Fixture | Code | Level | Message | Evidence | Compat record |
| ---------------- | ------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| agentchat | channel-contract-probe | suggestion | add channel envelope, config-schema, and runtime metadata probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 | - |
| wecom | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerHttpRoute @ plugins/wecom/index.js:45 | - |
| wecom | before-tool-call-probe | suggestion | add contract probes for before_tool_call terminal, block, and approval semantics | before_tool_call @ plugins/wecom/index.js:65 | - |
| wecom | channel-contract-probe | suggestion | add channel envelope, config-schema, and runtime metadata probes | registerChannel @ plugins/wecom/index.js:27 | - |
| wecom | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 | - |
| a2a-gateway | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerGatewayMethod @ plugins/a2a-gateway/index.ts:616, registerGatewayMethod @ plugins/a2a-gateway/index.ts:622, registerGatewayMethod @ plugins/a2a-gateway/index.ts:631, registerGatewayMethod @ plugins/a2a-gateway/index.ts:657, registerGatewayMethod @ plugins/a2a-gateway/index.ts:669, registerService @ plugins/a2a-gateway/index.ts:857 | - |
| a2a-gateway | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 | - |
| mcp-adapter | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerService @ plugins/mcp-adapter/index.ts:15 | - |
| mcp-adapter | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 | - |
| clawmetry | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerService @ plugins/clawmetry/clawhub-plugin/index.ts:9 | - |
| codex-app-server | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerCommand @ plugins/codex-app-server/index.ts:48, registerInteractiveHandler @ plugins/codex-app-server/index.ts:29, registerInteractiveHandler @ plugins/codex-app-server/index.ts:38, registerService @ plugins/codex-app-server/index.ts:12 | - |
| web-search-plus | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 | - |
| apify | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/apify/src/index.ts:13 | - |
| Fixture | Code | Level | Message | Evidence | Compat record |
| ---------------- | --------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| agentchat | package-build-artifact-entrypoint | suggestion | package OpenClaw entrypoint points at build output that is not present in the source fixture checkout | extension:./dist/index.js -> plugins/agentchat/integrations/openclaw-channel/dist/index.js, setupEntry:./dist/setup-entry.js -> plugins/agentchat/integrations/openclaw-channel/dist/setup-entry.js | - |
| agentchat | channel-contract-probe | suggestion | add channel envelope, config-schema, and runtime metadata probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 | - |
| wecom | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerHttpRoute @ plugins/wecom/index.js:45 | - |
| wecom | before-tool-call-probe | suggestion | add contract probes for before_tool_call terminal, block, and approval semantics | before_tool_call @ plugins/wecom/index.js:65 | - |
| wecom | channel-contract-probe | suggestion | add channel envelope, config-schema, and runtime metadata probes | registerChannel @ plugins/wecom/index.js:27 | - |
| wecom | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 | - |
| a2a-gateway | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerGatewayMethod @ plugins/a2a-gateway/index.ts:616, registerGatewayMethod @ plugins/a2a-gateway/index.ts:622, registerGatewayMethod @ plugins/a2a-gateway/index.ts:631, registerGatewayMethod @ plugins/a2a-gateway/index.ts:657, registerGatewayMethod @ plugins/a2a-gateway/index.ts:669, registerService @ plugins/a2a-gateway/index.ts:857 | - |
| a2a-gateway | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 | - |
| mcp-adapter | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerService @ plugins/mcp-adapter/index.ts:15 | - |
| mcp-adapter | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 | - |
| clawmetry | package-build-artifact-entrypoint | suggestion | package OpenClaw entrypoint points at build output that is not present in the source fixture checkout | runtimeExtension:./dist/index.js -> plugins/clawmetry/clawhub-plugin/dist/index.js | - |
| clawmetry | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerService @ plugins/clawmetry/clawhub-plugin/index.ts:9 | - |
| codex-app-server | registration-capture-gap | suggestion | future inspector capture API should record lifecycle, route, gateway, command, and interactive registrations | registerCommand @ plugins/codex-app-server/index.ts:48, registerInteractiveHandler @ plugins/codex-app-server/index.ts:29, registerInteractiveHandler @ plugins/codex-app-server/index.ts:38, registerService @ plugins/codex-app-server/index.ts:12 | - |
| web-search-plus | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 | - |
| apify | runtime-tool-capture | suggestion | tool shape is only visible after runtime registration capture | registerTool @ plugins/apify/src/index.ts:13 | - |
## Issue Findings
@ -80,20 +86,26 @@ _none_
| CRABPOT-0006 | P1 | wecom | inspector | inspector-follow-up | open | wecom: before_tool_call needs terminal/block/approval probes | before_tool_call @ plugins/wecom/index.js:65 |
| CRABPOT-0007 | P1 | wecom | inspector | inspector-follow-up | open | wecom: runtime registrations need capture before contract judgment | registerHttpRoute @ plugins/wecom/index.js:45 |
| CRABPOT-0008 | P2 | a2a-gateway | core | core-compat-adapter | open | a2a-gateway: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 |
| CRABPOT-0009 | P2 | a2a-gateway | inspector | inspector-follow-up | open | a2a-gateway: runtime tool schema needs registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 |
| CRABPOT-0010 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: channel runtime needs envelope/config probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 |
| CRABPOT-0011 | P2 | agentchat | core | core-compat-adapter | open | agentchat: channelEnvVars legacy manifest metadata must stay covered | agentchat |
| CRABPOT-0012 | P2 | apify | core | core-compat-adapter | open | apify: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| CRABPOT-0013 | P2 | apify | inspector | inspector-follow-up | open | apify: runtime tool schema needs registration capture | registerTool @ plugins/apify/src/index.ts:13 |
| CRABPOT-0014 | P2 | codex-app-server | core | core-compat-adapter | open | codex-app-server: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| CRABPOT-0015 | P2 | hasdata | core | core-compat-adapter | open | hasdata: providerAuthEnvVars legacy manifest metadata must stay covered | hasdata |
| CRABPOT-0016 | P2 | inworld-tts | core | core-compat-adapter | open | inworld-tts: providerAuthEnvVars legacy manifest metadata must stay covered | inworld |
| CRABPOT-0017 | P2 | llm-trace-phoenix | core | core-compat-adapter | open | llm-trace-phoenix: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| CRABPOT-0018 | P2 | mcp-adapter | inspector | inspector-follow-up | open | mcp-adapter: runtime tool schema needs registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 |
| CRABPOT-0019 | P2 | web-search-plus | core | core-compat-adapter | open | web-search-plus: providerAuthEnvVars legacy manifest metadata must stay covered | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| CRABPOT-0020 | P2 | web-search-plus | inspector | inspector-follow-up | open | web-search-plus: runtime tool schema needs registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 |
| CRABPOT-0021 | P2 | wecom | inspector | inspector-follow-up | open | wecom: channel runtime needs envelope/config probes | registerChannel @ plugins/wecom/index.js:27 |
| CRABPOT-0022 | P2 | wecom | inspector | inspector-follow-up | open | wecom: runtime tool schema needs registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
| CRABPOT-0009 | P2 | a2a-gateway | plugin | plugin-upstream-fix | open | a2a-gateway: package and manifest versions drift | package:1.4.0, manifest:1.3.0 |
| CRABPOT-0010 | P2 | a2a-gateway | plugin | plugin-upstream-fix | open | a2a-gateway: plugin API compatibility range is missing | plugins/a2a-gateway/package.json |
| CRABPOT-0011 | P2 | a2a-gateway | inspector | inspector-follow-up | open | a2a-gateway: runtime tool schema needs registration capture | registerTool @ plugins/a2a-gateway/index.ts:777 |
| CRABPOT-0012 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: channel runtime needs envelope/config probes | defineChannelPluginEntry @ plugins/agentchat/integrations/openclaw-channel/src/channel.ts:333 |
| CRABPOT-0013 | P2 | agentchat | core | core-compat-adapter | open | agentchat: channelEnvVars legacy manifest metadata must stay covered | agentchat |
| CRABPOT-0014 | P2 | agentchat | inspector | inspector-follow-up | open | agentchat: cold import requires package build output | extension:./dist/index.js -> plugins/agentchat/integrations/openclaw-channel/dist/index.js, setupEntry:./dist/setup-entry.js -> plugins/agentchat/integrations/openclaw-channel/dist/setup-entry.js |
| CRABPOT-0015 | P2 | apify | core | core-compat-adapter | open | apify: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| CRABPOT-0016 | P2 | apify | inspector | inspector-follow-up | open | apify: runtime tool schema needs registration capture | registerTool @ plugins/apify/src/index.ts:13 |
| CRABPOT-0017 | P2 | clawmetry | inspector | inspector-follow-up | open | clawmetry: cold import requires package build output | runtimeExtension:./dist/index.js -> plugins/clawmetry/clawhub-plugin/dist/index.js |
| CRABPOT-0018 | P2 | codex-app-server | core | core-compat-adapter | open | codex-app-server: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| CRABPOT-0019 | P2 | hasdata | core | core-compat-adapter | open | hasdata: providerAuthEnvVars legacy manifest metadata must stay covered | hasdata |
| CRABPOT-0020 | P2 | inworld-tts | core | core-compat-adapter | open | inworld-tts: providerAuthEnvVars legacy manifest metadata must stay covered | inworld |
| CRABPOT-0021 | P2 | llm-trace-phoenix | core | core-compat-adapter | open | llm-trace-phoenix: root plugin SDK barrel is still used by fixtures | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| CRABPOT-0022 | P2 | mcp-adapter | plugin | plugin-upstream-fix | open | mcp-adapter: plugin API compatibility range is missing | plugins/mcp-adapter/package.json |
| CRABPOT-0023 | P2 | mcp-adapter | inspector | inspector-follow-up | open | mcp-adapter: runtime tool schema needs registration capture | registerTool @ plugins/mcp-adapter/index.ts:30 |
| CRABPOT-0024 | P2 | web-search-plus | core | core-compat-adapter | open | web-search-plus: providerAuthEnvVars legacy manifest metadata must stay covered | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| CRABPOT-0025 | P2 | web-search-plus | inspector | inspector-follow-up | open | web-search-plus: runtime tool schema needs registration capture | registerTool @ plugins/web-search-plus/index.ts:815, registerTool @ plugins/web-search-plus/index.ts:947 |
| CRABPOT-0026 | P2 | wecom | inspector | inspector-follow-up | open | wecom: channel runtime needs envelope/config probes | registerChannel @ plugins/wecom/index.js:27 |
| CRABPOT-0027 | P2 | wecom | plugin | plugin-upstream-fix | open | wecom: plugin API compatibility range is missing | plugins/wecom/package.json |
| CRABPOT-0028 | P2 | wecom | inspector | inspector-follow-up | open | wecom: runtime tool schema needs registration capture | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
## Contract Probe Backlog
@ -110,6 +122,11 @@ _none_
| channel.runtime.envelope-config-metadata:wecom | P2 | wecom | channel-runtime | Channel setup, message envelope, sender metadata, and config schema remain stable. | registerChannel @ plugins/wecom/index.js:27 |
| manifest.compat.channel-env-vars:agentchat | P2 | agentchat | manifest-loader | Legacy channel env metadata continues to map into channel setup/help surfaces. | agentchat |
| manifest.compat.provider-auth-env-vars:hasdata | P2 | hasdata | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | hasdata |
| package.compat.plugin-api-range:a2a-gateway | P2 | a2a-gateway | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/a2a-gateway/package.json |
| package.compat.plugin-api-range:mcp-adapter | P2 | mcp-adapter | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/mcp-adapter/package.json |
| package.compat.plugin-api-range:wecom | P2 | wecom | package-loader | Package metadata declares the OpenClaw plugin API range used by the plugin. | plugins/wecom/package.json |
| package.entrypoint.build-before-cold-import:agentchat | P2 | agentchat | package-loader | Inspector can build or resolve source aliases before cold importing package entrypoints. | extension:./dist/index.js -> plugins/agentchat/integrations/openclaw-channel/dist/index.js, setupEntry:./dist/setup-entry.js -> plugins/agentchat/integrations/openclaw-channel/dist/setup-entry.js |
| package.metadata.version-alignment:a2a-gateway | P2 | a2a-gateway | package-loader | Package and OpenClaw manifest versions stay aligned for release compatibility reporting. | package:1.4.0, manifest:1.3.0 |
| sdk.import.root-barrel-cold-import:a2a-gateway | P2 | a2a-gateway | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/a2a-gateway/src/types.ts:14 |
| sdk.import.root-barrel-cold-import:llm-trace-phoenix | P2 | llm-trace-phoenix | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/llm-trace-phoenix/index.ts:12 |
| tool.registration.schema-capture:a2a-gateway | P2 | a2a-gateway | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/a2a-gateway/index.ts:777 |
@ -117,6 +134,7 @@ _none_
| tool.registration.schema-capture:wecom | P2 | wecom | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/wecom/index.js:28, registerTool @ plugins/wecom/index.js:29, registerTool @ plugins/wecom/index.js:33 |
| manifest.compat.provider-auth-env-vars:inworld-tts | P3 | inworld-tts | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | inworld |
| manifest.compat.provider-auth-env-vars:web-search-plus | P3 | web-search-plus | manifest-loader | Legacy provider auth env metadata continues to map into config/help surfaces. | serper, tavily, linkup, querit, exa, firecrawl, perplexity, you, searxng |
| package.entrypoint.build-before-cold-import:clawmetry | P3 | clawmetry | package-loader | Inspector can build or resolve source aliases before cold importing package entrypoints. | runtimeExtension:./dist/index.js -> plugins/clawmetry/clawhub-plugin/dist/index.js |
| sdk.import.root-barrel-cold-import:apify | P3 | apify | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/apify/src/cli.ts:2, openclaw/plugin-sdk @ plugins/apify/src/index.ts:1, openclaw/plugin-sdk @ plugins/apify/src/tools/apify-scraper-tool.ts:4 |
| sdk.import.root-barrel-cold-import:codex-app-server | P3 | codex-app-server | sdk-alias | Root plugin SDK barrel remains importable or has a machine-readable migration path. | openclaw/plugin-sdk @ plugins/codex-app-server/index.ts:1, openclaw/plugin-sdk @ plugins/codex-app-server/src/client.ts:6, openclaw/plugin-sdk @ plugins/codex-app-server/src/controller.ts:18, openclaw/plugin-sdk @ plugins/codex-app-server/src/types.ts:1 |
| tool.registration.schema-capture:apify | P3 | apify | tool-runtime | Registered runtime tools expose stable names, input schemas, and result metadata. | registerTool @ plugins/apify/src/index.ts:13 |
@ -142,21 +160,27 @@ _none_
| Fixture | Decision | Seam | Action | Evidence |
| ----------------- | ------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| agentchat | inspector-follow-up | cold-import | Run the plugin build or resolve source entrypoint aliases before cold-importing this fixture. | ./dist/index.js, ./dist/setup-entry.js |
| agentchat | core-compat-adapter | channel-env | Keep channelEnvVars compatibility active until channel setup metadata has a stable replacement path. | agentchat |
| agentchat | inspector-follow-up | channel-runtime | Probe channel setup and message envelope contracts before changing channel runtime payloads. | defineChannelPluginEntry |
| wecom | plugin-upstream-fix | package-metadata | Ask the plugin to declare the plugin API range it was built against. | plugins/wecom/package.json |
| wecom | inspector-follow-up | registration-capture | Expose or mirror a full public API capture shim before treating these runtime-only seams as covered. | registerHttpRoute |
| wecom | inspector-follow-up | tool-policy | Probe before_tool_call return shapes before changing tool-call approval or block behavior. | before_tool_call |
| wecom | inspector-follow-up | channel-runtime | Probe channel setup and message envelope contracts before changing channel runtime payloads. | registerChannel |
| wecom | inspector-follow-up | tool-schema | Capture registered tool schemas from plugin register() before judging tool compatibility. | registerTool without manifest contracts.tools |
| a2a-gateway | plugin-upstream-fix | package-metadata | Ask the plugin to keep package and manifest versions aligned before relying on release compatibility signals. | 1.4.0 != 1.3.0 |
| a2a-gateway | plugin-upstream-fix | package-metadata | Ask the plugin to declare the plugin API range it was built against. | plugins/a2a-gateway/package.json |
| a2a-gateway | core-compat-adapter | sdk-import | Keep the root SDK barrel stable or expose a machine-readable migration map before removing aliases. | openclaw/plugin-sdk |
| a2a-gateway | inspector-follow-up | registration-capture | Expose or mirror a full public API capture shim before treating these runtime-only seams as covered. | registerGatewayMethod, registerService |
| a2a-gateway | inspector-follow-up | tool-schema | Capture registered tool schemas from plugin register() before judging tool compatibility. | registerTool without manifest contracts.tools |
| hasdata | core-compat-adapter | env-auth | Keep providerAuthEnvVars compatibility active while the inspector recommends manifest-schema migration upstream. | hasdata |
| hasdata | no-action | manifest-contract | Keep checking this declarative contract in default offline CI. | tools |
| mcp-adapter | plugin-upstream-fix | package-metadata | Ask the plugin to declare the plugin API range it was built against. | plugins/mcp-adapter/package.json |
| mcp-adapter | inspector-follow-up | registration-capture | Expose or mirror a full public API capture shim before treating these runtime-only seams as covered. | registerService |
| mcp-adapter | inspector-follow-up | tool-schema | Capture registered tool schemas from plugin register() before judging tool compatibility. | registerTool without manifest contracts.tools |
| llm-trace-phoenix | inspector-follow-up | conversation-access | Add synthetic llm_input/llm_output/agent_end probes before tightening hook payloads or redaction behavior. | llm_input, llm_output |
| llm-trace-phoenix | core-compat-adapter | sdk-import | Keep the root SDK barrel stable or expose a machine-readable migration map before removing aliases. | openclaw/plugin-sdk |
| clawmetry | inspector-follow-up | cold-import | Run the plugin build or resolve source entrypoint aliases before cold-importing this fixture. | ./dist/index.js |
| clawmetry | inspector-follow-up | registration-capture | Expose or mirror a full public API capture shim before treating these runtime-only seams as covered. | registerService |
| codex-app-server | core-compat-adapter | sdk-import | Keep the root SDK barrel stable or expose a machine-readable migration map before removing aliases. | openclaw/plugin-sdk |
| codex-app-server | inspector-follow-up | registration-capture | Expose or mirror a full public API capture shim before treating these runtime-only seams as covered. | registerCommand, registerInteractiveHandler, registerService |
@ -169,48 +193,68 @@ _none_
## Raw Logs
| Fixture | Code | Level | Message | Evidence | Compat record |
| ----------------- | ---------------------- | ----- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| agentchat | seam-inventory | log | observed 0 hooks, 1 registrations, and 0 manifest contracts | registration:defineChannelPluginEntry | - |
| agentchat | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| agentchat | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | - | - |
| wecom | seam-inventory | log | observed 5 hooks, 3 registrations, and 0 manifest contracts | hook:before_prompt_build, hook:before_tool_call, hook:subagent_delivery_target, hook:subagent_ended, hook:subagent_spawned, registration:registerChannel, registration:registerHttpRoute, registration:registerTool | - |
| wecom | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | before_prompt_build, before_tool_call, subagent_delivery_target, subagent_ended, subagent_spawned | - |
| wecom | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerChannel, registerHttpRoute, registerTool | - |
| a2a-gateway | seam-inventory | log | observed 0 hooks, 3 registrations, and 0 manifest contracts | registration:registerGatewayMethod, registration:registerService, registration:registerTool | - |
| a2a-gateway | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| a2a-gateway | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerGatewayMethod, registerService, registerTool | - |
| hasdata | seam-inventory | log | observed 0 hooks, 1 registrations, and 1 manifest contracts | registration:registerTool, manifestContract:tools | - |
| hasdata | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| hasdata | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerTool | - |
| hasdata | declarative-contracts | log | fixture declares manifest contracts that can be checked without executing plugin code | tools | - |
| mcp-adapter | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:registerService, registration:registerTool | - |
| mcp-adapter | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| mcp-adapter | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerService, registerTool | - |
| llm-trace-phoenix | seam-inventory | log | observed 2 hooks, 0 registrations, and 0 manifest contracts | hook:llm_input, hook:llm_output | - |
| llm-trace-phoenix | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | llm_input, llm_output | - |
| llm-trace-phoenix | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | - | - |
| clawmetry | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:definePluginEntry, registration:registerService | - |
| clawmetry | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| clawmetry | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerService | - |
| codex-app-server | seam-inventory | log | observed 1 hooks, 3 registrations, and 0 manifest contracts | hook:inbound_claim, registration:registerCommand, registration:registerInteractiveHandler, registration:registerService | - |
| codex-app-server | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | inbound_claim | - |
| codex-app-server | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerCommand, registerInteractiveHandler, registerService | - |
| web-search-plus | seam-inventory | log | observed 0 hooks, 1 registrations, and 0 manifest contracts | registration:registerTool | - |
| web-search-plus | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| web-search-plus | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerTool | - |
| apify | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:registerCli, registration:registerTool | - |
| apify | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| apify | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerCli, registerTool | - |
| inworld-tts | seam-inventory | log | observed 0 hooks, 2 registrations, and 1 manifest contracts | registration:definePluginEntry, registration:registerSpeechProvider, manifestContract:speechProviders | - |
| inworld-tts | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| inworld-tts | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerSpeechProvider | - |
| inworld-tts | declarative-contracts | log | fixture declares manifest contracts that can be checked without executing plugin code | speechProviders | - |
| agentchat | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | channel-env-vars | channel-env-vars |
| a2a-gateway | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| hasdata | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |
| llm-trace-phoenix | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| codex-app-server | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| web-search-plus | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |
| apify | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| inworld-tts | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |
| Fixture | Code | Level | Message | Evidence | Compat record |
| ----------------- | ---------------------------- | ----- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| agentchat | seam-inventory | log | observed 0 hooks, 1 registrations, and 0 manifest contracts | registration:defineChannelPluginEntry | - |
| agentchat | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| agentchat | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | - | - |
| agentchat | package-metadata | log | selected package metadata for plugin contract checks | plugins/agentchat/integrations/openclaw-channel/package.json, @agentchatme/openclaw, version:0.6.1 | - |
| wecom | seam-inventory | log | observed 5 hooks, 3 registrations, and 0 manifest contracts | hook:before_prompt_build, hook:before_tool_call, hook:subagent_delivery_target, hook:subagent_ended, hook:subagent_spawned, registration:registerChannel, registration:registerHttpRoute, registration:registerTool | - |
| wecom | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | before_prompt_build, before_tool_call, subagent_delivery_target, subagent_ended, subagent_spawned | - |
| wecom | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerChannel, registerHttpRoute, registerTool | - |
| wecom | package-metadata | log | selected package metadata for plugin contract checks | plugins/wecom/package.json, @sunnoy/wecom, version:3.0.1 | - |
| a2a-gateway | seam-inventory | log | observed 0 hooks, 3 registrations, and 0 manifest contracts | registration:registerGatewayMethod, registration:registerService, registration:registerTool | - |
| a2a-gateway | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| a2a-gateway | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerGatewayMethod, registerService, registerTool | - |
| a2a-gateway | package-metadata | log | selected package metadata for plugin contract checks | plugins/a2a-gateway/package.json, openclaw-a2a-gateway, version:1.4.0 | - |
| a2a-gateway | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/a2a-gateway/index.ts | - |
| hasdata | seam-inventory | log | observed 0 hooks, 1 registrations, and 1 manifest contracts | registration:registerTool, manifestContract:tools | - |
| hasdata | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| hasdata | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerTool | - |
| hasdata | package-metadata | log | selected package metadata for plugin contract checks | plugins/hasdata/package.json, @hasdata/hasdata-openclaw-plugin, version:0.1.5 | - |
| hasdata | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/hasdata/src/index.ts | - |
| hasdata | declarative-contracts | log | fixture declares manifest contracts that can be checked without executing plugin code | tools | - |
| mcp-adapter | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:registerService, registration:registerTool | - |
| mcp-adapter | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| mcp-adapter | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerService, registerTool | - |
| mcp-adapter | package-metadata | log | selected package metadata for plugin contract checks | plugins/mcp-adapter/package.json, openclaw-mcp-adapter, version:0.1.1 | - |
| mcp-adapter | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/mcp-adapter/index.ts | - |
| llm-trace-phoenix | seam-inventory | log | observed 2 hooks, 0 registrations, and 0 manifest contracts | hook:llm_input, hook:llm_output | - |
| llm-trace-phoenix | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | llm_input, llm_output | - |
| llm-trace-phoenix | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | - | - |
| llm-trace-phoenix | package-metadata | log | selected package metadata for plugin contract checks | plugins/llm-trace-phoenix/package.json, llm-trace-phoenix, version:1.0.1 | - |
| llm-trace-phoenix | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/llm-trace-phoenix/index.ts | - |
| clawmetry | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:definePluginEntry, registration:registerService | - |
| clawmetry | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| clawmetry | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerService | - |
| clawmetry | package-metadata | log | selected package metadata for plugin contract checks | plugins/clawmetry/clawhub-plugin/package.json, @clawmetry/openclaw-plugin, version:1.0.0 | - |
| clawmetry | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/clawmetry/clawhub-plugin/index.ts | - |
| codex-app-server | seam-inventory | log | observed 1 hooks, 3 registrations, and 0 manifest contracts | hook:inbound_claim, registration:registerCommand, registration:registerInteractiveHandler, registration:registerService | - |
| codex-app-server | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | inbound_claim | - |
| codex-app-server | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerCommand, registerInteractiveHandler, registerService | - |
| codex-app-server | package-metadata | log | selected package metadata for plugin contract checks | plugins/codex-app-server/package.json, openclaw-codex-app-server, version:0.0.0 | - |
| codex-app-server | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/codex-app-server/index.ts | - |
| web-search-plus | seam-inventory | log | observed 0 hooks, 1 registrations, and 0 manifest contracts | registration:registerTool | - |
| web-search-plus | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| web-search-plus | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerTool | - |
| web-search-plus | package-metadata | log | selected package metadata for plugin contract checks | plugins/web-search-plus/package.json, web-search-plus-plugin-v2, version:2.2.0 | - |
| web-search-plus | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/web-search-plus/index.ts | - |
| apify | seam-inventory | log | observed 0 hooks, 2 registrations, and 0 manifest contracts | registration:registerCli, registration:registerTool | - |
| apify | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| apify | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerCli, registerTool | - |
| apify | package-metadata | log | selected package metadata for plugin contract checks | plugins/apify/package.json, @apify/apify-openclaw-plugin, version:0.2.0 | - |
| apify | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/apify/src/index.ts | - |
| inworld-tts | seam-inventory | log | observed 0 hooks, 2 registrations, and 1 manifest contracts | registration:definePluginEntry, registration:registerSpeechProvider, manifestContract:speechProviders | - |
| inworld-tts | hook-names-present | log | all observed hooks exist in the target OpenClaw hook registry | - | - |
| inworld-tts | api-registrars-present | log | all observed api.register* calls exist in the target OpenClaw plugin API builder | registerSpeechProvider | - |
| inworld-tts | package-metadata | log | selected package metadata for plugin contract checks | plugins/inworld-tts/package.json, openclaw-inworld-tts, version:1.0.2 | - |
| inworld-tts | typescript-source-entrypoint | log | package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout | extension:plugins/inworld-tts/index.ts | - |
| inworld-tts | declarative-contracts | log | fixture declares manifest contracts that can be checked without executing plugin code | speechProviders | - |
| agentchat | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | channel-env-vars | channel-env-vars |
| a2a-gateway | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| hasdata | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |
| llm-trace-phoenix | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| codex-app-server | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| web-search-plus | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |
| apify | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | legacy-root-sdk-import | legacy-root-sdk-import |
| inworld-tts | compat-record-present | log | target OpenClaw checkout has a matching compat registry record | provider-auth-env-vars | provider-auth-env-vars |

View File

@ -1,5 +1,5 @@
import { existsSync } from "node:fs";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
import path from "node:path";
import { inspectManifest } from "./inspect-fixtures.mjs";
import { readManifest, repoRoot } from "./manifest-lib.mjs";
@ -311,6 +311,48 @@ function issueMetadata(finding) {
decision: "core-compat-adapter",
title: "compat-dependent behavior lacks registry coverage",
},
"package-build-artifact-entrypoint": {
severity: "P2",
owner: "inspector",
decision: "inspector-follow-up",
title: "cold import requires package build output",
},
"package-entrypoint-missing": {
severity: "P1",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "OpenClaw package entrypoint is missing",
},
"package-json-missing": {
severity: "P2",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "package metadata is missing",
},
"package-manifest-version-drift": {
severity: "P2",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "package and manifest versions drift",
},
"package-openclaw-entry-missing": {
severity: "P2",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "OpenClaw package entrypoint metadata is missing",
},
"package-openclaw-metadata-missing": {
severity: "P2",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "OpenClaw package metadata is missing",
},
"package-plugin-api-compat-missing": {
severity: "P2",
owner: "plugin",
decision: "plugin-upstream-fix",
title: "plugin API compatibility range is missing",
},
"provider-auth-env-vars": {
severity: "P2",
owner: "core",
@ -380,6 +422,36 @@ function buildContractProbes({ warnings, suggestions, fixtures }) {
contract: "External inspector capture records service, route, gateway, command, and interactive registrations.",
target: "inspector-capture-api",
},
"package-build-artifact-entrypoint": {
id: "package.entrypoint.build-before-cold-import",
contract: "Inspector can build or resolve source aliases before cold importing package entrypoints.",
target: "package-loader",
},
"package-entrypoint-missing": {
id: "package.entrypoint.exists",
contract: "OpenClaw package entrypoints resolve to files in the published or built plugin package.",
target: "package-loader",
},
"package-openclaw-entry-missing": {
id: "package.entrypoint.openclaw-metadata",
contract: "OpenClaw package metadata declares entrypoints for cold import and registration capture.",
target: "package-loader",
},
"package-openclaw-metadata-missing": {
id: "package.metadata.openclaw",
contract: "Plugins that register OpenClaw APIs declare OpenClaw install and entrypoint metadata.",
target: "package-loader",
},
"package-manifest-version-drift": {
id: "package.metadata.version-alignment",
contract: "Package and OpenClaw manifest versions stay aligned for release compatibility reporting.",
target: "package-loader",
},
"package-plugin-api-compat-missing": {
id: "package.compat.plugin-api-range",
contract: "Package metadata declares the OpenClaw plugin API range used by the plugin.",
target: "package-loader",
},
"runtime-tool-capture": {
id: "tool.registration.schema-capture",
contract: "Registered runtime tools expose stable names, input schemas, and result metadata.",
@ -458,6 +530,7 @@ function classifyFixture({ fixture, inspection, fixtureReport, targetOpenClaw, b
classifyHookNameCoverage({ fixture, inspection, targetOpenClaw, breakages, logs });
classifyRegistrationNameCoverage({ fixture, inspection, targetOpenClaw, breakages, logs });
classifyPackageContracts({ fixture, inspection, fixtureReport, warnings, suggestions, logs, decisions });
for (const pluginManifest of fixtureReport.pluginManifests) {
const providerAuthKeys = Object.keys(pluginManifest.providerAuthEnvVars ?? {});
@ -700,12 +773,167 @@ function classifyRegistrationNameCoverage({ fixture, inspection, targetOpenClaw,
});
}
function classifyPackageContracts({ fixture, inspection, fixtureReport, warnings, suggestions, logs, decisions }) {
const packageSummary = fixtureReport.package;
if (!packageSummary) {
warnings.push({
fixture: fixture.id,
code: "package-json-missing",
level: "warning",
message: "fixture has no package.json to describe install and plugin entrypoint metadata",
evidence: [fixture.path],
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-metadata",
action: "Ask the plugin to publish package metadata before treating install/cold-import checks as covered.",
evidence: fixture.path,
});
return;
}
logs.push({
fixture: fixture.id,
code: "package-metadata",
level: "log",
message: "selected package metadata for plugin contract checks",
evidence: [
packageSummary.path,
packageSummary.name ?? "unnamed",
packageSummary.version ? `version:${packageSummary.version}` : "version:missing",
],
});
const manifestVersions = fixtureReport.pluginManifests
.map((manifest) => manifest.version)
.filter((version) => typeof version === "string" && version.length > 0);
const mismatchedManifestVersions = manifestVersions.filter((version) => version !== packageSummary.version);
if (packageSummary.version && mismatchedManifestVersions.length > 0) {
warnings.push({
fixture: fixture.id,
code: "package-manifest-version-drift",
level: "warning",
message: "package.json and openclaw.plugin.json publish different versions",
evidence: [`package:${packageSummary.version}`, ...mismatchedManifestVersions.map((version) => `manifest:${version}`)],
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-metadata",
action: "Ask the plugin to keep package and manifest versions aligned before relying on release compatibility signals.",
evidence: `${packageSummary.version} != ${mismatchedManifestVersions.join(", ")}`,
});
}
if (packageSummary.openclaw && !packageSummary.openclaw.compatPluginApi) {
warnings.push({
fixture: fixture.id,
code: "package-plugin-api-compat-missing",
level: "warning",
message: "package openclaw metadata does not declare compat.pluginApi",
evidence: [packageSummary.path],
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-metadata",
action: "Ask the plugin to declare the plugin API range it was built against.",
evidence: packageSummary.path,
});
}
if (packageSummary.openclaw && packageSummary.openclaw.entrypoints.length === 0) {
warnings.push({
fixture: fixture.id,
code: "package-openclaw-entry-missing",
level: "warning",
message: "package openclaw metadata does not declare plugin entrypoints",
evidence: [packageSummary.path],
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-entrypoint",
action: "Ask the plugin to declare openclaw.extensions or runtimeExtensions so cold import can target the correct entrypoint.",
evidence: packageSummary.path,
});
}
const missingEntrypoints = packageSummary.openclaw?.entrypoints.filter((entrypoint) => !entrypoint.exists) ?? [];
const buildEntrypoints = missingEntrypoints.filter((entrypoint) => entrypoint.requiresBuild);
const plainMissingEntrypoints = missingEntrypoints.filter((entrypoint) => !entrypoint.requiresBuild);
if (buildEntrypoints.length > 0) {
suggestions.push({
fixture: fixture.id,
code: "package-build-artifact-entrypoint",
level: "suggestion",
message: "package OpenClaw entrypoint points at build output that is not present in the source fixture checkout",
evidence: buildEntrypoints.map((entrypoint) => `${entrypoint.kind}:${entrypoint.specifier} -> ${entrypoint.relativePath}`),
});
decisions.push({
fixture: fixture.id,
decision: "inspector-follow-up",
seam: "cold-import",
action: "Run the plugin build or resolve source entrypoint aliases before cold-importing this fixture.",
evidence: buildEntrypoints.map((entrypoint) => entrypoint.specifier).join(", "),
});
}
if (plainMissingEntrypoints.length > 0) {
warnings.push({
fixture: fixture.id,
code: "package-entrypoint-missing",
level: "warning",
message: "package OpenClaw entrypoint does not exist in the fixture checkout",
evidence: plainMissingEntrypoints.map((entrypoint) => `${entrypoint.kind}:${entrypoint.specifier} -> ${entrypoint.relativePath}`),
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-entrypoint",
action: "Ask the plugin to publish a valid OpenClaw entrypoint or update package metadata.",
evidence: plainMissingEntrypoints.map((entrypoint) => entrypoint.specifier).join(", "),
});
}
const sourceEntrypoints = packageSummary.openclaw?.entrypoints.filter((entrypoint) => entrypoint.exists && entrypoint.relativePath.endsWith(".ts")) ?? [];
if (sourceEntrypoints.length > 0) {
logs.push({
fixture: fixture.id,
code: "typescript-source-entrypoint",
level: "log",
message: "package OpenClaw entrypoint resolves to TypeScript source in this fixture checkout",
evidence: sourceEntrypoints.map((entrypoint) => `${entrypoint.kind}:${entrypoint.relativePath}`),
});
}
if (inspection.registrations.length > 0 && !packageSummary.openclaw) {
warnings.push({
fixture: fixture.id,
code: "package-openclaw-metadata-missing",
level: "warning",
message: "fixture registers plugin APIs but the selected package.json has no openclaw metadata",
evidence: [packageSummary.path, ...inspection.registrations],
});
decisions.push({
fixture: fixture.id,
decision: "plugin-upstream-fix",
seam: "package-metadata",
action: "Ask the plugin to declare OpenClaw install and entrypoint metadata in package.json.",
evidence: packageSummary.path,
});
}
}
async function buildFixtureReport(fixture, inspection) {
const checkoutPath = path.join(repoRoot, fixture.path);
const sourceRoot = fixture.subdir ? path.join(checkoutPath, fixture.subdir) : checkoutPath;
const pluginManifests = await readPluginManifests(checkoutPath, sourceRoot);
const packageJson = await readPackageSummary(checkoutPath, sourceRoot);
const packageSummaries = await readPackageSummaries(checkoutPath, sourceRoot);
const packageJson = selectPrimaryPackage(packageSummaries);
const sdkImports = unique((inspection.sdkImports ?? []).map((sdkImport) => sdkImport.specifier));
return {
@ -724,6 +952,7 @@ async function buildFixtureReport(fixture, inspection) {
sourceFiles: inspection.sourceFiles ?? [],
pluginManifests,
package: packageJson,
packages: packageSummaries,
sdkImports,
sdkImportDetails: inspection.sdkImports ?? [],
};
@ -815,21 +1044,117 @@ async function readTargetOpenClaw(manifest, configuredPath) {
};
}
async function readPackageSummary(checkoutPath, sourceRoot) {
const candidates = unique([path.join(sourceRoot, "package.json"), path.join(checkoutPath, "package.json")].filter(existsSync));
if (candidates.length === 0) {
return null;
async function readPackageSummaries(checkoutPath, sourceRoot) {
const candidates = unique([
path.join(sourceRoot, "package.json"),
path.join(checkoutPath, "package.json"),
...(await findPackageFiles(checkoutPath, { maxDepth: 3 })),
].filter(existsSync));
const summaries = [];
for (const packagePath of candidates) {
const packageJson = JSON.parse(await readFile(packagePath, "utf8"));
summaries.push(summarizePackage(packagePath, packageJson));
}
return summaries.sort((left, right) => packageRank(left) - packageRank(right) || left.path.localeCompare(right.path));
}
function summarizePackage(packagePath, packageJson) {
const packageDir = path.dirname(packagePath);
const openclaw = packageJson.openclaw
? {
extensions: arrayValues(packageJson.openclaw.extensions),
runtimeExtensions: arrayValues(packageJson.openclaw.runtimeExtensions),
setupEntry: typeof packageJson.openclaw.setupEntry === "string" ? packageJson.openclaw.setupEntry : null,
compatPluginApi:
typeof packageJson.openclaw.compat?.pluginApi === "string" ? packageJson.openclaw.compat.pluginApi : null,
buildOpenClawVersion:
typeof packageJson.openclaw.build?.openclawVersion === "string"
? packageJson.openclaw.build.openclawVersion
: null,
buildPluginSdkVersion:
typeof packageJson.openclaw.build?.pluginSdkVersion === "string"
? packageJson.openclaw.build.pluginSdkVersion
: null,
}
: null;
if (openclaw) {
openclaw.entrypoints = collectOpenClawEntrypoints(packageDir, openclaw);
}
const packageJson = JSON.parse(await readFile(candidates[0], "utf8"));
return {
path: path.relative(repoRoot, candidates[0]),
path: path.relative(repoRoot, packagePath),
name: packageJson.name ?? null,
version: packageJson.version ?? null,
type: packageJson.type ?? null,
main: typeof packageJson.main === "string" ? packageJson.main : null,
openclaw,
};
}
function collectOpenClawEntrypoints(packageDir, openclaw) {
const entrypoints = [
...openclaw.extensions.map((specifier) => ({ kind: "extension", specifier })),
...openclaw.runtimeExtensions.map((specifier) => ({ kind: "runtimeExtension", specifier })),
...(openclaw.setupEntry ? [{ kind: "setupEntry", specifier: openclaw.setupEntry }] : []),
];
return entrypoints.map((entrypoint) => {
const resolvedPath = path.resolve(packageDir, entrypoint.specifier);
const relativePath = path.relative(repoRoot, resolvedPath);
return {
...entrypoint,
relativePath,
exists: existsSync(resolvedPath),
requiresBuild: /(^|\/)dist\//.test(entrypoint.specifier) || /(^|\/)build\//.test(entrypoint.specifier),
};
});
}
async function findPackageFiles(root, options, depth = 0) {
if (!existsSync(root) || depth > options.maxDepth) {
return [];
}
const files = [];
for (const entry of await readdir(root, { withFileTypes: true })) {
const entryPath = path.join(root, entry.name);
if (entry.isFile() && entry.name === "package.json") {
files.push(entryPath);
continue;
}
if (!entry.isDirectory() || shouldSkipPackageDir(entry.name)) {
continue;
}
files.push(...(await findPackageFiles(entryPath, options, depth + 1)));
}
return files;
}
function shouldSkipPackageDir(name) {
return name === ".git" || name === "node_modules" || name === "dist" || name === "build" || name === "coverage";
}
function selectPrimaryPackage(packages) {
return packages[0] ?? null;
}
function packageRank(packageSummary) {
if (packageSummary.openclaw?.entrypoints.length > 0) {
return 0;
}
if (packageSummary.openclaw) {
return 1;
}
return 2;
}
function arrayValues(value) {
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
}
function emptyInspection(fixture) {
return {
id: fixture.id,