Token导航 LogoToken导航

Agent Skill · 前端设计

tier-entitlements(等级权利)

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

tier-entitlements 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 6,283。

总安装 533周安装 22GitHub Stars 777下载 174核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

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

请帮我安装这个 Agent Skill:tier-entitlements(等级权利)
来源仓库:https://github.com/dadbodgeoff/drift
仓库路径:skills/tier-entitlements
安装命令:
npx skills add https://github.com/dadbodgeoff/drift --skill tier-entitlements
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

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

skills.shnpx skills
npx skills add https://github.com/dadbodgeoff/drift --skill tier-entitlements

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。适合围绕仓库状态、代码变更或协作事项进行整理。tier-entitlements 属于前端设计类 Skill,可作为该场景下的辅助能力补充。可结合来源仓库和原始 README 核验具体用法。

安装前建议确认权限范围、维护状态及是否触发联网或文件读写。安装方式:通过 npx 从指定 GitHub 仓库添加技能。

来源仓库内路径:skills/tier-entitlements

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/dadbodgeoff/drift --skill tier-entitlements;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

tier-entitlements 怎么安装?

在终端执行 npx skills add https://github.com/dadbodgeoff/drift --skill tier-entitlements。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

tier-entitlements 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

tier-entitlements 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

tier-entitlements 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

tier-entitlements 用的人多吗?

公开数据是累计安装 533 次,近一周安装 22 次,下载 174 次,GitHub 777 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

tier-entitlements 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
tier-entitlements

等级权利 · 本页

533777需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Tier-Based Entitlements

Gate features and track usage by subscription tier.

When to Use This Skill

  • Free users get limited features
  • Pro users get unlimited access
  • Need to track daily/monthly usage
  • Want clean API for checking limits

Core Concepts

  1. Tier config - Single source of truth for all limits
  2. Usage tracking - Database tracks consumption
  3. Atomic increments - Prevent race conditions
  4. Rate limit headers - Standard HTTP headers for clients

TypeScript Implementation

Tier Configuration

// lib/tiers.ts

export const TIER_LIMITS = {
  free: {
    requestsPerDay: 10,
    storageGB: 1,
    historyDays: 7,
    exportEnabled: false,
    apiAccess: false,
    prioritySupport: false,
  },
  pro: {
    requestsPerDay: Infinity,
    storageGB: 100,
    historyDays: 365,
    exportEnabled: true,
    apiAccess: true,
    prioritySupport: false,
  },
  enterprise: {
    requestsPerDay: Infinity,
    storageGB: Infinity,
    historyDays: Infinity,
    exportEnabled: true,
    apiAccess: true,
    prioritySupport: true,
  },
} as const;

export type UserTier = keyof typeof TIER_LIMITS;
export type TierLimits = typeof TIER_LIMITS[UserTier];

export function getTierLimits(tier: UserTier): TierLimits {
  return TIER_LIMITS[tier] || TIER_LIMITS.free;
}

Database Schema

-- migrations/001_user_profiles.sql

