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

@forgewisp/bundled-tools

v0.7.0

Published

Browser-effects tool catalog for AI agents — clipboard, geolocation, UUIDs, hashing, base64, QR codes, and more. Forgewisp-ready, safe by default.

Readme

@forgewisp/bundled-tools

GitHub stars GitHub repo npm version npm downloads CI license

Found Forgewisp useful? Star the repo on GitHub.

A catalog of browser-safe, ready-to-register FunctionDefinition tools for Forgewisp agents — time, UUIDs, safe math, hashing, base64, color conversion, QR-code generation, viewport/battery/localStorage/sessionStorage reads, clipboard, speech, downloads, vibration, Web Share, screen wake lock, geolocation, localStorage/sessionStorage writes, and destructive localStorage/sessionStorage clears.

@forgewisp/core lets you register your own functions as agent tools. This package ships a set of pre-built ones so you can give an agent real browser capabilities in one forEach. Every tool ships with a strict JSON Schema (additionalProperties: false, bounded strings/numbers, enum only for closed sets) and a safe handler that guards missing Web-Platform APIs and throws a clear Error on misuse (surfaced as a function_errored audit event). The only runtime dependency is @forgewisp/core — argument validation runs there.

The safe-math tool (evaluateMath) uses an internal shunting-yard evaluator with a closed grammar and an overflow check — no eval / Function — so it is safe to expose to LLM-generated input.

Install

pnpm add @forgewisp/bundled-tools @forgewisp/core
# or
npm install @forgewisp/bundled-tools @forgewisp/core

ESM, CommonJS, and full TypeScript definitions are shipped (dist/index.mjs, dist/index.cjs, dist/index.d.ts). Node.js ≥ 18.

Quick start

import { createAgent } from '@forgewisp/core';
import { BUNDLED_TOOLS } from '@forgewisp/bundled-tools';

const agent = createAgent({
  llmEndpoint: 'https://api.openai.com/v1/chat/completions',
  apiKey: process.env.OPENAI_API_KEY,
  model: 'gpt-4o',
  systemPrompt: 'You can read the time, do math, and save notes to localStorage.',
  // write/destructive tools require this — see "Risk tiers" below.
  onConfirmRequired: async (call) =>
    window.confirm(`${call.functionName}: ${JSON.stringify(call.args)}`),
});

// Register the whole catalog, or pick the ones you want (see "Catalog").
BUNDLED_TOOLS.forEach((def) => agent.registerFunction(def));

const result = await agent.run(
  'What time is it in Tokyo, and what is 17 * 23 + 4?',
);

Catalog

Tools are grouped by tier (readwritedestructive), matching the order of BUNDLED_TOOLS. Each is exported by name, with Args and Result types, e.g. import { getCurrentTime, type GetCurrentTimeResult }.

read

| Tool | Name | Description | | -------------------- | ------------------- | -------------------------------------------------------------------------- | | getCurrentTime | getCurrentTime | Current date/time; optionally in a given IANA timezone. | | generateUuid | generateUuid | A cryptographically-random UUID (v4) via crypto.randomUUID. | | evaluateMath | evaluateMath | Safe arithmetic (+ - * / % ^, parens, decimals, unary minus). No eval. | | hashText | hashText | SHA-256/384/512 (Web Crypto digest, hex digest). | | encodeBase64 | encodeBase64 | UTF-8 text → Base64 (unicode-safe). | | decodeBase64 | decodeBase64 | Base64 → UTF-8 text. Throws on invalid input. | | getViewportInfo | getViewportInfo | Viewport + document size, scroll position, device pixel ratio. | | getBatteryInfo | getBatteryInfo | Battery level + charging state (where the Battery API exists). | | convertColor | convertColor | Convert between hex / rgb / hsl; auto-detects the input format. | | generateQrCode | generateQrCode | Encode text/URL as a QR code → PNG data URL (offscreen <canvas>). | | listLocalStorageKeys | listLocalStorageKeys | All keys in this origin's localStorage. | | getLocalStorageItem | getLocalStorageItem | One localStorage value by key ({ exists: false } if absent). | | listSessionStorageKeys | listSessionStorageKeys | All keys in this tab's sessionStorage (per-tab; cleared on close). | | getSessionStorageItem | getSessionStorageItem | One sessionStorage value by key ({ exists: false } if absent). |

The catalog also includes seven agent planning tools — a job-tracking scratchpad persisted in localStorage under forgewisp.plans. They are read-tier by exception (agent-owned, bounded, schema-validated scratchpad the agent self-manages, so no onConfirmRequired prompts):

| Tool | Name | Description | | ---------------- | ---------------- | --------------------------------------------------------------------- | | listPlans | listPlans | Summaries of all plans (id, title, status, counts). | | getPlan | getPlan | One plan with its items. | | createPlan | createPlan | Create a plan with title/priority and initial items. | | addPlanItem | addPlanItem | Append an item to a plan. | | updatePlanItem | updatePlanItem | Update an item's text/status/priority. | | removePlanItem | removePlanItem | Remove an item from a plan. | | deletePlan | deletePlan | Delete a plan and its items. |

write

| Tool | Name | Description | | -------------------- | ------------------- | -------------------------------------------------------------------------- | | copyToClipboard | copyToClipboard | Write text to the system clipboard (navigator.clipboard). | | speakText | speakText | Speak text aloud (speechSynthesis), with optional BCP-47 language. | | downloadFile | downloadFile | Trigger a file download; rejects filenames with path separators. | | setLocalStorageItem | setLocalStorageItem | Write a key/value to localStorage. | | vibrateDevice | vibrateDevice | Vibrate the device (navigator.vibrate) with a pulse pattern. | | shareContent | shareContent | Open the native share sheet (navigator.share); cancellation is not an error. | | requestWakeLock | requestWakeLock | Acquire a screen wake lock (navigator.wakeLock); auto-releases on tab hide. | | setSessionStorageItem | setSessionStorageItem | Write a key/value to sessionStorage (per-tab; cleared on close). | | getGeolocation | getGeolocation | Request a GPS fix (navigator.geolocation); user-prompted by the browser. |

destructive

| Tool | Name | Description | | ---------------------- | --------------------- | ---------------------------------------- | | removeLocalStorageItem | removeLocalStorageItem | Delete a key from localStorage. | | clearLocalStorage | clearLocalStorage | Clear all keys from localStorage (high blast radius). | | removeSessionStorageItem | removeSessionStorageItem | Delete a key from sessionStorage. |

Register the whole catalog:

BUNDLED_TOOLS.forEach((def) => agent.registerFunction(def));

Or cherry-pick:

import { getCurrentTime, evaluateMath, setLocalStorageItem } from '@forgewisp/bundled-tools';

agent.registerFunction(getCurrentTime);
agent.registerFunction(evaluateMath);
agent.registerFunction(setLocalStorageItem);

Planning tools

The seven plan-management tools are also exported as a ready-to-register ToolSet named PLANNING_TOOLS (listPlans, getPlan, createPlan, addPlanItem, updatePlanItem, removePlanItem, deletePlan). Register them in one call with agent.registerToolSet (a method on the agent from @forgewisp/core):

import { PLANNING_TOOLS } from '@forgewisp/bundled-tools';

agent.registerToolSet(PLANNING_TOOLS);

These seven tools are members of BUNDLED_TOOLS, so registering the whole catalog (the Quick start above) registers them too — PLANNING_TOOLS is for consumers who want just the planning scratchpad. apps/planning-demo exercises them end-to-end.

Risk tiers

@forgewisp/bundled-tools respects the same risk-tier boundary as @forgewisp/core. Tier discipline is a security boundary here too:

  • read tools run immediately, no confirmation.
  • write / destructive tools require the consumer to configure onConfirmRequired. @forgewisp/core throws at registration time if a write/destructive tool is registered without it, so registering the whole BUNDLED_TOOLS catalog (which includes removeLocalStorageItem) will throw unless onConfirmRequired is set.

Confirmation UI must be rendered only from the schema-validated PendingCall.args — never from raw LLM output. The executor validates args against the JSON Schema before confirmation, so the args you get back are guaranteed well-formed.

Defining your own tool

The package re-exports defineTool, an identity helper that infers handler argument types from a TArgs shape:

import { defineTool } from '@forgewisp/bundled-tools';
import type { FunctionDefinition } from '@forgewisp/core';

export const myTool: FunctionDefinition<MyArgs> = defineTool({
  name: 'myTool',
  description: '...',
  riskTier: 'read',
  parameters: {
    type: 'object',
    properties: { /* ... */ },
    required: [],
    additionalProperties: false,
  },
  handler: (args) => {
    // `args` is typed as MyArgs — no cast needed.
    return result;
  },
});

The JSON Schema is hand-authored; defineTool does not derive it from the TS type (that would require a runtime schema builder, which this package does not depend on).

Tests

pnpm install
pnpm --filter @forgewisp/bundled-tools test   # vitest run

Each tool has a dedicated test file under tests/. The safe-math evaluator has its own eval-math.test.ts covering the closed grammar, precedence, and overflow guard.

License

MIT