npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@webpieces/webpieces-tooling

v0.4.979

Published

Complete webpieces tooling installation and the combined OpenClaw hook adapter.

Readme

@webpieces/webpieces-tooling

Install the complete toolchain through this umbrella package. Its workspace dependencies carry every published tooling package and its public bins, including wp-ai-rules-hook and wp-ai-guards-hook.

For a published release, declare @webpieces/webpieces-tooling as the single tooling dependency. Existing consumers should replace their former Nx umbrella declaration with this package when adopting the release. Keep registering @webpieces/nx-webpieces-rules in nx.json; that package implements the inference plugin and executors.

OpenClaw uses @webpieces/webpieces-tooling/openclaw-plugin and the packaged openclaw.plugin.json. Its single write/edit handler composes source rules, workflow guards, and source extensions in their original order.

This package owns packaging and composition smoke checks. Feature suites remain in ai-hook-rules, agent-workflow-rules, pr-gate, and the Nx implementation package.

The repository itself is validated with its previously published catalog release. Adding this source package does not upgrade that installed toolchain or its committed dispatcher.

The ordinary test target runs the small aggregation and OpenClaw checks. Run pnpm nx run webpieces-tooling:release-test when changing scripts/publish-packages.sh; it exercises the release retry loop in a fake registry workspace and is kept separate from source-rule edit workloads.

Repo-local rules

A repository can add rules of its own beside webpieces' built-in ones. A local rule is one TypeScript class. webpieces runs it in BOTH places, with no setting choosing between them: the Write/Edit source guard refuses the edit as it is written, and wp-build / the PR gate (validate-code) checks the committed diff. A repository that does not want the write-time check turns the source guard off with its existing switches. The two runners parse the same whole-file text with the same SourceSyntax, so they report the same sites at the same lines.

A rule decides from the file's syntax only. The guard sees one proposed file and no compiler program, so a rule that needs type information cannot give the same verdict in both places.

1. Write the rule. Import everything from @webpieces/webpieces-tooling/local-rules, including ts. Walk the parse with that ts, never a typescript of your own, because node kinds differ between TypeScript releases.

// webpieces-rules/no-banned-console.ts
import { ConfigObject, FieldDef, LocalRule, LocalRuleConfig, LocalRuleFile, LocalRuleFinding, Option, ts }
    from '@webpieces/webpieces-tooling/local-rules';

export class NoBannedConsoleConfig extends LocalRuleConfig {
    methods!: string[];
}

export class NoBannedConsoleRule extends LocalRule<NoBannedConsoleConfig> {
    readonly id = 'no-banned-console';
    readonly description = 'Production code must not call the banned console methods.';
    readonly files = ['**/*.ts'];
    readonly cures = [new Option('Throw a structured error, or log through the repo logger.', true)];
    readonly settings = { methods: FieldDef.nonEmptyStrings() };
    readonly seed = Object.assign(new ConfigObject(), { mode: 'NEW_AND_MODIFIED_CODE', methods: ['log'] });

    check(file: LocalRuleFile, config: NoBannedConsoleConfig): readonly LocalRuleFinding[] {
        const findings: LocalRuleFinding[] = [];
        const visit = (node: ts.Node): void => {
            if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)
                && node.expression.expression.getText() === 'console'
                && config.methods.includes(node.expression.name.text)) {
                findings.push(new LocalRuleFinding(file.lineOf(node), file.endLineOf(node),
                    `console.${node.expression.name.text}() is banned here.`));
            }
            ts.forEachChild(node, visit);
        };
        visit(file.source);
        return findings;
    }
}

2. Make it a pack. One module declares the pack and implements both runners:

// webpieces-rules/local-rules.ts
import { LocalRulePack } from '@webpieces/webpieces-tooling/local-rules';
import { NoBannedConsoleRule } from './no-banned-console';

const pack = new LocalRulePack('local-rules', __filename, [new NoBannedConsoleRule()]);
export const rulePackManifest = pack.rulePackManifest;
export const sourceRuleRuntime = pack.sourceRuleRuntime;
export const buildRuleRuntime = pack.buildRuleRuntime;
export const buildDebugRuntime = pack.buildDebugRuntime;

The fourth export is the one-rule debug run (below); without it wp-validate-code --rule=<id> refuses the pack's rules.

3. Register it in webpieces.config.json, beside the packs you already declare, with its own owner file:

{ "package": "./webpieces-rules/local-rules.ts", "config": ".webpieces-config/rules/local.json" }

Two things trip the first registration (both measured dogfooding this in webpieces-ts, #1320):

  • The pack lives outside every nx project, so a repo running validate-ts-in-src refuses to create it until its folder is listed in that rule's excludePaths (e.g. "webpieces-rules/**").
  • A declared owner file must be tracked by git. The PR gate and CI (wp-ci) refuse an untracked or ignored one — the guard hooks do not check it, since it is a commit-time invariant (#1355). Create the owner file, then stage it: git add -- <owner file>, or pnpm wp-migrate-dirs --stage, which stages the declaration and every owner file without reformatting the ones it does not change.

The .ts module is transpiled in memory when it loads, so there is no build step. The next tool call refuses the missing owner entry and prints the rule's seed to paste:

{
    "no-banned-console": {
        "mode": "NEW_AND_MODIFIED_CODE",
        "methods": ["log"],
        "turnOffRuleUntilEpoch": 0,
        "turnOffRuleWhileOnBranch": null
    }
}

Nothing has a default. You must state mode and every setting the rule declares. mode takes the values the built-in diff rules take: OFF, NEW_AND_MODIFIED_CODE (only findings on changed lines), NEW_AND_MODIFIED_FILES, MODIFIED_PROJECTS and RUN_EVERY_TIME. The framework applies the rest in both runners: turnOffRuleUntilEpoch, turnOffRuleWhileOnBranch, the optional excludePaths and reason, and the per-site escape // webpieces-disable no-banned-console -- <reason of at least 20 characters> on the reported line or the line above it. A disable with no reason does not exempt the site. Rule ids must be kebab-case and must not collide with any other pack's.

Count what is left with the debug run (#1330), exactly as for a built-in code rule and with no config edit:

pnpm exec wp-validate-code --rule=no-banned-console --mode=RUN_EVERY_TIME
pnpm exec wp-validate-code --rule=no-banned-console --mode=RUN_EVERY_TIME --projects=my-app,my-lib

It runs only that rule, through the same build policy the gate runs, so per-site disables, the repo's excludePaths and the rule's own apply unchanged. It ignores the two escape hatches for that run, prints the rule's own report and then one site count per project, writes nothing, and exits non-zero while any site remains. RUN_EVERY_TIME judges every file in the repo and never consults the diff. An unknown --rule is refused with the list of rules that accept a debug run, local ones included.