CREATE TABLE user_profiles (
    id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
    subscription_tier VARCHAR(20) NOT NULL DEFAULT 'free',

    -- Usage tracking
    requests_today INTEGER DEFAULT 0,
    requests_date DATE DEFAULT CURRENT_DATE,
    storage_used_bytes BIGINT DEFAULT 0,

    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Atomic increment function (prevents race conditions)
CREATE OR REPLACE FUNCTION increment_daily_usage(
    p_user_id UUID,
    p_today DATE
)
RETURNS TABLE(new_count INTEGER, was_reset BOOLEAN) AS $$
DECLARE
    v_new_count INTEGER;
    v_was_reset BOOLEAN := FALSE;
BEGIN
    UPDATE user_profiles
    SET
        requests_today = CASE
            WHEN requests_date = p_today THEN requests_today + 1
            ELSE 1
        END,
        requests_date = p_today,
        updated_at = NOW()
    WHERE id = p_user_id
    RETURNING requests_today INTO v_new_count;

    -- Check if we reset (new day)
    v_was_reset := (SELECT requests_date != p_today FROM user_profiles WHERE id = p_user_id);

    RETURN QUERY SELECT v_new_count, v_was_reset;
END;
$$ LANGUAGE plpgsql;

-- Index for fast lookups
CREATE INDEX idx_user_profiles_tier ON user_profiles(subscription_tier);

Rate Limit Functions

// lib/rate-limits.ts
import type { SupabaseClient } from '@supabase/supabase-js';
import { TIER_LIMITS, type UserTier } from './tiers';

export interface RateLimitResult {
  allowed: boolean;
  limit: number;
  remaining: number;
  reset: number;  // Unix timestamp
  tier: UserTier;
}

export async function checkRateLimit(
  supabase: SupabaseClient,
  userId: string
): Promise<RateLimitResult> {
  const today = new Date().toISOString().split('T')[0];

  const { data: profile } = await supabase
    .from('user_profiles')
    .select('subscription_tier, requests_today, requests_date')
    .eq('id', userId)
    .single();

  if (!profile) {
    return {
      allowed: true,
      limit: TIER_LIMITS.free.requestsPerDay,
      remaining: TIER_LIMITS.free.requestsPerDay,
      reset: getResetTimestamp(),
      tier: 'free',
    };
  }

  const tier = (profile.subscription_tier as UserTier) || 'free';
  const limit = TIER_LIMITS[tier].requestsPerDay;

  // Unlimited tier
  if (limit === Infinity) {
    return {
      allowed: true,
      limit: -1,
      remaining: -1,
      reset: getResetTimestamp(),
      tier,
    };
  }

  // Check usage from today
  const used = profile.requests_date === today ? profile.requests_today : 0;
  const remaining = Math.max(0, limit - used);

  return {
    allowed: remaining > 0,
    limit,
    remaining,
    reset: getResetTimestamp(),
    tier,
  };
}

export async function incrementUsage(
  supabase: SupabaseClient,
  userId: string
): Promise<boolean> {
  const today = new Date().toISOString().split('T')[0];

  const { error } = await supabase.rpc('increment_daily_usage', {
    p_user_id: userId,
    p_today: today,
  });

  return !error;
}

function getResetTimestamp(): number {
  const tomorrow = new Date();
  tomorrow.setUTCDate(tomorrow.getUTCDate() + 1);
  tomorrow.setUTCHours(0, 0, 0, 0);
  return Math.floor(tomorrow.getTime() / 1000);
}

export function getRateLimitHeaders(result: RateLimitResult): Record<string, string> {
  const headers: Record<string, string> = {
    'X-RateLimit-Limit': result.limit === -1 ? 'unlimited' : String(result.limit),
    'X-RateLimit-Remaining': result.remaining === -1 ? 'unlimited' : String(result.remaining),
    'X-RateLimit-Reset': String(result.reset),
  };

  if (!result.allowed) {
    const retryAfter = result.reset - Math.floor(Date.now() / 1000);
    headers['Retry-After'] = String(Math.max(0, retryAfter));
  }

  return headers;
}

export function createRateLimitResponse(result: RateLimitResult): Response {
  return new Response(
    JSON.stringify({
      error: 'Rate limit exceeded',
      code: 'RATE_LIMIT_EXCEEDED',
      message: `You've used all ${result.limit} requests for today. Upgrade for unlimited access.`,
      reset: result.reset,
      upgradeUrl: '/pricing',
    }),
    {
      status: 429,
      headers: {
        'Content-Type': 'application/json',
        ...getRateLimitHeaders(result),
      },
    }
  );
}

Using in API Routes

// app/api/generate/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { createServerSupabaseClient } from '@/lib/supabase-server';
import {
  checkRateLimit,
  incrementUsage,
  createRateLimitResponse,
  getRateLimitHeaders
} from '@/lib/rate-limits';

export async function POST(request: NextRequest) {
  const userId = request.headers.get('x-user-id');

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const supabase = await createServerSupabaseClient();

  // Check rate limit BEFORE expensive operation
  const rateLimit = await checkRateLimit(supabase, userId);

  if (!rateLimit.allowed) {
    return createRateLimitResponse(rateLimit);
  }

  // Process the request
  const body = await request.json();
  const result = await processRequest(body);

  // Increment usage AFTER successful operation
  await incrementUsage(supabase, userId);

  return NextResponse.json(
    { result },
    { headers: getRateLimitHeaders(rateLimit) }
  );
}

Feature Gate Component

// components/FeatureGate.tsx
'use client';

import { useUser } from '@/hooks/useUser';
import { TIER_LIMITS, type UserTier } from '@/lib/tiers';

interface FeatureGateProps {
  feature: keyof typeof TIER_LIMITS.free;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export function FeatureGate({ feature, children, fallback }: FeatureGateProps) {
  const { tier, isLoading } = useUser();

  if (isLoading) return null;

  const limits = TIER_LIMITS[tier as UserTier];
  const hasAccess = limits[feature] === true || limits[feature] === Infinity;

  if (!hasAccess) {
    return fallback ?? (
      <div className="p-4 bg-gray-100 rounded text-center">
        <p className="text-gray-600">This feature requires Pro</p>
        <a href="/pricing" className="text-blue-600 hover:underline">
          Upgrade now
        </a>
      </div>
    );
  }

  return <>{children}</>;
}

// Usage
<FeatureGate feature="exportEnabled">
  <ExportButton />
</FeatureGate>

<FeatureGate
  feature="apiAccess"
  fallback={<ApiAccessUpsell />}
>
  <ApiKeyManager />
</FeatureGate>

Usage Display Component

// components/UsageDisplay.tsx
'use client';

import { useUser } from '@/hooks/useUser';
import { TIER_LIMITS } from '@/lib/tiers';

export function UsageDisplay() {
  const { tier, profile } = useUser();
  const limits = TIER_LIMITS[tier];

  if (limits.requestsPerDay === Infinity) {
    return <span className="text-green-600">Unlimited</span>;
  }

  const used = profile?.requests_today ?? 0;
  const remaining = Math.max(0, limits.requestsPerDay - used);
  const percentage = (used / limits.requestsPerDay) * 100;

  return (
    <div className="space-y-2">
      <div className="flex justify-between text-sm">
        <span>{remaining} remaining today</span>
        <span>{used} / {limits.requestsPerDay}</span>
      </div>
      <div className="h-2 bg-gray-200 rounded-full overflow-hidden">
        <div
          className={`h-full ${percentage > 80 ? 'bg-red-500' : 'bg-blue-500'}`}
          style={{ width: `${Math.min(100, percentage)}%` }}
        />
      </div>
      {remaining === 0 && (
        <a href="/pricing" className="text-blue-600 text-sm">
          Upgrade for unlimited
        </a>
      )}
    </div>
  );
}

Python Implementation

# lib/tiers.py
from dataclasses import dataclass
from typing import Literal
import math

TierName = Literal["free", "pro", "enterprise"]

@dataclass(frozen=True)
class TierLimits:
    requests_per_day: float  # Use math.inf for unlimited
    storage_gb: float
    history_days: int
    export_enabled: bool
    api_access: bool

TIER_LIMITS: dict[TierName, TierLimits] = {
    "free": TierLimits(
        requests_per_day=10,
        storage_gb=1,
        history_days=7,
        export_enabled=False,
        api_access=False,
    ),
    "pro": TierLimits(
        requests_per_day=math.inf,
        storage_gb=100,
        history_days=365,
        export_enabled=True,
        api_access=True,
    ),
}

def get_tier_limits(tier: TierName) -> TierLimits:
    return TIER_LIMITS.get(tier, TIER_LIMITS["free"])
# lib/rate_limits.py
from datetime import datetime, timezone
from dataclasses import dataclass

@dataclass
class RateLimitResult:
    allowed: bool
    limit: int
    remaining: int
    reset: int
    tier: str

async def check_rate_limit(db, user_id: str) -> RateLimitResult:
    today = datetime.now(timezone.utc).date().isoformat()

    profile = await db.get_user_profile(user_id)
    tier = profile.subscription_tier if profile else "free"
    limits = get_tier_limits(tier)

    if limits.requests_per_day == math.inf:
        return RateLimitResult(
            allowed=True,
            limit=-1,
            remaining=-1,
            reset=get_reset_timestamp(),
            tier=tier,
        )

    used = profile.requests_today if profile.requests_date == today else 0
    remaining = max(0, int(limits.requests_per_day) - used)

    return RateLimitResult(
        allowed=remaining > 0,
        limit=int(limits.requests_per_day),
        remaining=remaining,
        reset=get_reset_timestamp(),
        tier=tier,
    )

Response Headers

X-RateLimit-Limit: 10         # Max requests allowed
X-RateLimit-Remaining: 3      # Requests remaining
X-RateLimit-Reset: 1705363200 # Unix timestamp when limit resets
Retry-After: 3600             # Seconds until reset (only on 429)

Best Practices

  1. Check before work - Verify limits before expensive operations
  2. Increment after success - Only count successful requests
  3. Atomic increments - Use database functions to prevent races
  4. Include upgrade CTA - 429 responses should help users upgrade
  5. Show remaining - Display usage in UI

Common Mistakes

  • Incrementing before the operation completes
  • Race conditions with non-atomic increments
  • Not resetting counters on new day
  • Missing rate limit headers on responses
  • Blocking unlimited tier users

Related Skills

平台分布

Codex

33.99%
按下载量换算59

Claude

29.37%
按下载量换算51

Cursor

18.3%
按下载量换算32

Gemini CLI

9.15%
按下载量换算16

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

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

继续浏览同类 Skills