Token导航 LogoToken导航TokenDH.com
前端设计敏感数据github未标认证来源可访问许可证需确认审计通过

customerio-local-dev-loop客户本地开发循环

Agent Skill

customerio-local-dev-loop 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

539

周安装

22

GitHub Stars

2,126

下载量

174
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:customerio-local-dev-loop(客户本地开发循环)
来源仓库:https://github.com/jeremylongshore/claude-code-plugins-plus-skills
仓库路径:skills/customerio-local-dev-loop
安装命令:
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill customerio-local-dev-loop
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill customerio-local-dev-loop

简介

建立本地隔离的开发环境,支持安全测试和客户数据脱敏操作。

  • 通过独立工作区和 Dry-Run 客户端避免污染生产数据,适合日常功能开发与调试。
  • 集成环境变量管理和测试桩(mock),提升单元测试覆盖率和开发效率。
  • 使用前需配置专用 Customer.io 工作区,并确保本地环境与生产环境参数分离。
  • customerio-local-dev-loop 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Customer.io Local Dev Loop

Overview

Set up an efficient local development workflow for Customer.io: environment isolation via separate workspaces, a dry-run client for safe development, test mocks for unit tests, and prefixed events that never pollute production data.

Prerequisites

  • customerio-node installed
  • Separate Customer.io workspace for development (recommended — free workspaces available)
  • dotenv or similar for environment variable loading

Instructions

Step 1: Environment Configuration

# .env.development
CUSTOMERIO_SITE_ID=dev-site-id
CUSTOMERIO_TRACK_API_KEY=dev-track-key
CUSTOMERIO_APP_API_KEY=dev-app-key
CUSTOMERIO_REGION=us
CUSTOMERIO_DRY_RUN=false
CUSTOMERIO_EVENT_PREFIX=dev_

# .env.test
CUSTOMERIO_SITE_ID=not-needed
CUSTOMERIO_TRACK_API_KEY=not-needed
CUSTOMERIO_APP_API_KEY=not-needed
CUSTOMERIO_DRY_RUN=true
CUSTOMERIO_EVENT_PREFIX=test_

Step 2: Environment-Aware Client

// lib/customerio-dev.ts
import { TrackClient, APIClient, RegionUS, RegionEU } from "customerio-node";

interface CioConfig {
  siteId: string;
  trackApiKey: string;
  appApiKey: string;
  region: typeof RegionUS | typeof RegionEU;
  dryRun: boolean;
  eventPrefix: string;
}

function loadConfig(): CioConfig {
  return {
    siteId: process.env.CUSTOMERIO_SITE_ID ?? "",
    trackApiKey: process.env.CUSTOMERIO_TRACK_API_KEY ?? "",
    appApiKey: process.env.CUSTOMERIO_APP_API_KEY ?? "",
    region: process.env.CUSTOMERIO_REGION === "eu" ? RegionEU : RegionUS,
    dryRun: process.env.CUSTOMERIO_DRY_RUN === "true",
    eventPrefix: process.env.CUSTOMERIO_EVENT_PREFIX ?? "",
  };
}

export class DevTrackClient {
  private client: TrackClient | null = null;
  private config: CioConfig;
  private log: typeof console.log;

  constructor() {
    this.config = loadConfig();
    this.log = console.log.bind(console);
    if (!this.config.dryRun) {
      this.client = new TrackClient(
        this.config.siteId,
        this.config.trackApiKey,
        { region: this.config.region }
      );
    }
  }

  async identify(userId: string, attributes: Record<string, any>) {
    const prefixedId = `${this.config.eventPrefix}${userId}`;
    if (this.config.dryRun) {
      this.log("[DRY RUN] identify:", prefixedId, attributes);
      return;
    }
    return this.client!.identify(prefixedId, attributes);
  }

  async track(userId: string, eventName: string, data?: Record<string, any>) {
    const prefixedId = `${this.config.eventPrefix}${userId}`;
    const prefixedEvent = `${this.config.eventPrefix}${eventName}`;
    if (this.config.dryRun) {
      this.log("[DRY RUN] track:", prefixedId, prefixedEvent, data);
      return;
    }
    return this.client!.track(prefixedId, {
      name: prefixedEvent,
      data,
    });
  }

  async suppress(userId: string) {
    const prefixedId = `${this.config.eventPrefix}${userId}`;
    if (this.config.dryRun) {
      this.log("[DRY RUN] suppress:", prefixedId);
      return;
    }
    return this.client!.suppress(prefixedId);
  }
}

Step 3: Test Mocks for Unit Tests

// __mocks__/customerio-node.ts (for vitest/jest auto-mocking)
import { vi } from "vitest";

export const TrackClient = vi.fn().mockImplementation(() => ({
  identify: vi.fn().mockResolvedValue(undefined),
  track: vi.fn().mockResolvedValue(undefined),
  trackAnonymous: vi.fn().mockResolvedValue(undefined),
  suppress: vi.fn().mockResolvedValue(undefined),
  destroy: vi.fn().mockResolvedValue(undefined),
  mergeCustomers: vi.fn().mockResolvedValue(undefined),
}));

export const APIClient = vi.fn().mockImplementation(() => ({
  sendEmail: vi.fn().mockResolvedValue({ delivery_id: "mock-delivery-123" }),
  sendPush: vi.fn().mockResolvedValue({ delivery_id: "mock-push-456" }),
  triggerBroadcast: vi.fn().mockResolvedValue(undefined),
}));

export const RegionUS = "us";
export const RegionEU = "eu";
export const SendEmailRequest = vi.fn().mockImplementation((data) => data);
export const SendPushRequest = vi.fn().mockImplementation((data) => data);

Step 4: Integration Test with Real API

// tests/customerio.integration.test.ts
import { describe, it, expect, afterAll } from "vitest";
import { TrackClient, RegionUS } from "customerio-node";

const TEST_PREFIX = `test_${Date.now()}_`;
const testUserIds: string[] = [];

const cio = new TrackClient(
  process.env.CUSTOMERIO_SITE_ID!,
  process.env.CUSTOMERIO_TRACK_API_KEY!,
  { region: RegionUS }
);

function testUserId(label: string): string {
  const id = `${TEST_PREFIX}${label}`;
  testUserIds.push(id);
  return id;
}

describe("Customer.io Integration", () => {
  afterAll(async () => {
    // Clean up all test users
    for (const id of testUserIds) {
      await cio.suppress(id).catch(() => {});
      await cio.destroy(id).catch(() => {});
    }
  });

  it("should identify a user", async () => {
    const id = testUserId("identify");
    await expect(
      cio.identify(id, { email: `${id}@test.example.com` })
    ).resolves.not.toThrow();
  });

  it("should track an event", async () => {
    const id = testUserId("track");
    await cio.identify(id, { email: `${id}@test.example.com` });
    await expect(
      cio.track(id, { name: "test_event", data: { step: 1 } })
    ).resolves.not.toThrow();
  });

  it("should reject invalid credentials", async () => {
    const badClient = new TrackClient("bad-id", "bad-key", {
      region: RegionUS,
    });
    await expect(
      badClient.identify("x", { email: "x@test.com" })
    ).rejects.toThrow();
  });
});

Run integration tests only against your dev workspace:

# Load dev env and run integration tests
npx dotenv -e .env.development -- npx vitest run tests/customerio.integration.test.ts

Step 5: Dev Scripts

// package.json scripts
{
  "scripts": {
    "cio:verify": "dotenv -e .env.development -- tsx scripts/verify-customerio.ts",
    "cio:test": "dotenv -e .env.development -- vitest run tests/customerio.integration.test.ts",
    "cio:test:dry": "CUSTOMERIO_DRY_RUN=true vitest run tests/customerio"
  }
}

Workspace Isolation Strategy

EnvironmentWorkspace NameEvent PrefixDry Run
Unit tests(mocked)test_true
Integration testsmyapp-devinttest_false
Stagingmyapp-staging(none)false
Productionmyapp-prod(none)false

Error Handling

ErrorCauseSolution
Dev events in productionWrong .env file loadedVerify NODE_ENV and env file path
Mock not interceptingImport order issueMock customerio-node before importing your client module
Test user pollutionNo cleanupAlways suppress + destroy test users in afterAll

Resources

Next Steps

After setting up local dev, proceed to customerio-sdk-patterns for production-ready patterns.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.85%
按下载量换算64

Claude

29.21%
按下载量换算51

Cursor

19.84%
按下载量换算35

Gemini CLI

9.52%
按下载量换算17

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills