Skill: vittor1o/rollbar (version 1.5.0)

--- name: rollbar version: 1.5.0 description: "Monitor and manage Rollbar error tracking. List recent items, get item details, resolve/mute issues, track deployments, and manage project access tokens via the Rollbar API." homepage: https://github.com/vittor1o/rollbar-openclaw-skill metadata: openclaw: emoji: "🐛" requires: bins: - curl - python3 permissions: shell: exec env: read: - ROLLBAR_ACCESS_TOKEN - ROLLBAR_CONFIG_FILE network: outbound: - https://api.rollbar.com files: read: - .rollbar-mcp.json - secrets/rollbar - .env write: - .rollbar-mcp.json safety: destructive_commands: - resolve - mute - activate - project-token-create - project-token-update interlock: "--yes or --dry-run required for state-changing commands" --- # Rollbar Skill Monitor and manage Rollbar errors directly from OpenClaw. ## Setup The script resolves your Rollbar token from the first matching source: | Priority | Method | How | |---|---|---| | 1 | `$PWD/secrets/rollbar` | One-line file in your agent workspace containing the token | | 2 | `.rollbar-mcp.json` | MCP-compatible JSON config (cwd, `~/.rollbar-mcp.json`, or `$ROLLBAR_CONFIG_FILE`) | | 3 | `$PWD/.env` | File in your agent workspace with `ROLLBAR_ACCESS_TOKEN=your-token` | | 4 | `ROLLBAR_ACCESS_TOKEN` | Environment variable (injected or shell) | ### MCP-Compatible Config (Recommended for multi-project setups) Create `.rollbar-mcp.json` in your agent workspace: ```json // Single project { "token": "tok_abc123" } // Multiple projects { "projects": [ { "name": "linkz-api", "token": "tok_abc123" }, { "name": "linkz-dashboard", "token": "tok_xyz789" }, { "name": "linkz-php", "token": "tok_def456" } ] } ``` Use `--project-name <name>` to select a specific project's token when running commands. > **Tip:** Use `project-token-create --save` to have the agent auto-create and persist tokens to `.rollbar-mcp.json`. ### Single-project .env ```bash # workspace-myagent/.env ROLLBAR_ACCESS_TOKEN=your-token-here ``` ### Token types - **Project-level token** — from Rollbar → Project → Settings → Project Access Tokens. Use `read` scope for monitoring; add `write` scope to resolve/mute. Best for single-project use. - **Account-level token** — from Rollbar → Account Settings → Account Access Tokens. Required for `projects`, `project-tokens`, and `project-token-create`. Use `--project-id` to target specific projects. ## Commands All commands use the helper script `rollbar.sh` in this skill directory. ### List projects (account token only) ```bash ./skills/rollbar/rollbar.sh projects ``` ### List recent items (errors/warnings) ```bash ./skills/rollbar/rollbar.sh items [--project-id <id>] [--project-name <name>] [--status active|resolved|muted] [--level critical|error|warning|info] [--limit 20] ``` ### Get item details ```bash ./skills/rollbar/rollbar.sh item <item_id> ``` ### Get occurrences for an item ```bash ./skills/rollbar/rollbar.sh occurrences <item_id> [--limit 5] ``` ### Resolve an item ```bash ./skills/rollbar/rollbar.sh resolve <item_id> --yes # or preview without making changes: ./skills/rollbar/rollbar.sh resolve <item_id> --dry-run ``` ### Mute an item ```bash ./skills/rollbar/rollbar.sh mute <item_id> --yes ``` ### Activate (reopen) an item ```bash ./skills/rollbar/rollbar.sh activate <item_id> --yes ``` > **Safety interlock:** `resolve`, `mute`, `activate`, `project-token-create`, and `project-token-update` > require `--yes` to execute or `--dry-run` to preview. Omitting both prints a warning and exits with > an error — preventing silent state changes from mistaken or manipulated invocations. ### List deploys ```bash ./skills/rollbar/rollbar.sh deploys [--limit 10] ``` ### Get project info ```bash ./skills/rollbar/rollbar.sh project ``` ### Top active items (summary) ```bash ./skills/rollbar/rollbar.sh top [--limit 10] [--hours 24] ``` --- ## Project Access Token Management These commands require an **account-level token with `write` scope**. ### List project access tokens ```bash ./skills/rollbar/rollbar.sh project-tokens --project-id <id> ``` Token values are truncated in output (first 8 chars + `...`) for safety. ### Create a project access token ```bash ./skills/rollbar/rollbar.sh project-token-create \ --project-id <id> \ --name "openclaw-agent" \ --scopes read,write \ [--project-name <name>] \ [--save] ``` - `--scopes` — comma-separated, e.g. `read` or `read,write` (default: `read,write`) - `--save` — automatically saves the new token to `.rollbar-mcp.json` using `--project-name` (or `--name`) as the key - `--project-name` — name used as the key in `.rollbar-mcp.json` when `--save` is set **Bootstrap workflow** — let the agent provision its own project tokens: ```bash # Set account token first export ROLLBAR_ACCESS_TOKEN=your-account-token # Create tokens for each project and save to MCP config ./rollbar.sh project-token-create --project-id 378962 --name "linkz-api-agent" --scopes read,write --project-name linkz-api --save --yes ./rollbar.sh project-token-create --project-id 462118 --name "linkz-dashboard-agent" --scopes read,write --project-name linkz-dashboard --save --yes ./rollbar.sh project-token-create --project-id 755542 --name "linkz-php-agent" --scopes read,write --project-name linkz-php --save --yes # Now use per-project tokens directly from config ./rollbar.sh items --project-name linkz-api ``` ### Update a project access token ```bash ./skills/rollbar/rollbar.sh project-token-update <token_id> \ --project-id <id> \ --token-status enabled|disabled ``` --- ## Proactive Monitoring To get automatic alerts for new critical/error items, set up a cron job in OpenClaw: > "Check Rollbar for new critical or error-level items in the last hour. If any new items appeared, summarize them and alert me." Recommended schedule: every 30–60 minutes during work hours. ## Notes - All output is JSON for easy parsing. - The `top` command sorts active items by occurrence count — useful for daily triage. - Token values in `project-tokens` output are truncated for safety; full values are only returned on creation. - Rollbar API docs: https://docs.rollbar.com/reference

