Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ OpenUsage lives in your menu bar and shows you how much of your AI coding subscr
- [**Claude**](docs/providers/claude.md) / session, weekly, peak/off-peak, extra usage, local token usage (ccusage)
- [**Codex**](docs/providers/codex.md) / session, weekly, reviews, credits
- [**Copilot**](docs/providers/copilot.md) / premium, chat, completions
- [**CrofAI**](docs/providers/crofai.md) / credits, daily requests
- [**Cursor**](docs/providers/cursor.md) / credits, total usage, auto usage, API usage, on-demand, CLI auth
- [**Factory / Droid**](docs/providers/factory.md) / standard, premium tokens
- [**Gemini**](docs/providers/gemini.md) / pro, flash, workspace/free/paid tier
Expand Down
60 changes: 60 additions & 0 deletions docs/providers/crofai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# CrofAI

> Uses the CrofAI Usage API with a user-provided API key.

## Overview

- **Protocol:** HTTPS (JSON)
- **Endpoint:** `GET https://crof.ai/usage_api/`
- **Auth:** `Authorization: Bearer <api_key>`
- **Data:** credit balance, daily requests remaining

## Authentication

Set the `CROFAI_API_KEY` environment variable:

```bash
export CROFAI_API_KEY="your-api-key-here"
```

The key is read from the environment at probe time. Restart OpenUsage after setting it.

## Data Source

Request:

```http
GET /usage_api/ HTTP/1.1
Host: crof.ai
Authorization: Bearer <api_key>
Accept: application/json
```

Response:

```json
{
"credits": 12.3456,
"usable_requests": 450
}
```

| Field | Type | Description |
|---|---|---|
| `credits` | number | Available credit balance (USD) |
| `usable_requests` | number \| null | Requests remaining today (`null` if not on a subscription plan) |

## Output

- **Requests** (overview text line): requests remaining today (e.g., `450 remaining`); hidden when `usable_requests` is null
- **Credits** (overview text line): formatted dollar balance (e.g., `$12.35`)

## Errors

| Condition | Message |
|---|---|
| Missing `CROFAI_API_KEY` env var | `No CROFAI_API_KEY found. Set up environment variable first.` |
| HTTP 401/403 | `API key invalid. Check your CrofAI API key.` |
| Non-2xx | `Usage request failed (HTTP {status}). Try again later.` |
| Network failure | `Usage request failed. Check your connection.` |
| Unparseable or invalid response shape/type | `Usage response invalid. Try again later.` |
16 changes: 16 additions & 0 deletions plugins/crofai/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 72 additions & 0 deletions plugins/crofai/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
(function () {
var API_URL = "https://crof.ai/usage_api/"

function probe(ctx) {
var apiKey = ctx.host.env.get("CROFAI_API_KEY")
if (!apiKey || !String(apiKey).trim()) {
throw "No CROFAI_API_KEY found. Set up environment variable first."
}

var resp
try {
resp = ctx.util.request({
method: "GET",
url: API_URL,
headers: {
Authorization: "Bearer " + String(apiKey).trim(),
Accept: "application/json",
},
timeoutMs: 10000,
})
} catch (e) {
throw "Usage request failed. Check your connection."
}

if (ctx.util.isAuthStatus(resp.status)) {
throw "API key invalid. Check your CrofAI API key."
}

if (resp.status < 200 || resp.status >= 300) {
throw "Usage request failed (HTTP " + String(resp.status) + "). Try again later."
}

var data = ctx.util.tryParseJson(resp.bodyText)
if (!data || typeof data !== "object" || Array.isArray(data)) {
throw "Usage response invalid. Try again later."
}

var hasCredits = typeof data.credits === "number" && Number.isFinite(data.credits)
if ("credits" in data && !hasCredits) {
throw "Usage response invalid. Try again later."
}
var credits = hasCredits ? data.credits : 0

var lines = []

var usableRequests = data.usable_requests
if (usableRequests !== null && usableRequests !== undefined) {
if (typeof usableRequests !== "number" || !Number.isFinite(usableRequests)) {
throw "Usage response invalid. Try again later."
}
lines.push(
ctx.line.text({
label: "Requests",
value: String(usableRequests) + " remaining",
})
)
}

if (hasCredits && credits >= 0) {
lines.push(
ctx.line.text({
label: "Credits",
value: "$" + credits.toFixed(2),
})
)
}

return { lines: lines }
}

globalThis.__openusage_plugin = { id: "crofai", probe }
})()
16 changes: 16 additions & 0 deletions plugins/crofai/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"schemaVersion": 1,
"id": "crofai",
"name": "CrofAI",
"version": "0.0.1",
"entry": "plugin.js",
"icon": "icon.svg",
"brandColor": "#000000",
"links": [
{ "label": "Status", "url": "https://status.nahcrof.com" }
],
"lines": [
{ "type": "text", "label": "Requests", "scope": "overview" },
{ "type": "text", "label": "Credits", "scope": "overview" }
]
}
Loading
Loading