Skip to content

feat: add CrofAI provider#412

Open
msadiks wants to merge 1 commit intorobinebers:mainfrom
msadiks:crofai-provider
Open

feat: add CrofAI provider#412
msadiks wants to merge 1 commit intorobinebers:mainfrom
msadiks:crofai-provider

Conversation

@msadiks
Copy link
Copy Markdown

@msadiks msadiks commented Apr 27, 2026

Description

Adds CrofAI provider as plugin.

Type of Change

  • Bug fix
  • New feature
  • New provider plugin
  • Documentation
  • Performance improvement
  • Other (describe below)

Testing

  • I ran bun run build and it succeeded
  • I ran bun run test and all tests pass
  • I tested the change locally with bun tauri dev

Checklist

  • I read CONTRIBUTING.md
  • My PR targets the main branch
  • I did not introduce new dependencies without justification

Summary by cubic

Adds the crofai provider to show CrofAI credits and daily request usage. Uses requests_plan to render a requests progress bar; hides lines when data is missing or invalid.

  • New Features

    • Uses GET https://crof.ai/usage_api/ with CROFAI_API_KEY (Bearer).
    • Requests: progress of used vs requests_plan (count); hidden when usable_requests is null/absent; clamps used to 0 if remaining exceeds plan.
    • Credits: USD value (shows $0.00); hidden when negative/missing.
    • Adds plugin icon and status link; docs at docs/providers/crofai.md; README updated; CROFAI_API_KEY whitelisted; tests included.
  • Migration

    • Set CROFAI_API_KEY in your environment and restart the app.

Written for commit 5d0696b. Summary will update on new commits. Review in cubic

@github-actions github-actions Bot added rust Pull requests that update rust code plugin docs labels Apr 27, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src-tauri/src/plugin_engine/host_api.rs">

<violation number="1" location="src-tauri/src/plugin_engine/host_api.rs:18">
P1: Adding `CROFAI_API_KEY` to the global plugin env allowlist exposes a sensitive credential to any plugin via `host.env.get`, because env access is not scoped per plugin.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

"CODEX_HOME",
"CLAUDE_CONFIG_DIR",
"CLAUDE_CODE_OAUTH_TOKEN",
"CROFAI_API_KEY",
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Adding CROFAI_API_KEY to the global plugin env allowlist exposes a sensitive credential to any plugin via host.env.get, because env access is not scoped per plugin.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src-tauri/src/plugin_engine/host_api.rs, line 18:

<comment>Adding `CROFAI_API_KEY` to the global plugin env allowlist exposes a sensitive credential to any plugin via `host.env.get`, because env access is not scoped per plugin.</comment>

<file context>
@@ -11,10 +11,11 @@ use std::path::{Path, PathBuf};
     "CODEX_HOME",
     "CLAUDE_CONFIG_DIR",
     "CLAUDE_CODE_OAUTH_TOKEN",
+    "CROFAI_API_KEY",
     "USER_TYPE",
     "USE_STAGING_OAUTH",
</file context>
Fix with Cubic

Copy link
Copy Markdown
Owner

@robinebers robinebers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! 👋 This is Rob's AI reviewer. Thanks for the contribution!

Nice clean provider plugin overall. The API call is scoped, tests are solid, docs are included, and the env var whitelist was updated. Three things to fix before merge:

  1. Icon themingplugins/crofai/icon.svg uses a fixed gradient fill. OpenUsage icons should use currentColor so they work in light/dark themes.

  2. Show zero credits — if CrofAI returns credits: 0, the plugin hides the Credits line. A valid zero balance should show $0.00, not disappear.

  3. Fail clearly on unexpected data — if credits or usable_requests has the wrong type, the plugin currently treats it like 0. Better to show a clear “usage response invalid” error so bad API data does not look like real usage.

Everything else looks good: manifest shape, README/docs, tests, env whitelist, and request URL all match the repo’s patterns.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docs/providers/crofai.md">

<violation number="1" location="docs/providers/crofai.md:55">
P3: Malformed Markdown table in Errors section: separator row declares 3 columns while header/data rows have 2.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread docs/providers/crofai.md Outdated
@msadiks
Copy link
Copy Markdown
Author

msadiks commented Apr 28, 2026

Hey! 👋 This is Rob's AI reviewer. Thanks for the contribution!

Nice clean provider plugin overall. The API call is scoped, tests are solid, docs are included, and the env var whitelist was updated. Three things to fix before merge:

  1. Icon themingplugins/crofai/icon.svg uses a fixed gradient fill. OpenUsage icons should use currentColor so they work in light/dark themes.
  2. Show zero credits — if CrofAI returns credits: 0, the plugin hides the Credits line. A valid zero balance should show $0.00, not disappear.
  3. Fail clearly on unexpected data — if credits or usable_requests has the wrong type, the plugin currently treats it like 0. Better to show a clear “usage response invalid” error so bad API data does not look like real usage.

Everything else looks good: manifest shape, README/docs, tests, env whitelist, and request URL all match the repo’s patterns.

addressed the requested changes:

  • icon now uses currentColor
  • zero credits are shown as $0.00
  • invalid usage response types now fail clearly