path: README.md
content: # Rollbar Skill for OpenClaw

🐛 Monitor and manage [Rollbar](https://rollbar.com) error tracking directly from [OpenClaw](https://openclaw.ai).

## Features

- **List & filter** active errors by status and severity level
- **Inspect** item details and individual occurrences
- **Triage** — resolve, mute, or reopen items
- **Deployments** — list recent deploys
- **Top errors** — rank active items by occurrence count within a time window
- **Proactive monitoring** — pair with OpenClaw cron for automatic alerts

## Installation

```bash
clawhub install rollbar
```

Or manually clone this repo into your OpenClaw workspace `skills/` directory.

## Setup

The script resolves your Rollbar token from the first matching source:

| Priority | Method | How |
|---|---|---|
| 1 | `$PWD/secrets/rollbar` | One-line file in your agent workspace containing the token |
| 2 | `$PWD/.env` | `ROLLBAR_ACCESS_TOKEN=your-token` in your agent workspace |
| 3 | `ROLLBAR_ACCESS_TOKEN` | Environment variable (injected or shell) |

**Option A — `.env` file (recommended):**

```bash
# workspace-myagent/.env
ROLLBAR_ACCESS_TOKEN=your-token-here
```

**Option B — secrets file:**

```bash
# workspace-myagent/secrets/rollbar
your-token-here
```

> **⚠️ Security:** Never commit tokens. Use workspace-local files or environment variables only.

**Token types:**
- **Project token** (recommended) — Rollbar → Project → Settings → Project Access Tokens. Use `read` scope; add `write` only if you need to resolve/mute items.
- **Account token** (multi-project) — Rollbar → Account Settings → Account Access Tokens. Use with `--project-id <id>` to target specific projects.

## Usage

```bash
# List active errors
./skills/rollbar/rollbar.sh items --status active --level error

# Get item details
./skills/rollbar/rollbar.sh item 12345

# Top errors in the last 24 hours
./skills/rollbar/rollbar.sh top --hours 24

# Resolve an item
./skills/rollbar/rollbar.sh resolve 12345

# List deploys
./skills/rollbar/rollbar.sh deploys
```

See [SKILL.md](./SKILL.md) for full command reference.

## Proactive Monitoring

Set up an OpenClaw cron job to check for new errors automatically:

> "Check Rollbar for new critical or error-level items in the last hour. Summarize and alert me if any new items appeared."

## License

MIT


path: rollbar.sh
content: #!/usr/bin/env bash
# rollbar.sh — Rollbar API helper for OpenClaw
# Supports account-level and project-level tokens with MCP-compatible config.
# Usage: rollbar.sh <command> [options]

set -euo pipefail

BASE_URL="https://api.rollbar.com/api/1"

# --- MCP Config Helpers ---

# Resolve config file path:
# ROLLBAR_CONFIG_FILE env > .rollbar-mcp.json in cwd > ~/.rollbar-mcp.json
_find_mcp_config() {
  if [[ -n "${ROLLBAR_CONFIG_FILE:-}" && -f "$ROLLBAR_CONFIG_FILE" ]]; then
    echo "$ROLLBAR_CONFIG_FILE"; return
  fi
  [[ -f "$PWD/.rollbar-mcp.json" ]] && echo "$PWD/.rollbar-mcp.json" && return
  [[ -f "$HOME/.rollbar-mcp.json" ]] && echo "$HOME/.rollbar-mcp.json" && return
  echo ""
}

# Extract token from MCP config, optionally for a specific project name
_mcp_get_token() {
  local config_file="$1" project_name="${2:-}"
  [[ -z "$config_file" || ! -f "$config_file" ]] && return 1
  python3 - "$config_file" "$project_name" <<'PYEOF'
import json, sys
config_file, target = sys.argv[1], sys.argv[2]
with open(config_file) as f:
    cfg = json.load(f)
if not target:
    tok = cfg.get('token') or next((p.get('token', '') for p in cfg.get('projects', [])), '')
    if tok: print(tok); sys.exit(0)
    sys.exit(1)
for p in cfg.get('projects', []):
    if p.get('name') == target:
        print(p['token']); sys.exit(0)
sys.exit(1)
PYEOF
}

# Save/update a project token in the MCP config file (creates if missing)
_mcp_save_token() {
  local config_file="$1" project_name="$2" token="$3"
  python3 - "$config_file" "$project_name" "$token" <<'PYEOF'
import json, os, sys
config_file, project_name, [REDACTED_SECRET], sys.argv[2], sys.argv[3]
cfg = {}
if os.path.exists(config_file):
    with open(config_file) as f:
        cfg = json.load(f)
# Convert single-project shorthand to multi-project format
if 'token' in cfg and 'projects' not in cfg:
    cfg = {'projects': [{'name': 'default', 'token': cfg['token']}]}
if 'projects' not in cfg:
    cfg['projects'] = []
for p in cfg['projects']:
    if p.get('name') == project_name:
        p['token'] = token; break
else:
    cfg['projects'].append({'name': project_name, 'token': token})
with open(config_file, 'w') as f:
    json.dump(cfg, f, indent=2); f.write('\n')
print(f'Saved token for project: {project_name} -> {config_file}')
PYEOF
}

# --- Usage ---
usage() {
  cat <<EOF
Usage: rollbar.sh <command> [options]

Commands:
  projects                  List all projects (account token required)
  items                     List recent items
  item <id>                 Get item details
  occurrences <id>          Get occurrences for an item
  resolve <id>              Resolve an item
  mute <id>                 Mute an item
  activate <id>             Reopen an item
  deploys                   List recent deploys
  project                   Get project info
  top                       Top active items by occurrence count
  project-tokens            List access tokens for a project
  project-token-create      Create a project access token (account write token required)
  project-token-update      Update a project access token status/rate-limits

Options:
  --project-id <id>         Target project by numeric ID
  --project-name <name>     Select project by name (from .rollbar-mcp.json config)
  --status <active|resolved|muted>   Filter items by status
  --level <critical|error|warning|info>  Filter items by level
  --limit <n>               Max results (default: 20)
  --hours <n>               Time window for 'top' (default: 24)
  --name <name>             Token name (project-token-create)
  --scopes <read,write>     Comma-separated scopes (default: read,write)
  --token-status <enabled|disabled>  Token status (project-token-update)
  --save                    Save created token to .rollbar-mcp.json

Token resolution (first match wins):
  1. \$PWD/secrets/rollbar           — one-line token file
  2. .rollbar-mcp.json (cwd or ~/)  — MCP-compatible JSON config
     Single:   { "token": "tok_..." }
     Multiple: { "projects": [{ "name": "myapp", "token": "tok_..." }] }
     Also: set ROLLBAR_CONFIG_FILE env var for a custom path
  3. \$PWD/.env                      — ROLLBAR_ACCESS_TOKEN=<token>
  4. ROLLBAR_ACCESS_TOKEN           — environment variable

MCP config (.rollbar-mcp.json):
  Use --project-name to select a specific project's token from the config.
  Use 'project-token-create --save' to auto-persist new tokens to the config.
EOF
  exit 0
}

# --- Parse command ---
COMMAND="${1:-}"
[[ -z "$COMMAND" || "$COMMAND" == "--help" || "$COMMAND" == "-h" ]] && usage
shift

# --- Parse options ---
STATUS="" LEVEL="" LIMIT="20" HOURS="24" ITEM_ID=""
PROJECT_ID="" PROJECT_NAME="" TOKEN_NAME="" SCOPES="read,write"
TOKEN_STATUS_VAL="" SAVE_TOKEN=false DRY_RUN=false YES=false

while [[ $# -gt 0 ]]; do
  case "$1" in
    --status)         STATUS="$2"; shift 2 ;;
    --level)          LEVEL="$2"; shift 2 ;;
    --limit)          LIMIT="$2"; shift 2 ;;
    --hours)          HOURS="$2"; shift 2 ;;
    --project-id)     PROJECT_ID="$2"; shift 2 ;;
    --project-name)   PROJECT_NAME="$2"; shift 2 ;;
    --name)           TOKEN_NAME="$2"; shift 2 ;;
    --scopes)         SCOPES="$2"; shift 2 ;;
    --token-status)   TOKEN_STATUS_VAL="$2"; shift 2 ;;
    --save)           SAVE_TOKEN=true; shift ;;
    --dry-run)        DRY_RUN=true; shift ;;
    --yes)            YES=true; shift ;;
    *)
      if [[ -z "$ITEM_ID" ]]; then
        ITEM_ID="$1"; shift
      else
        echo "Unknown option: $1" >&2; exit 1
      fi
      ;;
  esac
