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

@ofocus/sdk

v0.4.0

Published

OmniFocus SDK - Core library for interacting with OmniFocus

Readme

@ofocus/sdk

Core SDK for interacting with OmniFocus via AppleScript.

Installation

pnpm add @ofocus/sdk

Usage

import {
  addToInbox,
  queryTasks,
  queryProjects,
  completeTask,
  success,
  failure,
} from "@ofocus/sdk";

// Add a task to the inbox
const result = await addToInbox("Buy groceries", {
  note: "Milk, eggs, bread",
  due: "tomorrow 5pm",
  flag: true,
  tags: ["errands"],
});

if (result.success) {
  console.log("Created task:", result.data.id);
} else {
  console.error("Error:", result.error.message);
}

// Query tasks
const tasks = await queryTasks({
  flagged: true,
  available: true,
});

// Complete a task
await completeTask("task-id-here");

Querying Tasks

Use Filters First

Always prefer filtering to fetching everything. The SDK supports many filters:

// Get flagged tasks only
const flagged = await queryTasks({ flagged: true });

// Get tasks in a specific project
const projectTasks = await queryTasks({ project: "Project Name" });

// Get tasks with a specific tag
const tagged = await queryTasks({ tag: "urgent" });

// Get tasks due soon
const dueSoon = await queryTasks({ dueBefore: "2024-12-31" });

// Get available (actionable) tasks
const available = await queryTasks({ available: true });

// Combine filters
const urgentAvailable = await queryTasks({ flagged: true, available: true });

Inbox vs Project Tasks

queryTasks() returns both inbox tasks and project tasks:

  • Inbox tasks: projectId === null (not assigned to any project)
  • Project tasks: projectId is set
const result = await queryTasks({ flagged: true });
if (result.success) {
  const inboxTasks = result.data.items.filter((t) => t.projectId === null);
  const projectTasks = result.data.items.filter((t) => t.projectId !== null);
}

Pagination

All query functions return paginated results (default limit: 100 items):

// First page (default)
const page1 = await queryTasks({ flagged: true });

// Check if there are more results
if (page1.data.hasMore) {
  const page2 = await queryTasks({ flagged: true, offset: 100 });
}

// Smaller pages for efficiency
const smallPage = await queryTasks({ limit: 20, offset: 0 });

Result format:

interface PaginatedResult<T> {
  items: T[]; // The items for this page
  totalCount: number; // Total items matching the query (before pagination)
  returnedCount: number; // Items in this page
  hasMore: boolean; // Whether more items exist
  offset: number; // The offset used
  limit: number; // The limit used
}

Note: Only increase the limit beyond 100 when you specifically need all matching items. For most agent tasks, filters and pagination are more efficient.

API

Commands

  • addToInbox(title, options?) - Add a task to the OmniFocus inbox
  • queryTasks(options?) - Query tasks with optional filters
  • queryProjects(options?) - Query projects with optional filters
  • queryTags(options?) - Query tags with optional filters
  • queryFolders(options?) - Query folders with optional filters
  • completeTask(taskId) - Mark a task as complete
  • updateTask(taskId, options) - Update task properties
  • deleteTask(taskId) - Permanently delete a task
  • deleteProject(projectId) - Permanently delete a project
  • deleteTag(tagId) - Permanently delete a tag
  • deleteFolder(folderId) - Permanently delete a folder

Result Helpers

  • success(data) - Create a successful result
  • failure(error) - Create a failed result
  • failureMessage(message) - Create a failed result with a string message

Error Handling

  • ErrorCode - Enum of error codes for semantic error handling
  • createError(code, message, details?) - Create a structured error
  • parseAppleScriptError(rawError) - Parse AppleScript errors

Utilities

  • escapeAppleScript(str) - Escape strings for AppleScript
  • validateId(id, type) - Validate OmniFocus IDs
  • validateDateString(dateStr) - Validate date strings
  • validateTags(tags) - Validate tag names
  • validateProjectName(name) - Validate project names

License

MIT