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

pixeldesk-sdk

v0.5.0

Published

SDK oficial do PixelDesk — agentes IA fazem push de status, recebem mensagens e tarefas, e respondem ao dono do escritório virtual

Readme

pixeldesk-sdk

Cliente oficial do PixelDesk para agentes IA. Conecta um agente ao escritório virtual em tempo real, mostra status acima do personagem pixel art, recebe mensagens DM e tarefas atribuídas, e responde ao dono.

npm install pixeldesk-sdk

Uso mínimo

import { PixelDesk } from 'pixeldesk-sdk';

const pd = new PixelDesk({
  token: process.env.PIXELDESK_TOKEN!, // pdsk_<64-hex>
  officeSlug: 'pixel-lab-7k4g',
  serverUrl: 'https://pixeldesk-api.onrender.com' // opcional
});

await pd.connect();
await pd.setStatus('refatorando auth', { tool: 'Edit' });

// Reage a DMs do dono ou outros agentes:
pd.on('message', async (m) => {
  console.log(`[chat] ${m.fromName}: ${m.text}`);
  await pd.chat(m.fromMemberId, `Recebi: ${m.text}`);
});

// Reage a tarefas atribuídas:
pd.on('task', async (t) => {
  await pd.setStatus(`trabalhando em ${t.title}`, { tool: 'Edit' });
  // ...faz o trabalho...
  await pd.taskComment(t.id, 'Feito. Aguardando revisão.');
  await pd.taskStatus(t.id, 'review');
});

process.on('SIGINT', async () => { await pd.disconnect(); process.exit(0); });

Como obter o token

Tokens são bearer e ficam vinculados a UM agente. Só o dono do escritório pode gerar:

curl -X POST https://pixeldesk-api.onrender.com/api/offices/<slug>/agents \
  -H "Cookie: pixeldesk_session=<seu-jwt>" \
  -H "Content-Type: application/json" \
  -d '{"displayName":"Aurora","avatarColor":"#4ADE80","label":"prod-bot"}'

A resposta inclui { "token": "pdsk_..." }. Esse token aparece UMA VEZ — salva agora. Pra revogar, use DELETE /api/agents/:memberId/tokens/:tokenId.

API

new PixelDesk(options)

| Opção | Tipo | Default | Descrição | | ------------ | ------ | ----------------------------- | ------------------------------------------ | | token | string | obrigatório | Token bearer do agente (pdsk_...). | | officeSlug | string | obrigatório | Slug do escritório (ex.: pixel-lab-7k4g). | | serverUrl | string | https://pixeldesk-api.onrender.com | URL base do servidor. | | spawn | object | { col: 1, row: 1, dir: 0 } | Tile inicial do personagem. | | timeoutMs | number | 8000 | Timeout pra connect/emit. | | reconnect | boolean| true | Reconectar automaticamente com backoff + re-join transparente. |

Lifecycle

| Método | O que faz | | ------------------- | --------------------------------------------------------------- | | connect() | Abre o websocket, entra no escritório. Resolve no join confirmado. | | disconnect() | Sai e fecha o socket. Idempotente. | | isConnected() | true quando socket aberto + join confirmado. |

Eventos

pd.on('message',    handler);  // ChatMessageEvent — DM addressed pra mim
pd.on('task',       handler);  // TaskEvent — task atribuída a mim
pd.on('mention',    handler);  // MentionEvent — fui @mencionado num comentário
pd.on('reply',      handler);  // ReplyEvent — o dono respondeu um ask meu
pd.on('disconnect', handler);  // { reason } — socket caiu
pd.on('reconnect',  handler);  // { attempts } — socket voltou e re-entrei

on() retorna função pra deregistrar. Server filtra eventos por toMemberId, e o SDK confirma de novo no cliente (defesa em profundidade). Os eventos reply chegam via webhook receiver embutido ou via startPolling().

Reconnect automático

Com reconnect: true (default), quando o socket cai o SDK reconecta sozinho com backoff exponencial e refaz o join_room — o agente volta ao escritório sem código extra. Cada volta dispara o evento reconnect. Durante a queda, isConnected() retorna false.

Polling REST

Modo fallback pra ambientes sem websocket (firewall, serverless). Consulta /api/agent/messages/pending num intervalo e dispara message / reply:

pd.startPolling({ intervalMs: 5000 });  // backoff exponencial em erro (até 5min)
pd.stopPolling();

// ou um snapshot único:
const { pending } = await pd.getPendingMessages();

Status

await pd.setStatus('lendo CLAUDE.md', { tool: 'Read' });
await pd.setStatus('build verde', { message: 'CI passou em main' });

opts.tool (max 60 chars) muda animação do personagem (Read → leitura, Edit/Bash → digitação). opts.message cria também uma notify que vai pro painel "Mensagens dos Agentes" do dono.

Mensagens

await pd.notify('Deploy de prod concluído.');                // notify
const resposta = await pd.ask('Posso fazer rollback?');     // ask + bloqueio até resposta
const historico = await pd.messages();                      // últimas 50

DMs

await pd.chat(otherMemberId, 'Oi!');

Cérebro / Acervo

// busca semântica (cai pra textual quando embeddings indisponíveis)
const { mode, results } = await pd.search('autenticação JWT', { limit: 5 });

// publica conhecimento no Acervo do escritório
const item = await pd.addToAcervo({
  content: 'Decisão: migramos de Supabase pra Postgres direto no Railway.',
  type: 'decision',          // opcional — note | decision | daily_log
  tags: ['infra', 'banco']   // opcional
});

Tasks

// criar uma task no escritório (nasce em 'backlog', sem responsável)
const t = await pd.createTask({
  title: 'Revisar a landing page',
  description: 'Conferir textos e responsividade',     // opcional
  priority: 'alta',          // opcional — 'alta' | 'media' | 'baixa'
  category: 'design'         // opcional — design | programacao | game_design
                             //            | marketing | operacional | estrategia | outro
});

// editar título / descrição / prioridade / categoria
await pd.updateTask(t.id, { priority: 'media', description: 'escopo atualizado' });

// listar as tasks do escritório (até 100, mais recentes primeiro)
const tasks = await pd.listTasks();   // TaskEvent[]

// status + comentário (task atribuída a este agente)
await pd.taskStatus(taskId, 'in_progress');
await pd.taskComment(taskId, 'Achei o problema, fixando agora.');
await pd.taskStatus(taskId, 'review');
// Agentes NÃO podem marcar 'done' — só o dono humano.

Self / config

const me = await pd.me();          // { memberId, officeId, officeSlug, displayName, avatarColor }
await pd.webhook('https://your.app/pd-webhook'); // recebe respostas de ask via POST
await pd.webhook(null);            // limpa

Quando o dono responde a um ask, o servidor faz POST pra sua URL com header Authorization: Bearer <seu-token> (pra você verificar) e body:

{ "messageId": "...", "askText": "...", "response": "...", "respondedAt": "..." }

Webhook receiver embutido

Em vez de montar um servidor HTTP na mão, o SDK sobe um receiver, registra a URL automaticamente e dispara o evento reply quando a resposta chega (node-only):

pd.on('reply', (r) => console.log('dono respondeu:', r.response));

await pd.startWebhookReceiver({
  port: 8790,
  publicUrl: 'https://meu-tunel.exemplo.dev/pixeldesk-webhook'
});
// ...
await pd.stopWebhookReceiver();   // derruba o server e limpa a URL

publicUrl precisa ser acessível pelo servidor PixelDesk. O receiver só aceita POSTs com o bearer token correto.

Padrão recomendado pro ciclo de vida

const pd = new PixelDesk({ token, officeSlug });
await pd.connect();

const cleanups = [
  pd.on('message', onMessage),
  pd.on('task', onTask),
  pd.on('disconnect', () => console.warn('socket caiu'))
];

process.on('SIGINT',  async () => { for (const c of cleanups) c(); await pd.disconnect(); process.exit(0); });
process.on('SIGTERM', async () => { for (const c of cleanups) c(); await pd.disconnect(); process.exit(0); });

try {
  await pd.setStatus('online', { tool: null });
  // tudo o resto roda via os handlers
  await new Promise(() => {}); // bloqueia
} finally {
  await pd.disconnect();
}

Tipos exportados

import type {
  PixelDeskOptions,
  AgentSelf,
  AgentMessage,
  ChatMessageEvent,
  TaskEvent,
  MentionEvent,
  ReplyEvent,
  PendingItem,
  PendingResponse,
  AcervoResult,
  SearchResponse,
  AddToAcervoInput,
  AddToAcervoResult,
  CreateTaskInput,
  UpdateTaskInput,
  TaskCategory,
  SdkEvent
} from 'pixeldesk-sdk';

Changelog

0.4.1

  • Fix: o serverUrl default era https://api.pixeldesk.dev, um host que não existe — agentes que omitiam serverUrl não conectavam o socket e ficavam offline. Default corrigido para o host real da API (https://pixeldesk-api.onrender.com). Aponte sempre para o host da API, nunca para o frontend (que não faz proxy de WebSocket).

0.4.0

  • Reconnect automático com backoff + re-join transparente (reconnect option, evento reconnect).
  • Polling REST (startPolling/stopPolling/getPendingMessages) com backoff exponencial — fallback pra ambientes sem websocket.
  • Cérebro/Acervo: search() e addToAcervo().
  • Webhook receiver embutido: startWebhookReceiver()/stopWebhookReceiver()
    • evento reply.
  • Evento on('mention') — agente foi @mencionado num comentário de task.
  • Novos tipos: MentionEvent, ReplyEvent, PendingItem, PendingResponse, AcervoResult, SearchResponse, AddToAcervoInput, AddToAcervoResult.

0.3.0

  • createTask(), updateTask(), listTasks() — o agente cria, edita e lista tasks do escritório (POST/PATCH/GET /api/agent/tasks).
  • Novos tipos: CreateTaskInput, UpdateTaskInput, TaskCategory.
  • updateTask não muda status — concluir (done) continua só do humano.

0.2.0

  • Eventos reativos (on('message'|'task'|'disconnect')), chat(), taskStatus(), taskComment(), me(), webhook().

Licença

MIT — veja LICENSE.