done

# --- Input validation ---
if [[ -n "$ITEM_ID" && ! "$ITEM_ID" =~ ^[a-zA-Z0-9_-]+$ ]]; then
  echo "Error: Invalid item/token ID: $ITEM_ID" >&2; exit 1
fi
if [[ -n "$PROJECT_ID" && ! "$PROJECT_ID" =~ ^[0-9]+$ ]]; then
  echo "Error: Invalid project ID: $PROJECT_ID" >&2; exit 1
fi
if [[ ! "$LIMIT" =~ ^[0-9]+$ ]]; then
  echo "Error: Invalid limit: $LIMIT" >&2; exit 1
fi
if [[ ! "$HOURS" =~ ^[0-9]+$ ]]; then
  echo "Error: Invalid hours: $HOURS" >&2; exit 1
fi

# --- Token Resolution ---
# Source workspace .env if present
[[ -f "$PWD/.env" ]] && source "$PWD/.env" 2>/dev/null || true

MCP_CONFIG="$(_find_mcp_config)"

TOKEN=""
# 1. Secrets file
if [[ -f "$PWD/secrets/rollbar" ]]; then
  TOKEN=$(cat "$PWD/secrets/rollbar" 2>/dev/null || true)
  [REDACTED_SECRET]'\t\r\n ']}"
fi
# 2. MCP config (use --project-name to select specific project)
if [[ -z "$TOKEN" && -n "$MCP_CONFIG" ]]; then
  [REDACTED_SECRET] "$MCP_CONFIG" "$PROJECT_NAME" 2>/dev/null || true)
fi
# 3. ROLLBAR_ACCESS_TOKEN from .env or environment
if [[ -z "$TOKEN" ]]; then
  [REDACTED_SECRET]"
fi

if [[ -z "$TOKEN" ]]; then
  echo "Error: No Rollbar token found." >&2
  echo "" >&2
  echo "Token resolution order (first match wins):" >&2
  echo "  1. \$PWD/secrets/rollbar           — one-line token file" >&2
  echo "  2. .rollbar-mcp.json (cwd or ~/)  — MCP-compatible JSON config" >&2
  echo "     Single:   { \"token\": \"tok_...\" }" >&2
  echo "     Multiple: { \"projects\": [{\"name\": \"myapp\", \"token\": \"tok_...\"}] }" >&2
  echo "     Custom:   set ROLLBAR_CONFIG_FILE env var" >&2
  echo "  3. \$PWD/.env                      — ROLLBAR_ACCESS_TOKEN=<token>" >&2
  echo "  4. ROLLBAR_ACCESS_TOKEN           — environment variable" >&2
  exit 1
fi

# --- HTTP Helpers ---
api_get() {
  local endpoint="$1"; shift
  curl -sf -H "X-Rollbar-Access-[REDACTED_SECRET]" "$BASE_URL/$endpoint" "$@"
}

api_post() {
  local endpoint="$1" data="$2"
  curl -sf -X POST \
    -H "X-Rollbar-Access-[REDACTED_SECRET]" \
    -H "Content-Type: application/json" \
    -d "$data" \
    "$BASE_URL/$endpoint"
}

api_patch() {
  local endpoint="$1" data="$2"
  curl -sf -X PATCH \
    -H "X-Rollbar-Access-[REDACTED_SECRET]" \
    -H "Content-Type: application/json" \
    -d "$data" \
    "$BASE_URL/$endpoint"
}

# Helper: resolve a project-level read token via account token
_get_project_token() {
  local project_id="$1"
  local tmpfile
  tmpfile=$(mktemp)
  api_get "project/$project_id/access_tokens" > "$tmpfile" 2>/dev/null || { rm -f "$tmpfile"; return 1; }
  python3 - "$tmpfile" <<'PYEOF'
import json, sys
with open(sys.argv[1]) as f:
    tokens = json.load(f).get('result', [])
for t in tokens:
    if 'read' in t.get('scopes', []):
        print(t['access_token']); break
PYEOF
  rm -f "$tmpfile"
}

# Auto-switch to project token for item commands when account token is in use
if [[ -n "$PROJECT_ID" && "$COMMAND" != "projects" && "$COMMAND" != "project-tokens" && \
      "$COMMAND" != "project-token-create" && "$COMMAND" != "project-token-update" ]]; then
  PROJECT_TOKEN=$(_get_project_token "$PROJECT_ID" 2>/dev/null || true)
  [[ -n "$PROJECT_TOKEN" ]] && [REDACTED_SECRET]"
fi

# --- Commands ---
case "$COMMAND" in

  projects)
    api_get "projects" | python3 -c "
import json, sys
data = json.load(sys.stdin)
projects = data.get('result', [])
print(json.dumps([{
    'id': p['id'],
    'name': p['name'],
    'status': p.get('status', '?'),
    'date_created': p.get('date_created'),
} for p in projects], indent=2))
"
    ;;

  items)
    PARAMS="?page=1&sort=last_occurrence"
    [[ -n "$STATUS" ]] && PARAMS="$PARAMS&status=$STATUS"
    [[ -n "$LEVEL" ]] && PARAMS="$PARAMS&level=$LEVEL"
    api_get "items$PARAMS" | _LIMIT="$LIMIT" python3 -c "
import json, sys, os
data = json.load(sys.stdin)
items = data.get('result', {}).get('items', data.get('result', []))
limit = int(os.environ['_LIMIT'])
if isinstance(items, list): items = items[:limit]
print(json.dumps([{
    'id': i['id'],
    'counter': i.get('counter'),
    'title': i.get('title', '')[:150],
    'level': i.get('level_string', i.get('level', '')),
    'status': i.get('status', ''),
    'total_occurrences': i.get('total_occurrences', 0),
    'last_occurrence': i.get('last_occurrence_timestamp'),
    'environment': i.get('environment', ''),
    'framework': i.get('framework', ''),
} for i in items], indent=2))
"
    ;;

  item)
    [[ -z "$ITEM_ID" ]] && { echo "Usage: rollbar.sh item <item_id>" >&2; exit 1; }
    api_get "item/$ITEM_ID" | python3 -m json.tool 2>/dev/null || api_get "item/$ITEM_ID"
    ;;

  occurrences)
    [[ -z "$ITEM_ID" ]] && { echo "Usage: rollbar.sh occurrences <item_id>" >&2; exit 1; }
    api_get "item/$ITEM_ID/instances/?page=1" | python3 -m json.tool 2>/dev/null || \
      api_get "item/$ITEM_ID/instances/?page=1"
    ;;

  resolve)
    [[ -z "$ITEM_ID" ]] && { echo "Usage: rollbar.sh resolve <item_id>" >&2; exit 1; }
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "{\"dry_run\": true, \"action\": \"resolve\", \"item_id\": \"$ITEM_ID\"}"
      exit 0
    fi
    if [[ "$YES" != "true" ]]; then
      echo "⚠️  This will resolve item $ITEM_ID and suppress future alerts. Pass --yes to confirm, or --dry-run to preview." >&2
      exit 1
    fi
    api_patch "item/$ITEM_ID" '{"status":"resolved"}' | python3 -m json.tool 2>/dev/null || \
      api_patch "item/$ITEM_ID" '{"status":"resolved"}'
    ;;

  mute)
    [[ -z "$ITEM_ID" ]] && { echo "Usage: rollbar.sh mute <item_id>" >&2; exit 1; }
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "{\"dry_run\": true, \"action\": \"mute\", \"item_id\": \"$ITEM_ID\"}"
      exit 0
    fi
    if [[ "$YES" != "true" ]]; then
      echo "⚠️  This will mute item $ITEM_ID and stop all alerts for it. Pass --yes to confirm, or --dry-run to preview." >&2
      exit 1
    fi
    api_patch "item/$ITEM_ID" '{"status":"muted"}' | python3 -m json.tool 2>/dev/null || \
      api_patch "item/$ITEM_ID" '{"status":"muted"}'
    ;;

  activate)
    [[ -z "$ITEM_ID" ]] && { echo "Usage: rollbar.sh activate <item_id>" >&2; exit 1; }
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "{\"dry_run\": true, \"action\": \"activate\", \"item_id\": \"$ITEM_ID\"}"
      exit 0
    fi
    if [[ "$YES" != "true" ]]; then
      echo "⚠️  This will reopen item $ITEM_ID. Pass --yes to confirm, or --dry-run to preview." >&2
      exit 1
    fi
    api_patch "item/$ITEM_ID" '{"status":"active"}' | python3 -m json.tool 2>/dev/null || \
      api_patch "item/$ITEM_ID" '{"status":"active"}'
    ;;

  deploys)
    api_get "deploys/?page=1" | python3 -m json.tool 2>/dev/null || api_get "deploys/?page=1"
    ;;

  project)
    api_get "project" | python3 -m json.tool 2>/dev/null || api_get "project"
    ;;

  top)
    PARAMS="?status=active&sort=total_occurrences&direction=desc&page=1"
    [[ -n "$LEVEL" ]] && PARAMS="$PARAMS&level=$LEVEL"
    api_get "items$PARAMS" | _HOURS="$HOURS" _LIMIT="$LIMIT" python3 -c "
import json, sys, os
from datetime import datetime, timedelta, timezone
data = json.load(sys.stdin)
items = data.get('result', {}).get('items', data.get('result', []))
hours = int(os.environ['_HOURS'])
limit = int(os.environ['_LIMIT'])
cutoff = datetime.now(timezone.utc) - timedelta(hours=hours)
print(json.dumps({
    'window_hours': hours,
    'items': [{
        'id': i['id'],
        'counter': i.get('counter'),
        'title': i.get('title', '')[:120],
        'level': i.get('level_string', i.get('level', '')),
        'total_occurrences': i.get('total_occurrences', 0),
        'last_occurrence': i.get('last_occurrence_timestamp'),
        'environment': i.get('environment', ''),
    } for i in (items if isinstance(items, list) else [])
      if i.get('last_occurrence_timestamp', 0) >= cutoff.timestamp()
    ][:limit]
}, indent=2))
" 2>/dev/null || api_get "items$PARAMS"
    ;;

  # --- Project Token Management ---

  project-tokens)
    [[ -z "$PROJECT_ID" ]] && { echo "Error: --project-id required" >&2; exit 1; }
    api_get "project/$PROJECT_ID/access_tokens" | python3 -c "
