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

@shiplightai/sdk

v0.1.4

Published

Shiplight SDK with pluggable custom actions

Readme

@shiplightai/sdk

A companion SDK for Playwright that makes your tests resilient to UI changes like dynamic IDs, layout rearrangements, and styling updates.

Installation

npm install @shiplightai/sdk playwright

Quick Start

import { chromium } from 'playwright';
import { createAgent, configureSdk } from '@shiplightai/sdk';

// Configure SDK with API key (call once at startup)
configureSdk({
  env: { GOOGLE_API_KEY: process.env.GOOGLE_API_KEY! },
  // Or for Claude: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! }
});

// Create an agent
const agent = createAgent({
  model: 'gemini-2.5-pro',
});

// Use with Playwright
const browser = await chromium.launch();
const page = await browser.newPage();

// Login using the Sauce Labs demo site (public test site)
await agent.login(page, {
  url: 'https://www.saucedemo.com/',
  username: 'standard_user',
  password: 'secret_sauce',
});

// Verify login succeeded
await agent.assert(page, 'Products page is visible');

// Extract data from the page
await agent.extract(page, 'the first product name', 'productName');
console.log('First product:', agent.getVariable('productName'));

await browser.close();

Custom Actions

Extend the agent with custom actions for your specific use case:

import { createAgent, z } from '@shiplightai/sdk';

const agent = createAgent({ model: 'gemini-2.5-pro' });

// Register a custom action
agent.registerAction({
  name: 'extract_email_code',
  description: 'Extract verification code from email inbox',
  schema: z.object({
    email_address: z.string().describe('The email address to check'),
    code_type: z.enum(['verification', 'reset']).describe('Type of code'),
  }),
  async execute(args, ctx) {
    // Your custom logic here
    const code = await myEmailService.getCode(args.email_address, args.code_type);

    // Store the result for later use
    ctx.variableStore.set('verification_code', code);

    return { success: true, message: `Found code: ${code}` };
  },
});

// The agent will automatically use your action when needed
await agent.act(page, 'Get the verification code from email');
await agent.act(page, 'Enter {{ verification_code }} in the input field');

API Reference

createAgent(options)

Create a new agent instance.

const agent = createAgent({
  // Required: LLM model to use
  model: 'gemini-2.5-pro',

  // Optional: Initial variables
  variables: { username: '[email protected]' },

  // Optional: Keys to mark as sensitive (masked in logs)
  sensitiveKeys: ['password', 'apiKey'],

  // Optional: Directory for test data files
  testDataDir: './test-data',

  // Optional: Directory for downloads
  downloadDir: './downloads',
});

Supported Models

| Provider | Model | Notes | |----------|-------|-------| | Google | gemini-2.5-pro | Recommended, requires GOOGLE_API_KEY | | Google | gemini-3-pro-preview | More powerful, higher cost | | Anthropic | claude-haiku-4-5 | Fast and affordable, requires ANTHROPIC_API_KEY | | Anthropic | claude-sonnet-4-5 | Balanced speed and capability | | Anthropic | claude-opus-4-5 | Most capable | | OpenAI | computer-use-preview | Optional, for vision operations (drag and drop) |

agent.registerAction(action)

Register a custom action.

agent.registerAction({
  // Unique action name (snake_case recommended)
  name: 'my_action',

  // Description for the agent
  description: 'What this action does and when to use it',

  // Zod schema for parameters
  schema: z.object({
    param1: z.string().describe('Description of the parameter'),
    param2: z.number().optional(),
  }),

  // Execute function
  async execute(args, ctx) {
    // args: validated parameters
    // ctx.page: Playwright page
    // ctx.variableStore: access to variables

    return { success: true, message: 'Optional status message' };
  },
});

agent.act(page, instruction)

Perform a single action on the page.

await agent.act(page, 'Click the login button');
await agent.act(page, 'Fill the email field with [email protected]');
await agent.act(page, 'Select "Express" from shipping dropdown');

agent.run(page, instruction, options?)

Run a multi-step instruction until the goal is achieved.

await agent.run(page, 'Complete the checkout process');
await agent.run(page, 'Fill out the entire registration form');
await agent.run(page, 'Add 3 items to cart', { maxSteps: 10 });

agent.assert(page, statement)

Assert a condition (throws on failure).

await agent.assert(page, 'Login button is visible');
await agent.assert(page, 'Cart contains 3 items');

agent.evaluate(page, statement)

Evaluate a condition (returns boolean, doesn't throw).

const isLoggedIn = await agent.evaluate(page, 'User is logged in');
if (!isLoggedIn) {
  await agent.run(page, 'Click the login button');
}

agent.extract(page, description, variableName)

Extract data from the page and store in a variable.

await agent.extract(page, 'the order total', 'orderTotal');
await agent.run(page, 'Verify {{ orderTotal }} is displayed on receipt');

agent.waitUntil(page, condition, timeoutSeconds?)

Wait until a condition becomes true.

await agent.waitUntil(page, 'Loading spinner is no longer visible');

const appeared = await agent.waitUntil(page, 'Table shows at least 5 rows', 30);
if (!appeared) {
  throw new Error('Data did not load in time');
}

Custom Action Context

The execute function receives a context object:

interface IActionExecutionContext {
  // Playwright page instance
  page: Page;

  // Variable store for reading/writing variables
  variableStore: VariableStore;
}

Using Variables

async execute(args, ctx) {
  // Read a variable
  const email = ctx.variableStore.get('email');

  // Set a variable
  ctx.variableStore.set('result', 'some value');

  // Set a sensitive variable (masked in logs)
  ctx.variableStore.set('token', secretToken, true);

  return { success: true };
}

SDK Configuration

Configure SDK-wide settings before creating agents:

import { configureSdk, getSdkConfig, LogLevel } from '@shiplightai/sdk';

configureSdk({
  // Log level: DEBUG, INFO, WARN, ERROR
  logLevel: LogLevel.INFO,

  // Enable detailed agent logging
  debugAgent: false,

  // Environment variables (API keys)
  env: {
    // At least one model provider key is required
    GOOGLE_API_KEY: 'your-google-api-key',       // for Gemini models
    // ANTHROPIC_API_KEY: 'your-anthropic-key',   // for Claude models
    // OPENAI_API_KEY: 'sk-...',                  // for vision operations
  },

  // Optional: paths for logs and results
  agentLogPath: './logs/agent.log',
  testResultsJsonPath: './results.json',
});

// Read current config
const config = getSdkConfig();

API Keys

API keys must be passed via configureSdk({ env }) — the SDK does not read process.env directly.

| Key | Required | Description | |-----|----------|-------------| | GOOGLE_API_KEY | Yes* | Google AI API key for Gemini models | | ANTHROPIC_API_KEY | Yes* | Anthropic API key for Claude models | | OPENAI_API_KEY | No | OpenAI API key (for vision operations) |

*At least one model provider key is required.

License

MIT