@msadiks msadiks requested a review from robinebers April 28, 2026 19:54
@RanaMoizHaider
Copy link
Copy Markdown

/usage_api endpoint now also returns requests_plan which is total number of requests offered per day in the active plan.

Example response:

{"credits":4.9971,"requests_plan":500,"usable_requests":321}

So now we can show a progress bar instead of just text.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="plugins/crofai/plugin.js">

<violation number="1" location="plugins/crofai/plugin.js:59">
P2: `used` can go negative when `usable_requests` is greater than `requests_plan`, violating the documented progress-line contract.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread plugins/crofai/plugin.js Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new CrofAI provider plugin to the OpenUsage plugin ecosystem, enabling display of CrofAI credits and daily request usage via CrofAI’s Usage API.

Changes:

  • Adds the crofai plugin (manifest, implementation, icon) and a comprehensive vitest suite.
  • Documents the provider and links it from the main README.
  • Whitelists CROFAI_API_KEY for plugin environment access in the Tauri host.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src-tauri/src/plugin_engine/host_api.rs Adds CROFAI_API_KEY to the environment variable allowlist for plugins.
plugins/crofai/plugin.js Implements CrofAI usage probing, response validation, and line rendering.
plugins/crofai/plugin.json Defines the CrofAI plugin manifest (lines, icon, links, branding).
plugins/crofai/plugin.test.js Adds unit tests for auth handling, HTTP/error paths, parsing, and line output.
plugins/crofai/icon.svg Adds the CrofAI provider icon.
docs/providers/crofai.md Adds provider documentation for setup, API, output, and errors.
README.md Adds CrofAI to the list of supported providers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugins/crofai/plugin.js Outdated
Comment on lines +46 to +55
var requestsPlan = data.requests_plan
if (typeof requestsPlan !== "number" || !Number.isFinite(requestsPlan) || requestsPlan <= 0) {
throw "Usage response invalid. Try again later."
}

var usableRequests = data.usable_requests
if (usableRequests !== null && usableRequests !== undefined) {
if (typeof usableRequests !== "number" || !Number.isFinite(usableRequests)) {
throw "Usage response invalid. Try again later."
}
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requests_plan is validated unconditionally, so the probe will throw even when usable_requests is null/absent (i.e., when you intend to omit the Requests line). Consider only requiring/validating requests_plan inside the block that builds the Requests progress line, so Credits can still render when request fields are missing.

Suggested change
var requestsPlan = data.requests_plan
if (typeof requestsPlan !== "number" || !Number.isFinite(requestsPlan) || requestsPlan <= 0) {
throw "Usage response invalid. Try again later."
}
var usableRequests = data.usable_requests
if (usableRequests !== null && usableRequests !== undefined) {
if (typeof usableRequests !== "number" || !Number.isFinite(usableRequests)) {
throw "Usage response invalid. Try again later."
}
var usableRequests = data.usable_requests
if (usableRequests !== null && usableRequests !== undefined) {
if (typeof usableRequests !== "number" || !Number.isFinite(usableRequests)) {
throw "Usage response invalid. Try again later."
}
var requestsPlan = data.requests_plan
if (typeof requestsPlan !== "number" || !Number.isFinite(requestsPlan) || requestsPlan <= 0) {
throw "Usage response invalid. Try again later."
}

Copilot uses AI. Check for mistakes.
Comment thread plugins/crofai/plugin.test.js Outdated
Comment on lines +161 to +171
it("throws when credits is Infinity", async () => {
const ctx = makeCtx()
ctx.host.env.get.mockReturnValue("test-api-key")
ctx.host.http.request.mockReturnValue({
status: 200,
bodyText: JSON.stringify({ credits: Infinity, usable_requests: 10, requests_plan: 500 }),
})
const plugin = await loadPlugin()
expect(() => plugin.probe(ctx)).toThrow(
"Usage response invalid. Try again later."
)
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test doesn't actually exercise credits: Infinity: JSON.stringify(Infinity) becomes null, so the plugin is really being tested against credits: null. Either adjust the test name/intent (e.g., credits is null) or use a non-JSON body (like the literal string "Infinity") to cover the invalid-response path you want.

Copilot uses AI. Check for mistakes.
Comment thread plugins/crofai/plugin.test.js Outdated
Comment on lines +174 to +185
it("throws when credits is NaN", async () => {
const ctx = makeCtx()
ctx.host.env.get.mockReturnValue("test-api-key")
ctx.host.http.request.mockReturnValue({
status: 200,
bodyText: JSON.stringify({ credits: NaN, usable_requests: 10, requests_plan: 500 }),
})
const plugin = await loadPlugin()
expect(() => plugin.probe(ctx)).toThrow(
"Usage response invalid. Try again later."
)
})
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: JSON.stringify(NaN) becomes null, so this test isn't validating a NaN value coming from the API. Rename the test to match what it covers, or change the mocked bodyText to a non-JSON value to verify the intended failure mode.

Copilot uses AI. Check for mistakes.
@validatedev
Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs plugin rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants