Compare commits

...

2 Commits

Author SHA1 Message Date
Vincent Koc
242fb3f16f
fix: fetch plugin inspector smoke source 2026-04-26 11:14:05 -07:00
Vincent Koc
02dde1afe7
feat: add plugin inspector smoke 2026-04-26 11:08:37 -07:00
6 changed files with 117 additions and 4 deletions

View File

@ -35,6 +35,7 @@ jobs:
- run: node scripts/sync-fixtures.mjs --check
- run: node scripts/run-contract-smoke.mjs --strict --openclaw ./openclaw
- run: node scripts/inspect-fixtures.mjs --check
- run: npm run plugin-inspector:smoke
- run: node scripts/generate-report.mjs --check --openclaw ./openclaw
- run: node scripts/capture-contracts.mjs --check --openclaw ./openclaw
- run: node scripts/synthetic-probes.mjs --check --openclaw ./openclaw
@ -85,6 +86,7 @@ jobs:
- run: npm test
- run: node scripts/sync-fixtures.mjs --check
- run: node scripts/inspect-fixtures.mjs --check
- run: npm run plugin-inspector:smoke
- run: node scripts/generate-report.mjs --check --openclaw ./openclaw
- run: node scripts/cold-import-readiness.mjs --check --openclaw ./openclaw
- run: node scripts/workspace-plan.mjs --check --openclaw ./openclaw

View File

@ -1,7 +1,8 @@
# Inspector Plan
Crabpot is the fixture base. The reusable inspector should become a separate
package later.
Crabpot is the fixture base. The reusable inspector now lives in the separate
`openclaw/plugin-inspector` repo and will replace the local prototype scripts in
phases.
## Layers
@ -85,8 +86,20 @@ Generated reports live in `reports/`:
- `crabpot-workspace-plan.md`
- `crabpot-workspace-plan.json`
Later, replace the static scanner with the packaged inspector while keeping
`crabpot.config.json` as the fixture manifest.
The first packaged-inspector smoke runs through:
```bash
npm run plugin-inspector:smoke
```
The smoke writes ignored artifacts under `.crabpot/plugin-inspector-smoke/`.
For local development it uses a sibling `../plugin-inspector` checkout when one
exists. In CI or standalone checkouts it falls back to the pinned GitHub package
source checkout. This intentionally avoids npm publishing until the package
boundary is reviewed.
Migration path: replace the local static scanner with the packaged inspector
while keeping `crabpot.config.json` as the fixture manifest.
## Compatibility issue workflow

View File

@ -108,6 +108,7 @@ records, and manifest fields.
Run the quality gate directly when changing classifiers:
```bash
npm run plugin-inspector:smoke
npm run contract:coverage
npm run contract:capture -- --check
npm run contract:synthetic -- --check

View File

@ -23,6 +23,7 @@
"fixtures:inspect": "node scripts/inspect-fixtures.mjs",
"fixtures:sync": "node scripts/sync-fixtures.mjs --materialize",
"import:profile": "node scripts/import-loop-profile.mjs",
"plugin-inspector:smoke": "node scripts/run-plugin-inspector-smoke.mjs --check",
"profile": "node scripts/profile-contract-runtime.mjs",
"profile:compare": "node scripts/compare-runtime-profile.mjs",
"platform:probes": "node scripts/platform-probes.mjs",

View File

@ -0,0 +1,94 @@
#!/usr/bin/env node
import { spawnSync } from "node:child_process";
import { existsSync, rmSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const pluginInspectorRef = "7348aadd7897505bc433c61aa912d256b6f208a4";
const args = process.argv.slice(2);
const check = args.includes("--check");
const outIndex = args.indexOf("--out");
const outDir = outIndex === -1 ? ".crabpot/plugin-inspector-smoke" : args[outIndex + 1];
const configIndex = args.indexOf("--config");
const configPath = configIndex === -1 ? "crabpot.config.json" : args[configIndex + 1];
const command = check ? "ci" : "report";
const inspectorArgs = [command, "--config", configPath, "--out", outDir];
const invocation = resolveInspectorInvocation();
const result = spawnSync(invocation.command, [...invocation.args, ...inspectorArgs], {
cwd: repoRoot,
encoding: "utf8",
stdio: "inherit",
});
if (result.error) {
throw result.error;
}
process.exitCode = result.status ?? 1;
function resolveInspectorInvocation() {
if (process.env.CRABPOT_PLUGIN_INSPECTOR_BIN) {
return {
command: process.env.CRABPOT_PLUGIN_INSPECTOR_BIN,
args: [],
};
}
const siblingCli = path.resolve(repoRoot, "../plugin-inspector/src/cli.js");
if (existsSync(siblingCli)) {
return {
command: process.execPath,
args: [siblingCli],
};
}
const pinnedCli = ensurePinnedInspectorCheckout();
return {
command: process.execPath,
args: [pinnedCli],
};
}
function ensurePinnedInspectorCheckout() {
const checkoutDir = path.join(repoRoot, ".crabpot", "plugin-inspector", pluginInspectorRef);
const cliPath = path.join(checkoutDir, "src", "cli.js");
if (existsSync(cliPath) && readGitHead(checkoutDir) === pluginInspectorRef) {
return cliPath;
}
rmSync(checkoutDir, { force: true, recursive: true });
run("git", ["init", checkoutDir]);
run("git", ["-C", checkoutDir, "fetch", "--depth=1", "https://github.com/openclaw/plugin-inspector.git", pluginInspectorRef]);
run("git", ["-C", checkoutDir, "checkout", "--detach", "FETCH_HEAD"]);
if (readGitHead(checkoutDir) !== pluginInspectorRef) {
throw new Error(`plugin-inspector checkout did not resolve to ${pluginInspectorRef}`);
}
return cliPath;
}
function readGitHead(checkoutDir) {
const result = spawnSync("git", ["-C", checkoutDir, "rev-parse", "HEAD"], {
encoding: "utf8",
});
if (result.status !== 0) {
return null;
}
return result.stdout.trim();
}
function run(command, commandArgs) {
const result = spawnSync(command, commandArgs, {
cwd: repoRoot,
encoding: "utf8",
stdio: "inherit",
});
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
throw new Error(`${command} ${commandArgs.join(" ")} failed with exit code ${result.status}`);
}
}

View File

@ -49,6 +49,7 @@ test("default check workflow uploads policy and summary reports", async () => {
assert.match(workflow, /node scripts\/compare-runtime-profile\.mjs/);
assert.match(workflow, /node scripts\/platform-probes\.mjs/);
assert.match(workflow, /node scripts\/import-loop-profile\.mjs/);
assert.match(workflow, /npm run plugin-inspector:smoke/);
assert.match(workflow, /node scripts\/check-ci-policy\.mjs/);
assert.match(workflow, /node scripts\/write-ci-summary\.mjs/);
assert.match(workflow, /node scripts\/update-readme-summary\.mjs/);
@ -75,6 +76,7 @@ test("default check workflow runs OS and container static lanes", async () => {
assert.match(workflow, /os: \[ubuntu-latest, macos-latest, windows-latest\]/);
assert.match(workflow, /container-smoke:/);
assert.match(workflow, /image: node:22-bookworm/);
assert.match(workflow, /npm run plugin-inspector:smoke/);
assert.match(workflow, /crabpot-check-reports-\$\{\{ matrix\.os \}\}/);
});