refactor(api): simplify public package surface
This commit is contained in:
parent
fc7cb61afd
commit
1840c601a7
112
README.md
112
README.md
@ -6,22 +6,17 @@
|
||||
wraps the static inspection, registration capture, and report model prototyped
|
||||
in crabpot into an npm-publishable package.
|
||||
|
||||
No npm package has been published yet.
|
||||
|
||||
## Install
|
||||
|
||||
During development, use a local checkout or packed tarball:
|
||||
|
||||
```bash
|
||||
npm install --save-dev ../plugin-inspector
|
||||
npx plugin-inspector check --no-openclaw
|
||||
```
|
||||
|
||||
After the package is published, plugin repos should install it as a dev
|
||||
dependency and run it from the plugin root:
|
||||
Install it as a dev dependency in a plugin repo:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @openclaw/plugin-inspector
|
||||
```
|
||||
|
||||
Then run it from the plugin root:
|
||||
|
||||
```bash
|
||||
npx @openclaw/plugin-inspector check
|
||||
```
|
||||
|
||||
@ -145,101 +140,6 @@ jobs:
|
||||
path: reports/plugin-inspector-*
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
import {
|
||||
buildCiSummary,
|
||||
buildCiPolicyReport,
|
||||
buildColdImportReadiness,
|
||||
buildContractCapture,
|
||||
buildExecutionResultsReport,
|
||||
buildImportLoopProfile,
|
||||
buildPlatformProbes,
|
||||
buildProfileDiff,
|
||||
buildRefDiff,
|
||||
buildRuntimeProfile,
|
||||
buildRuntimeCaptureReport,
|
||||
buildWorkspacePlan,
|
||||
createCaptureApi,
|
||||
inspectFixtureSet,
|
||||
loadInspectorConfig,
|
||||
readOpenClawTargetSurface,
|
||||
renderCiPolicyMarkdown,
|
||||
renderColdImportReadinessMarkdown,
|
||||
renderContractCaptureMarkdown,
|
||||
renderExecutionResultsMarkdown,
|
||||
renderImportLoopProfileMarkdown,
|
||||
renderPlatformProbesMarkdown,
|
||||
renderProfileDiffMarkdown,
|
||||
renderRefDiffMarkdown,
|
||||
renderRuntimeProfileMarkdown,
|
||||
renderRuntimeCaptureMarkdown,
|
||||
renderWorkspacePlanMarkdown,
|
||||
renderMarkdownReport,
|
||||
validateCiPolicyReport,
|
||||
validateContractCoverage,
|
||||
writeCiSummary,
|
||||
writeCiPolicyReport,
|
||||
writeColdImportReadiness,
|
||||
writeContractCapture,
|
||||
writeExecutionResultsReport,
|
||||
writeImportLoopProfile,
|
||||
writePlatformProbes,
|
||||
writeProfileDiff,
|
||||
writeRefDiff,
|
||||
writeRuntimeProfile,
|
||||
writeRuntimeCaptureReport,
|
||||
writeWorkspacePlan,
|
||||
writeReport,
|
||||
} from "@openclaw/plugin-inspector";
|
||||
|
||||
const config = await loadInspectorConfig("crabpot.config.json");
|
||||
const report = await inspectFixtureSet(config);
|
||||
await writeReport(report, { outDir: "reports" });
|
||||
|
||||
const summary = await buildCiSummary({ reportsDir: "reports" });
|
||||
await writeCiSummary(summary);
|
||||
|
||||
const policyReport = buildCiPolicyReport({ policy, compatibilityReport: report });
|
||||
await writeCiPolicyReport(policyReport);
|
||||
|
||||
const capture = buildContractCapture({ report });
|
||||
await writeContractCapture(capture);
|
||||
const coverageErrors = validateContractCoverage(report);
|
||||
|
||||
const readiness = buildColdImportReadiness({ report });
|
||||
await writeColdImportReadiness(readiness);
|
||||
|
||||
const target = await readOpenClawTargetSurface({ manifest: config });
|
||||
|
||||
const workspacePlan = await buildWorkspacePlan({ report, readiness });
|
||||
await writeWorkspacePlan(workspacePlan);
|
||||
|
||||
const platformProbes = buildPlatformProbes({ plan: workspacePlan });
|
||||
await writePlatformProbes(platformProbes);
|
||||
|
||||
const executionResults = await buildExecutionResultsReport({ resultsDir: ".plugin-inspector/results" });
|
||||
await writeExecutionResultsReport(executionResults);
|
||||
|
||||
const importLoop = await buildImportLoopProfile({ entrypoint: "dist/index.js", runs: 3 });
|
||||
await writeImportLoopProfile(importLoop);
|
||||
|
||||
const runtimeProfile = await buildRuntimeProfile({
|
||||
commands: [{ id: "node-boot", label: "Node boot", category: "baseline", args: ["-e", "0"] }],
|
||||
});
|
||||
await writeRuntimeProfile(runtimeProfile);
|
||||
|
||||
const runtimeCapture = await buildRuntimeCaptureReport({ report, rootDir: process.cwd() });
|
||||
await writeRuntimeCaptureReport(runtimeCapture);
|
||||
|
||||
const refDiff = await buildRefDiff({ baseReport, headReport });
|
||||
await writeRefDiff(refDiff);
|
||||
|
||||
const profileDiff = await buildProfileDiff({ current, baseline, policy });
|
||||
await writeProfileDiff(profileDiff);
|
||||
```
|
||||
|
||||
## Scope
|
||||
|
||||
Default inspection is offline and credential-free. It reads manifests, package
|
||||
|
||||
@ -55,8 +55,9 @@ npm trust github @openclaw/plugin-inspector --repo openclaw/plugin-inspector --f
|
||||
npm run release:local
|
||||
```
|
||||
|
||||
This runs tests, `npm pack --dry-run`, and `npm publish --dry-run --access
|
||||
public`.
|
||||
This runs tests and `npm pack --dry-run`. Once a version has been published,
|
||||
`npm publish --dry-run` rejects that same version, so the real publish check is
|
||||
the tag workflow.
|
||||
|
||||
## Publish
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
"./advanced": "./src/advanced.js",
|
||||
"./capture-api": "./src/capture-api.js",
|
||||
"./ci-policy": "./src/ci-policy.js",
|
||||
"./cold-import-readiness": "./src/cold-import-readiness.js",
|
||||
@ -45,7 +46,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"scripts": {
|
||||
"check": "npm test && npm pack --dry-run && npm publish --dry-run --access public",
|
||||
"check": "npm test && npm pack --dry-run",
|
||||
"release:local": "npm run check",
|
||||
"test": "node --test test/*.test.js"
|
||||
},
|
||||
|
||||
186
src/advanced.js
Normal file
186
src/advanced.js
Normal file
@ -0,0 +1,186 @@
|
||||
export {
|
||||
escapeMarkdownTableCell,
|
||||
renderArtifactContent,
|
||||
renderMarkdownTable,
|
||||
renderPaddedMarkdownTable,
|
||||
writeArtifacts,
|
||||
writeJsonMarkdownArtifacts,
|
||||
} from "./artifacts.js";
|
||||
export {
|
||||
normalizeRepoPath,
|
||||
posixJoin,
|
||||
resolveFromRoot,
|
||||
resolveRequiredFromRoot,
|
||||
slugForArtifact,
|
||||
toRepoPath,
|
||||
} from "./path-utils.js";
|
||||
export { readJsonFile, readOptionalJsonFile } from "./json-file.js";
|
||||
export { assertRunCount, percentile } from "./stats.js";
|
||||
export { createCaptureApi } from "./capture-api.js";
|
||||
export {
|
||||
buildCiPolicyReport,
|
||||
defaultCiPolicyReportOptions,
|
||||
renderCiPolicyMarkdown,
|
||||
validateCiPolicy,
|
||||
validateCiPolicyReport,
|
||||
writeCiPolicyReport,
|
||||
} from "./ci-policy.js";
|
||||
export {
|
||||
buildCiSummary,
|
||||
defaultCiReportPaths,
|
||||
deriveCiStatus,
|
||||
readCiReports,
|
||||
renderCiSummaryMarkdown,
|
||||
writeCiSummary,
|
||||
} from "./ci-summary.js";
|
||||
export {
|
||||
buildContractProbes,
|
||||
contractProbeRules,
|
||||
probePriority,
|
||||
} from "./contract-probes.js";
|
||||
export {
|
||||
buildContractCapture,
|
||||
defaultHookAssertions,
|
||||
defaultHookContexts,
|
||||
defaultHookEvents,
|
||||
defaultRegistrationArguments,
|
||||
defaultRegistrationAssertions,
|
||||
renderContractCaptureMarkdown,
|
||||
validateContractCapture,
|
||||
writeContractCapture,
|
||||
} from "./contract-capture.js";
|
||||
export {
|
||||
renderCompatibilityIssuesReport,
|
||||
renderCompatibilityMarkdownReport,
|
||||
} from "./compatibility-report.js";
|
||||
export {
|
||||
knownIssueClasses,
|
||||
validateContractCoverage,
|
||||
} from "./contract-coverage.js";
|
||||
export {
|
||||
buildColdImportReadiness,
|
||||
renderColdImportReadinessMarkdown,
|
||||
validateColdImportReadiness,
|
||||
writeColdImportReadiness,
|
||||
} from "./cold-import-readiness.js";
|
||||
export {
|
||||
buildIssues,
|
||||
classifyIssueFinding,
|
||||
deprecatedCompatRecords,
|
||||
issueId,
|
||||
issueMetadata,
|
||||
issueMetadataByCode,
|
||||
knownIssueCodes,
|
||||
summarizeIssueClasses,
|
||||
} from "./issues.js";
|
||||
export {
|
||||
buildExecutionResultsReport,
|
||||
defaultExecutionResultsOptions,
|
||||
renderExecutionResultsMarkdown,
|
||||
writeExecutionResultsReport,
|
||||
} from "./execution-results.js";
|
||||
export {
|
||||
buildCompatibilityFixtureReport,
|
||||
classifyCompatibilityFixture,
|
||||
classifyPackageContracts,
|
||||
classifyTargetOpenClawCoverage,
|
||||
readPackageSummaries,
|
||||
readPluginManifests,
|
||||
summarizePackage,
|
||||
} from "./fixture-summary.js";
|
||||
export {
|
||||
buildImportLoopProfile,
|
||||
defaultImportLoopProfileOptions,
|
||||
renderImportLoopProfileMarkdown,
|
||||
validateImportLoopProfile,
|
||||
writeImportLoopProfile,
|
||||
} from "./import-loop-profile.js";
|
||||
export {
|
||||
defaultOpenClawCheckoutPaths,
|
||||
openClawTargetPathCandidates,
|
||||
parseCompatRecordEntries,
|
||||
parseExportedStringArray,
|
||||
parsePluginSdkExports,
|
||||
parseTypeFields,
|
||||
readOpenClawTargetSurface,
|
||||
} from "./openclaw-target.js";
|
||||
export {
|
||||
captureEntrypoint,
|
||||
captureEntrypointWithMockSdk,
|
||||
inspectCompatibilityFixtureSet,
|
||||
inspectFixtureSet,
|
||||
inspectPlugin,
|
||||
inspectSourceText,
|
||||
} from "./inspector.js";
|
||||
export {
|
||||
defaultPluginRootConfigFiles,
|
||||
fixtureCheckoutPath,
|
||||
fixtureSourceRoot,
|
||||
loadInspectorConfig,
|
||||
loadPluginRootConfig,
|
||||
normalizeInspectorConfig,
|
||||
normalizePluginRootConfig,
|
||||
validateInspectorConfig,
|
||||
} from "./config.js";
|
||||
export {
|
||||
buildPlatformProbes,
|
||||
defaultPlatformTargets,
|
||||
renderPlatformProbesMarkdown,
|
||||
validatePlatformProbes,
|
||||
writePlatformProbes,
|
||||
} from "./platform-probes.js";
|
||||
export {
|
||||
buildProfileDiff,
|
||||
defaultProfileDiffOptions,
|
||||
renderProfileDiffMarkdown,
|
||||
validateProfileDiff,
|
||||
writeProfileDiff,
|
||||
} from "./profile-diff.js";
|
||||
export {
|
||||
buildRefDiff,
|
||||
defaultRefDiffDimensions,
|
||||
defaultRefDiffOptions,
|
||||
renderRefDiffMarkdown,
|
||||
validateRefDiff,
|
||||
writeRefDiff,
|
||||
} from "./ref-diff.js";
|
||||
export {
|
||||
buildCompatibilityReport,
|
||||
classifyCompatRecordCoverage,
|
||||
renderMarkdownReport,
|
||||
renderTextSummary,
|
||||
writeCompatibilityReport,
|
||||
writeReport,
|
||||
} from "./report.js";
|
||||
export {
|
||||
buildRuntimeProfile,
|
||||
defaultRuntimeProfileCommands,
|
||||
defaultRuntimeProfileOptions,
|
||||
renderRuntimeProfileMarkdown,
|
||||
validateRuntimeProfile,
|
||||
writeRuntimeProfile,
|
||||
} from "./runtime-profile.js";
|
||||
export {
|
||||
buildRuntimeCaptureReport,
|
||||
renderRuntimeCaptureMarkdown,
|
||||
writeRuntimeCaptureReport,
|
||||
} from "./runtime-capture-report.js";
|
||||
export { createMockSdkPackage } from "./sdk-mock.js";
|
||||
export {
|
||||
buildSyntheticProbePlan,
|
||||
defaultSyntheticHookContexts,
|
||||
defaultSyntheticHookEvents,
|
||||
defaultSyntheticRegistrationArguments,
|
||||
renderSyntheticProbeMarkdown,
|
||||
runCapturedSyntheticProbes,
|
||||
syntheticRegistrationExecutionProfiles,
|
||||
validateSyntheticProbePlan,
|
||||
writeSyntheticProbePlan,
|
||||
} from "./synthetic-probes.js";
|
||||
export {
|
||||
buildWorkspacePlan,
|
||||
defaultWorkspacePlanOptions,
|
||||
renderWorkspacePlanMarkdown,
|
||||
validateWorkspacePlan,
|
||||
writeWorkspacePlan,
|
||||
} from "./workspace-plan.js";
|
||||
85
src/api.js
Normal file
85
src/api.js
Normal file
@ -0,0 +1,85 @@
|
||||
import path from "node:path";
|
||||
import { createCaptureApi } from "./capture-api.js";
|
||||
import { loadInspectorConfig, loadPluginRootConfig } from "./config.js";
|
||||
import { captureEntrypoint } from "./inspector.js";
|
||||
import { renderTextSummary, writeCompatibilityReport } from "./report.js";
|
||||
import { buildRuntimeCaptureReport, writeRuntimeCaptureReport } from "./runtime-capture-report.js";
|
||||
import { inspectCompatibilityFixtureSet, inspectFixtureSet } from "./inspector.js";
|
||||
|
||||
export async function loadPluginConfig(options = {}) {
|
||||
if (options.config) {
|
||||
return options.config;
|
||||
}
|
||||
const cwd = options.pluginRoot ?? options.cwd;
|
||||
if (options.configPath) {
|
||||
return options.fixtureSet === true
|
||||
? loadInspectorConfig(options.configPath, { cwd })
|
||||
: loadPluginRootConfig(options.configPath, { cwd });
|
||||
}
|
||||
return loadPluginRootConfig(null, { cwd });
|
||||
}
|
||||
|
||||
export async function inspectPluginRoot(options = {}) {
|
||||
const config = await loadPluginConfig(options);
|
||||
return inspectCompatibilityFixtureSet(config, {
|
||||
generatedAt: options.generatedAt,
|
||||
openclawPath: options.openclawPath,
|
||||
targetOpenClaw: options.targetOpenClaw,
|
||||
});
|
||||
}
|
||||
|
||||
export async function inspectFixtureSetConfig(options = {}) {
|
||||
const config = options.config ?? (await loadInspectorConfig(options.configPath, { cwd: options.cwd }));
|
||||
return inspectFixtureSet(config, { generatedAt: options.generatedAt });
|
||||
}
|
||||
|
||||
export async function writePluginReports(report, options = {}) {
|
||||
return writeCompatibilityReport(report, {
|
||||
basename: options.basename,
|
||||
check: options.check,
|
||||
cwd: options.cwd ?? options.pluginRoot,
|
||||
issuesBasename: options.issuesBasename,
|
||||
outDir: options.outDir,
|
||||
});
|
||||
}
|
||||
|
||||
export async function runPluginCheck(options = {}) {
|
||||
const outDir = options.outDir ?? "reports";
|
||||
const report = await inspectPluginRoot(options);
|
||||
const paths = await writePluginReports(report, { ...options, outDir });
|
||||
const result = { report, paths };
|
||||
|
||||
if (options.capture === true) {
|
||||
if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
|
||||
throw new Error("runtime capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
|
||||
}
|
||||
const config = await loadPluginConfig(options);
|
||||
const runtimeCapture = await buildRuntimeCaptureReport({
|
||||
mockSdk: options.mockSdk ?? true,
|
||||
report,
|
||||
rootDir: config.rootDir,
|
||||
});
|
||||
const outputRoot = options.cwd ?? options.pluginRoot ?? process.cwd();
|
||||
const runtimeCapturePaths = await writeRuntimeCaptureReport(runtimeCapture, {
|
||||
jsonPath: path.resolve(outputRoot, outDir, "plugin-inspector-runtime-capture.json"),
|
||||
markdownPath: path.resolve(outputRoot, outDir, "plugin-inspector-runtime-capture.md"),
|
||||
});
|
||||
result.runtimeCapture = runtimeCapture;
|
||||
result.runtimeCapturePaths = runtimeCapturePaths;
|
||||
if (runtimeCapture.summary.failedCount > 0) {
|
||||
throw new Error(`plugin-inspector runtime capture failed for ${runtimeCapture.summary.failedCount} entrypoints`);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.failOnBreakages === true && report.status !== "pass") {
|
||||
throw new Error(`plugin-inspector found ${report.summary.breakageCount} breakages`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function capturePluginEntrypoint(entrypoint, options = {}) {
|
||||
return captureEntrypoint(entrypoint, options);
|
||||
}
|
||||
|
||||
export { createCaptureApi, renderTextSummary };
|
||||
29
src/cli.js
29
src/cli.js
@ -1,17 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
import {
|
||||
buildRuntimeCaptureReport,
|
||||
renderTextSummary,
|
||||
runPluginCheck,
|
||||
} from "./index.js";
|
||||
import {
|
||||
captureEntrypoint,
|
||||
inspectCompatibilityFixtureSet,
|
||||
inspectFixtureSet,
|
||||
loadInspectorConfig,
|
||||
loadPluginRootConfig,
|
||||
renderTextSummary,
|
||||
writeArtifacts,
|
||||
writeCompatibilityReport,
|
||||
writeReport,
|
||||
writeRuntimeCaptureReport,
|
||||
} from "./index.js";
|
||||
} from "./advanced.js";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0]?.startsWith("-") ? "check" : (args[0] ?? "check");
|
||||
@ -40,22 +38,7 @@ async function runCheck(commandArgs) {
|
||||
const openclawPath = commandArgs.includes("--no-openclaw") ? false : readFlag(commandArgs, "--openclaw");
|
||||
const json = commandArgs.includes("--json");
|
||||
const capture = commandArgs.includes("--capture");
|
||||
const config = configPath ? await loadInspectorConfig(configPath) : await loadPluginRootConfig();
|
||||
const report = await inspectCompatibilityFixtureSet(config, { openclawPath });
|
||||
await writeCompatibilityReport(report, { outDir });
|
||||
if (capture) {
|
||||
if (process.env.PLUGIN_INSPECTOR_EXECUTE_ISOLATED !== "1") {
|
||||
throw new Error("check --capture imports plugin code; rerun with PLUGIN_INSPECTOR_EXECUTE_ISOLATED=1 in an isolated workspace");
|
||||
}
|
||||
const captureReport = await buildRuntimeCaptureReport({ report, rootDir: config.rootDir, mockSdk: true });
|
||||
await writeRuntimeCaptureReport(captureReport, {
|
||||
jsonPath: `${outDir}/plugin-inspector-runtime-capture.json`,
|
||||
markdownPath: `${outDir}/plugin-inspector-runtime-capture.md`,
|
||||
});
|
||||
if (captureReport.summary.failedCount > 0) {
|
||||
throw new Error(`plugin-inspector runtime capture failed for ${captureReport.summary.failedCount} entrypoints`);
|
||||
}
|
||||
}
|
||||
const { report } = await runPluginCheck({ configPath, outDir, openclawPath, capture });
|
||||
|
||||
if (json) {
|
||||
console.log(JSON.stringify(report, null, 2));
|
||||
|
||||
192
src/index.js
192
src/index.js
@ -1,186 +1,10 @@
|
||||
export {
|
||||
escapeMarkdownTableCell,
|
||||
renderArtifactContent,
|
||||
renderMarkdownTable,
|
||||
renderPaddedMarkdownTable,
|
||||
writeArtifacts,
|
||||
writeJsonMarkdownArtifacts,
|
||||
} from "./artifacts.js";
|
||||
export {
|
||||
normalizeRepoPath,
|
||||
posixJoin,
|
||||
resolveFromRoot,
|
||||
resolveRequiredFromRoot,
|
||||
slugForArtifact,
|
||||
toRepoPath,
|
||||
} from "./path-utils.js";
|
||||
export { readJsonFile, readOptionalJsonFile } from "./json-file.js";
|
||||
export { assertRunCount, percentile } from "./stats.js";
|
||||
export { createCaptureApi } from "./capture-api.js";
|
||||
export {
|
||||
buildCiPolicyReport,
|
||||
defaultCiPolicyReportOptions,
|
||||
renderCiPolicyMarkdown,
|
||||
validateCiPolicy,
|
||||
validateCiPolicyReport,
|
||||
writeCiPolicyReport,
|
||||
} from "./ci-policy.js";
|
||||
export {
|
||||
buildCiSummary,
|
||||
defaultCiReportPaths,
|
||||
deriveCiStatus,
|
||||
readCiReports,
|
||||
renderCiSummaryMarkdown,
|
||||
writeCiSummary,
|
||||
} from "./ci-summary.js";
|
||||
export {
|
||||
buildContractProbes,
|
||||
contractProbeRules,
|
||||
probePriority,
|
||||
} from "./contract-probes.js";
|
||||
export {
|
||||
buildContractCapture,
|
||||
defaultHookAssertions,
|
||||
defaultHookContexts,
|
||||
defaultHookEvents,
|
||||
defaultRegistrationArguments,
|
||||
defaultRegistrationAssertions,
|
||||
renderContractCaptureMarkdown,
|
||||
validateContractCapture,
|
||||
writeContractCapture,
|
||||
} from "./contract-capture.js";
|
||||
export {
|
||||
renderCompatibilityIssuesReport,
|
||||
renderCompatibilityMarkdownReport,
|
||||
} from "./compatibility-report.js";
|
||||
export {
|
||||
knownIssueClasses,
|
||||
validateContractCoverage,
|
||||
} from "./contract-coverage.js";
|
||||
export {
|
||||
buildColdImportReadiness,
|
||||
renderColdImportReadinessMarkdown,
|
||||
validateColdImportReadiness,
|
||||
writeColdImportReadiness,
|
||||
} from "./cold-import-readiness.js";
|
||||
export {
|
||||
buildIssues,
|
||||
classifyIssueFinding,
|
||||
deprecatedCompatRecords,
|
||||
issueId,
|
||||
issueMetadata,
|
||||
issueMetadataByCode,
|
||||
knownIssueCodes,
|
||||
summarizeIssueClasses,
|
||||
} from "./issues.js";
|
||||
export {
|
||||
buildExecutionResultsReport,
|
||||
defaultExecutionResultsOptions,
|
||||
renderExecutionResultsMarkdown,
|
||||
writeExecutionResultsReport,
|
||||
} from "./execution-results.js";
|
||||
export {
|
||||
buildCompatibilityFixtureReport,
|
||||
classifyCompatibilityFixture,
|
||||
classifyPackageContracts,
|
||||
classifyTargetOpenClawCoverage,
|
||||
readPackageSummaries,
|
||||
readPluginManifests,
|
||||
summarizePackage,
|
||||
} from "./fixture-summary.js";
|
||||
export {
|
||||
buildImportLoopProfile,
|
||||
defaultImportLoopProfileOptions,
|
||||
renderImportLoopProfileMarkdown,
|
||||
validateImportLoopProfile,
|
||||
writeImportLoopProfile,
|
||||
} from "./import-loop-profile.js";
|
||||
export {
|
||||
defaultOpenClawCheckoutPaths,
|
||||
openClawTargetPathCandidates,
|
||||
parseCompatRecordEntries,
|
||||
parseExportedStringArray,
|
||||
parsePluginSdkExports,
|
||||
parseTypeFields,
|
||||
readOpenClawTargetSurface,
|
||||
} from "./openclaw-target.js";
|
||||
export {
|
||||
captureEntrypoint,
|
||||
captureEntrypointWithMockSdk,
|
||||
inspectCompatibilityFixtureSet,
|
||||
inspectFixtureSet,
|
||||
inspectPlugin,
|
||||
inspectSourceText,
|
||||
} from "./inspector.js";
|
||||
export {
|
||||
defaultPluginRootConfigFiles,
|
||||
fixtureCheckoutPath,
|
||||
fixtureSourceRoot,
|
||||
loadInspectorConfig,
|
||||
loadPluginRootConfig,
|
||||
normalizeInspectorConfig,
|
||||
normalizePluginRootConfig,
|
||||
validateInspectorConfig,
|
||||
} from "./config.js";
|
||||
export {
|
||||
buildPlatformProbes,
|
||||
defaultPlatformTargets,
|
||||
renderPlatformProbesMarkdown,
|
||||
validatePlatformProbes,
|
||||
writePlatformProbes,
|
||||
} from "./platform-probes.js";
|
||||
export {
|
||||
buildProfileDiff,
|
||||
defaultProfileDiffOptions,
|
||||
renderProfileDiffMarkdown,
|
||||
validateProfileDiff,
|
||||
writeProfileDiff,
|
||||
} from "./profile-diff.js";
|
||||
export {
|
||||
buildRefDiff,
|
||||
defaultRefDiffDimensions,
|
||||
defaultRefDiffOptions,
|
||||
renderRefDiffMarkdown,
|
||||
validateRefDiff,
|
||||
writeRefDiff,
|
||||
} from "./ref-diff.js";
|
||||
export {
|
||||
buildCompatibilityReport,
|
||||
classifyCompatRecordCoverage,
|
||||
renderMarkdownReport,
|
||||
capturePluginEntrypoint,
|
||||
createCaptureApi,
|
||||
inspectFixtureSetConfig,
|
||||
inspectPluginRoot,
|
||||
loadPluginConfig,
|
||||
renderTextSummary,
|
||||
writeCompatibilityReport,
|
||||
writeReport,
|
||||
} from "./report.js";
|
||||
export {
|
||||
buildRuntimeProfile,
|
||||
defaultRuntimeProfileCommands,
|
||||
defaultRuntimeProfileOptions,
|
||||
renderRuntimeProfileMarkdown,
|
||||
validateRuntimeProfile,
|
||||
writeRuntimeProfile,
|
||||
} from "./runtime-profile.js";
|
||||
export {
|
||||
buildRuntimeCaptureReport,
|
||||
renderRuntimeCaptureMarkdown,
|
||||
writeRuntimeCaptureReport,
|
||||
} from "./runtime-capture-report.js";
|
||||
export { createMockSdkPackage } from "./sdk-mock.js";
|
||||
export {
|
||||
buildSyntheticProbePlan,
|
||||
defaultSyntheticHookContexts,
|
||||
defaultSyntheticHookEvents,
|
||||
defaultSyntheticRegistrationArguments,
|
||||
renderSyntheticProbeMarkdown,
|
||||
runCapturedSyntheticProbes,
|
||||
syntheticRegistrationExecutionProfiles,
|
||||
validateSyntheticProbePlan,
|
||||
writeSyntheticProbePlan,
|
||||
} from "./synthetic-probes.js";
|
||||
export {
|
||||
buildWorkspacePlan,
|
||||
defaultWorkspacePlanOptions,
|
||||
renderWorkspacePlanMarkdown,
|
||||
validateWorkspacePlan,
|
||||
writeWorkspacePlan,
|
||||
} from "./workspace-plan.js";
|
||||
runPluginCheck,
|
||||
writePluginReports,
|
||||
} from "./api.js";
|
||||
|
||||
95
test/api.test.js
Normal file
95
test/api.test.js
Normal file
@ -0,0 +1,95 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { test } from "node:test";
|
||||
import {
|
||||
capturePluginEntrypoint,
|
||||
inspectFixtureSetConfig,
|
||||
inspectPluginRoot,
|
||||
loadPluginConfig,
|
||||
runPluginCheck,
|
||||
} from "../src/index.js";
|
||||
|
||||
test("public API runs the plugin-root check and writes reports", async () => {
|
||||
const pluginRoot = await createPluginRoot();
|
||||
|
||||
const config = await loadPluginConfig({ pluginRoot });
|
||||
assert.equal(config.fixtures[0].id, "weather");
|
||||
|
||||
const inspected = await inspectPluginRoot({ pluginRoot, openclawPath: false });
|
||||
assert.equal(inspected.status, "pass");
|
||||
assert.equal(inspected.targetOpenClaw.status, "disabled");
|
||||
|
||||
const { report, paths } = await runPluginCheck({ pluginRoot, outDir: "reports", openclawPath: false });
|
||||
const written = JSON.parse(await readFile(path.join(pluginRoot, "reports", "plugin-inspector-report.json"), "utf8"));
|
||||
|
||||
assert.equal(report.status, "pass");
|
||||
assert.equal(written.fixtures[0].id, "weather");
|
||||
assert.equal(paths.jsonPath, path.join(pluginRoot, "reports", "plugin-inspector-report.json"));
|
||||
});
|
||||
|
||||
test("public API keeps crabpot-style fixture configs behind an explicit helper", async () => {
|
||||
const report = await inspectFixtureSetConfig({ configPath: "test/fixtures/inspector.config.json" });
|
||||
|
||||
assert.equal(report.status, "pass");
|
||||
assert.equal(report.summary.fixtureCount, 1);
|
||||
});
|
||||
|
||||
test("public API exposes capture through an explicit entrypoint helper", async () => {
|
||||
const dir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-api-capture-"));
|
||||
const entrypoint = path.join(dir, "fixture.mjs");
|
||||
await writeFile(
|
||||
entrypoint,
|
||||
[
|
||||
"export function register(api) {",
|
||||
" api.on('before_tool_call', () => undefined);",
|
||||
" api.registerTool({ name: 'fixture_tool', inputSchema: { type: 'object' }, run() {} });",
|
||||
"}",
|
||||
].join("\n"),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const result = await capturePluginEntrypoint(entrypoint, {
|
||||
apiOptions: { knownRegistrars: ["registerTool"] },
|
||||
});
|
||||
|
||||
assert.equal(result.status, "captured");
|
||||
assert.deepEqual(
|
||||
result.captured.map((item) => `${item.kind}:${item.name}`),
|
||||
["hook:before_tool_call", "registration:registerTool"],
|
||||
);
|
||||
});
|
||||
|
||||
async function createPluginRoot() {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-api-root-"));
|
||||
await mkdir(path.join(rootDir, "src"), { recursive: true });
|
||||
await writeFile(
|
||||
path.join(rootDir, "package.json"),
|
||||
`${JSON.stringify(
|
||||
{
|
||||
name: "@example/openclaw-weather",
|
||||
version: "1.0.0",
|
||||
type: "module",
|
||||
openclaw: {
|
||||
extensions: ["src/index.js"],
|
||||
compat: { pluginApi: "^1.0.0" },
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
await writeFile(
|
||||
path.join(rootDir, "openclaw.plugin.json"),
|
||||
`${JSON.stringify({ id: "weather", name: "Weather", version: "1.0.0", contracts: { tools: {} } }, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
await writeFile(
|
||||
path.join(rootDir, "src", "index.js"),
|
||||
'import { definePluginEntry } from "openclaw/plugin-sdk";\nexport default definePluginEntry((api) => api.registerTool({ name: "weather" }));\n',
|
||||
"utf8",
|
||||
);
|
||||
return rootDir;
|
||||
}
|
||||
@ -8,7 +8,7 @@ import {
|
||||
renderCiPolicyMarkdown,
|
||||
validateCiPolicyReport,
|
||||
writeCiPolicyReport,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
const policy = {
|
||||
version: 1,
|
||||
|
||||
@ -3,7 +3,7 @@ import { mkdtemp, readFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { test } from "node:test";
|
||||
import { buildCiSummary, deriveCiStatus, renderCiSummaryMarkdown, writeCiSummary } from "../src/index.js";
|
||||
import { buildCiSummary, deriveCiStatus, renderCiSummaryMarkdown, writeCiSummary } from "../src/advanced.js";
|
||||
|
||||
test("ci summary rolls up compatibility, policy, ref diff, and profile findings", async () => {
|
||||
const summary = await buildCiSummary({
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
buildColdImportReadiness,
|
||||
renderColdImportReadinessMarkdown,
|
||||
validateColdImportReadiness,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("cold import readiness classifies entrypoint blockers", async (t) => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-readiness-"));
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
buildContractCapture,
|
||||
renderContractCaptureMarkdown,
|
||||
validateContractCapture,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("contract capture turns compatibility reports into executable inventory", () => {
|
||||
const capture = buildContractCapture({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { buildContractProbes, contractProbeRules, probePriority } from "../src/index.js";
|
||||
import { buildContractProbes, contractProbeRules, probePriority } from "../src/advanced.js";
|
||||
|
||||
test("contract probes map issue findings to executable backlog rows", () => {
|
||||
const probes = buildContractProbes({
|
||||
|
||||
@ -3,7 +3,7 @@ import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { test } from "node:test";
|
||||
import { captureEntrypoint, inspectFixtureSet, inspectSourceText, loadInspectorConfig } from "../src/index.js";
|
||||
import { captureEntrypoint, inspectFixtureSet, inspectSourceText, loadInspectorConfig } from "../src/advanced.js";
|
||||
|
||||
test("source inspection records hook, registrar, and SDK import evidence", () => {
|
||||
const inspection = inspectSourceText(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { buildIssues, classifyIssueFinding, issueId, knownIssueCodes, summarizeIssueClasses } from "../src/index.js";
|
||||
import { buildIssues, classifyIssueFinding, issueId, knownIssueCodes, summarizeIssueClasses } from "../src/advanced.js";
|
||||
|
||||
test("issue ids are stable fingerprints", () => {
|
||||
const finding = {
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
parsePluginSdkExports,
|
||||
parseTypeFields,
|
||||
readOpenClawTargetSurface,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("OpenClaw target parser reads public target surface facts", async (t) => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-openclaw-target-"));
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
buildPlatformProbes,
|
||||
renderPlatformProbesMarkdown,
|
||||
validatePlatformProbes,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("platform probes classify loader and shell portability risks", () => {
|
||||
const report = buildPlatformProbes({
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
defaultProfileDiffOptions,
|
||||
renderProfileDiffMarkdown,
|
||||
validateProfileDiff,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
const policy = {
|
||||
thresholds: {
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
renderMarkdownTable,
|
||||
writeArtifacts,
|
||||
writeReport,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("markdown report includes summary and inventory", async () => {
|
||||
const config = await loadInspectorConfig("test/fixtures/inspector.config.json");
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
inspectCompatibilityFixtureSet,
|
||||
loadPluginRootConfig,
|
||||
writeRuntimeCaptureReport,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("runtime capture report imports plugin entrypoints with mocked SDK", async () => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-runtime-capture-"));
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
renderSyntheticProbeMarkdown,
|
||||
runCapturedSyntheticProbes,
|
||||
validateSyntheticProbePlan,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("synthetic probe plan maps capture inventory to executable probes", () => {
|
||||
const plan = buildSyntheticProbePlan({
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
buildWorkspacePlan,
|
||||
renderWorkspacePlanMarkdown,
|
||||
validateWorkspacePlan,
|
||||
} from "../src/index.js";
|
||||
} from "../src/advanced.js";
|
||||
|
||||
test("workspace plan maps blocked entrypoints to opt-in install/build/capture steps", async (t) => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-workspace-"));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user