import json, sys
data = json.load(sys.stdin)
tokens = data.get('result', [])
print(json.dumps([{
    'access_token': t.get('access_token', '')[:8] + '...',
    'name': t.get('name', ''),
    'scopes': t.get('scopes', []),
    'status': t.get('status', ''),
    'date_created': t.get('date_created'),
    'rate_limit_window_size': t.get('rate_limit_window_size'),
    'rate_limit_window_count': t.get('rate_limit_window_count'),
} for t in tokens], indent=2))
"
    ;;

  project-token-create)
    [[ -z "$PROJECT_ID" ]] && { echo "Error: --project-id required" >&2; exit 1; }
    [[ -z "$TOKEN_NAME" ]] && { echo "Error: --name required (token name)" >&2; exit 1; }
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "{\"dry_run\": true, \"action\": \"project-token-create\", \"project_id\": \"$PROJECT_ID\", \"name\": \"$TOKEN_NAME\", \"scopes\": \"$SCOPES\"}"
      exit 0
    fi
    if [[ "$YES" != "true" ]]; then
      echo "⚠️  This will create a new $SCOPES access token for project $PROJECT_ID. Pass --yes to confirm, or --dry-run to preview." >&2
      exit 1
    fi
    # Build scopes array from comma-separated string
    SCOPES_JSON=$(python3 -c "import json; print(json.dumps('$SCOPES'.split(',')))")
    PAYLOAD=$(python3 -c "
import json
print(json.dumps({'name': '$TOKEN_NAME', 'scopes': '$SCOPES'.split(',')}))
")
    RESULT=$(api_post "project/$PROJECT_ID/access_tokens" "$PAYLOAD")
    echo "$RESULT" | python3 -m json.tool 2>/dev/null || echo "$RESULT"
    # Optionally save to .rollbar-mcp.json
    if [[ "$SAVE_TOKEN" == "true" ]]; then
      NEW_TOKEN=$(echo "$RESULT" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(data.get('result', {}).get('access_token', ''))
" 2>/dev/null || true)
      if [[ -n "$NEW_TOKEN" ]]; then
        SAVE_NAME="${PROJECT_NAME:-$TOKEN_NAME}"
        CONFIG_DEST="${MCP_CONFIG:-$PWD/.rollbar-mcp.json}"
        _mcp_save_token "$CONFIG_DEST" "$SAVE_NAME" "$NEW_TOKEN"
      else
        echo "Warning: could not extract token from response; skipping save." >&2
      fi
    fi
    ;;

  project-token-update)
    # ITEM_ID is used as the token value/id to update
    [[ -z "$ITEM_ID" ]] && { echo "Error: Usage: rollbar.sh project-token-update <token_id_or_value> --project-id <id> [--token-status enabled|disabled]" >&2; exit 1; }
    [[ -z "$PROJECT_ID" ]] && { echo "Error: --project-id required" >&2; exit 1; }
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "{\"dry_run\": true, \"action\": \"project-token-update\", \"token_id\": \"$ITEM_ID\", \"project_id\": \"$PROJECT_ID\", \"token_status\": \"$TOKEN_STATUS_VAL\"}"
      exit 0
    fi
    if [[ "$YES" != "true" ]]; then
      echo "⚠️  This will update token $ITEM_ID on project $PROJECT_ID. Pass --yes to confirm, or --dry-run to preview." >&2
      exit 1
    fi
    PATCH_DATA="{}"
    [[ -n "$TOKEN_STATUS_VAL" ]] && PATCH_DATA=$(python3 -c "import json; print(json.dumps({'status': '$TOKEN_STATUS_VAL'}))")
    api_patch "project/$PROJECT_ID/access_token/$ITEM_ID" "$PATCH_DATA" | \
      python3 -m json.tool 2>/dev/null || \
      api_patch "project/$PROJECT_ID/access_token/$ITEM_ID" "$PATCH_DATA"
    ;;

  *)
    echo "Unknown command: $COMMAND" >&2
    echo "Run: rollbar.sh --help" >&2
    exit 1
    ;;
esac


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal:  | SkillSpector: clean (LOW)