diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 6e4fc26..0a1aaf6 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "polar", "displayName": "Polar", - "version": "0.1.0", + "version": "0.2.0", "description": "Add Polar payments, subscriptions and usage billing to your app. Connects Claude to your Polar organization through the Polar MCP server and adds skills for setup, integration, testing and migrating from other payment platforms.", "author": { "name": "Polar", diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index d3faaac..a4f10a0 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "polar", "displayName": "Polar", - "version": "0.1.0", + "version": "0.2.0", "description": "Add Polar payments, subscriptions and usage billing to your app. Connects Cursor to your Polar organization through the Polar MCP server and adds skills for setup, integration, testing and migrating from other payment platforms.", "author": { "name": "Polar" diff --git a/.github/drift-review.md b/.github/drift-review.md new file mode 100644 index 0000000..20159e2 --- /dev/null +++ b/.github/drift-review.md @@ -0,0 +1,37 @@ +# Weekly skill drift review + +You maintain the Polar agent skills in `skills/`. Coding agents follow them to integrate Polar, so a wrong command, field or claim breaks real integrations. Polar's monorepo is checked out at `../polar`. + +Find and fix significant drift between the skills and what Polar ships. Below this prompt are the results of this repository's checks and the monorepo commits merged since the last review. + +## What to fix + +- Every failing check below. +- Code, commands, flags, fields, event names, environment variables, URLs or dashboard paths that no longer match what Polar ships. +- Claims that contradict Polar's code or docs, such as limits, retry behavior or which events fire. +- A path Polar now recommends instead of the one a skill teaches. + +## What to leave alone + +- Wording, style, formatting and ordering. +- Polar features the skills don't cover yet. +- Anything not released yet. The skills target the latest published `@polar-sh/sdk` and `@polar-sh/cli` (`npm view version`), so ignore `[Unreleased]` changelog entries. The API, MCP server and docs deploy from `main`. +- Anything you can't confirm in `../polar`. A missed fix is cheaper than a wrong one. + +## How to work + +1. Read every `skills/*/SKILL.md`. +2. Triage the commits by subject. For each one that could affect a skill, run `git -C ../polar show --stat `, then `git -C ../polar show -- ` for the files that matter. For SDK and CLI releases, read `../polar/sdk/CHANGELOG.md` and `../polar/clients/packages/cli/CHANGELOG.md`. For SDK usage, the SDK team's reference is `../polar/sdk/typescript/.agents/skills/polar-typescript-sdk/`. +3. Confirm each suspected drift in the current files under `../polar` before you change anything. +4. Edit only `skills/`, `README.md` and `CHANGELOG.md`. Keep each change minimal and match the surrounding style. +5. Run these until they pass, exactly as written, without pipes or `cd`: + - `node .github/scripts/check-plugin.mjs` + - `node .github/scripts/check-samples.mjs` + - `node .github/scripts/check-plugin.mjs --cli ` + - `node .github/scripts/check-plugin.mjs --links` +6. Record the changes as "This run" says: either run `node .github/scripts/bump-version.mjs patch '' ...`, or add the lines to the top section of `CHANGELOG.md`. Write one line per change, for people who use the plugin. +7. Write `DRIFT_SUMMARY.md` in the repository root. It becomes the pull request description: + - One bullet per change: the skill, what was wrong, what it says now, and the evidence. Link evidence as `https://github.com/polarsource/polar/blob//#L`, or name the failing check. + - A short "Checked, no change needed" list of the commits that looked relevant but weren't, one line each. + +If nothing needs fixing, change no files and don't write `DRIFT_SUMMARY.md`. diff --git a/.github/scripts/check-plugin.mjs b/.github/scripts/check-plugin.mjs index f7d26a4..b9ce689 100644 --- a/.github/scripts/check-plugin.mjs +++ b/.github/scripts/check-plugin.mjs @@ -21,6 +21,7 @@ const MAX_TEXT_FILE_BYTES = 256 * 1024; const PIPE_TO_SHELL = /(curl|wget)\b[^\n]*\|\s*(ba|z)?sh\b|\|\s*iex\b/; const JUNK_FILES = /(^|\/)(\.DS_Store|Thumbs\.db|desktop\.ini|__MACOSX)(\/|$)/; const SKILL_NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/; +const MARKDOWN_LINK = /\]\((https?:\/\/[^)\s]+)\)|<(https?:\/\/[^>\s]+)>/g; function checkNames() { for (const path of NAMED_FILES) { @@ -142,10 +143,13 @@ function codeSnippets(text) { return snippets; } +function documents() { + return ["README.md", ...readdirSync("skills").map((directory) => join("skills", directory, "SKILL.md"))]; +} + function cliCommands() { const commands = new Map(); - const documents = ["README.md", ...readdirSync("skills").map((directory) => join("skills", directory, "SKILL.md"))]; - for (const document of documents) { + for (const document of documents()) { for (const snippet of codeSnippets(readFileSync(document, "utf8"))) { for (const [, rest] of snippet.matchAll(/(?:^|[\s($])polar ([^#|;&>)]*)/g)) { const tokens = rest.trim().split(/\s+/); @@ -179,8 +183,34 @@ function checkCli(binary) { } } +function linkStatus(url) { + return fetch(url, { signal: AbortSignal.timeout(20_000) }).then( + (response) => (response.ok ? null : `HTTP ${response.status}`), + (error) => error.cause?.code ?? error.message, + ); +} + +async function checkLinks() { + const links = new Map(); + for (const document of documents()) { + for (const [, markdownUrl, autolinkUrl] of readFileSync(document, "utf8").matchAll(MARKDOWN_LINK)) { + const url = (markdownUrl ?? autolinkUrl).split("#")[0]; + links.set(url, [...new Set([...(links.get(url) ?? []), document])]); + } + } + await Promise.all( + [...links].map(async ([url, linkedFrom]) => { + const status = (await linkStatus(url)) && (await linkStatus(url)); + if (status) fail(`${url} (${linkedFrom.join(", ")}): ${status}`); + else console.log(url); + }), + ); +} + const cliFlag = process.argv.indexOf("--cli"); -if (cliFlag === -1) { +if (process.argv.includes("--links")) { + await checkLinks(); +} else if (cliFlag === -1) { checkNames(); checkVersions(); checkChangelog(); diff --git a/.github/scripts/check-samples.mjs b/.github/scripts/check-samples.mjs new file mode 100644 index 0000000..5f40b11 --- /dev/null +++ b/.github/scripts/check-samples.mjs @@ -0,0 +1,119 @@ +import { execFileSync, spawnSync } from "node:child_process"; +import { mkdtempSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const SDK_VERSION = process.env.POLAR_SDK_VERSION || "latest"; +const DEPENDENCIES = [`@polar-sh/sdk@${SDK_VERSION}`, "typescript@5.9.3", "vitest@3.2.4", "@types/node@24"]; +const FENCE_START = /^(\s*)```(ts|typescript)\s*$/; +const FENCE_END = /^\s*```\s*$/; +const USES_SDK = /@polar-sh\/sdk|\bpolar\.|\bevent\./; +const ELIDED = /^\s*\/\/ \.\.\./m; +const CLIENT = /^export const polar\b/m; +const WEBHOOK_CASE = /^case /; +const TSC_ERROR = /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.*)$/; +const MISSING_RELATIVE_MODULE = /^Cannot find module '\.\.?\//; +const CLIENT_DECLARATION = `declare const polar: typeof import("./polar").polar;\n`; +const PRELUDE = `declare function getUserId(request: Request): Promise; +declare function recordMigratedSubscription(ids: { stripeSubscriptionId: string; polarSubscriptionId: string }): Promise; +declare const polarCustomerId: string; +declare const appCustomerId: string; +declare const productId: string; +declare const email: string; +declare const name: string; +`; +const TSCONFIG = { + compilerOptions: { + target: "es2023", + lib: ["es2023"], + module: "preserve", + moduleResolution: "bundler", + moduleDetection: "force", + resolveJsonModule: true, + strict: true, + noEmit: true, + skipLibCheck: true, + types: ["node"], + }, + include: ["*.ts"], +}; + +function codeBlocks(path) { + const blocks = []; + let block = null; + readFileSync(path, "utf8") + .split("\n") + .forEach((line, index) => { + if (!block) { + const start = line.match(FENCE_START); + if (start) block = { path, line: index + 1, indent: start[1].length, lines: [] }; + } else if (FENCE_END.test(line)) { + blocks.push({ ...block, code: block.lines.join("\n") }); + block = null; + } else { + block.lines.push(line.slice(block.indent)); + } + }); + return blocks; +} + +const documents = readdirSync("skills").map((skill) => join("skills", skill, "SKILL.md")); +const blocks = documents.flatMap(codeBlocks); +const checked = blocks.filter((block) => USES_SDK.test(block.code) && !ELIDED.test(block.code)); +const client = checked.find((block) => CLIENT.test(block.code)); +const sdkModule = client?.code.match(/"(@polar-sh\/sdk[^"]*)"/)?.[1]; +const compiled = checked.filter((block) => sdkModule || !WEBHOOK_CASE.test(block.code)); + +const directory = mkdtempSync(join(tmpdir(), "polar-samples-")); +const files = new Map(); +for (const block of compiled) { + const file = block === client ? "polar.ts" : `${block.path.split("/")[1]}-${block.line}.ts`; + const prefix = WEBHOOK_CASE.test(block.code) + ? [`import { webhooks } from "${sdkModule}";`, "export async function handle(event: webhooks.WebhookPayload) {", "switch (event.type) {"] + : []; + const suffix = prefix.length > 0 ? ["}", "}"] : []; + files.set(file, { ...block, offset: prefix.length }); + writeFileSync(join(directory, file), [...prefix, block.code, ...suffix, ""].join("\n")); +} +writeFileSync(join(directory, "prelude.d.ts"), (client ? CLIENT_DECLARATION : "") + PRELUDE); +writeFileSync(join(directory, "tsconfig.json"), JSON.stringify(TSCONFIG)); + +execFileSync("npm", ["install", "--ignore-scripts", "--no-audit", "--no-fund", "--loglevel=error", ...DEPENDENCIES], { + cwd: directory, + stdio: "inherit", +}); +const sdk = JSON.parse(readFileSync(join(directory, "node_modules/@polar-sh/sdk/package.json"), "utf8")); +console.log(`Type-checking ${compiled.length} of ${blocks.length} TypeScript samples against @polar-sh/sdk ${sdk.version}`); + +const tsc = spawnSync(process.execPath, ["node_modules/typescript/bin/tsc", "--pretty", "false"], { + cwd: directory, + encoding: "utf8", +}); +const errors = tsc.stderr ? [{ location: "tsc", message: tsc.stderr.trim() }] : []; +if (!client) errors.push({ location: "skills", message: "No TypeScript sample exports the `polar` client that the other samples import" }); +for (const output of tsc.stdout.split("\n")) { + if (!output.includes("error TS")) continue; + const match = output.match(TSC_ERROR); + const block = match && files.get(match[1]); + if (!block) { + errors.push({ location: "tsc", message: output }); + continue; + } + const [, , line, column, code, message] = match; + if (code === "TS2307" && MISSING_RELATIVE_MODULE.test(message)) continue; + const documentLine = block.line + Number(line) - block.offset; + errors.push({ + location: `${block.path}:${documentLine}:${Number(column) + block.indent}`, + message: `${code} ${message}`, + annotation: `file=${block.path},line=${documentLine}`, + }); +} + +if (errors.length > 0) { + for (const { location, message, annotation } of errors) { + console.error(`✘ ${location} ${message}`); + if (process.env.GITHUB_ACTIONS && annotation) console.log(`::error ${annotation}::${message}`); + } + process.exit(1); +} +console.log("✔ TypeScript samples compile"); diff --git a/.github/workflows/drift.yml b/.github/workflows/drift.yml new file mode 100644 index 0000000..cd7cd03 --- /dev/null +++ b/.github/workflows/drift.yml @@ -0,0 +1,202 @@ +name: Skill drift review + +on: + schedule: + - cron: "0 7 * * 1" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + actions: write + +concurrency: + group: drift-review + +env: + BRANCH: drift/skills + REVIEWER: sebastianekstrom + MODEL: claude-opus-5-5 + MAX_BUDGET_USD: "10" + POLAR_CLI_TELEMETRY_OPTOUT: "1" + POLAR_PATHS: >- + sdk/CHANGELOG.md sdk/typescript/.agents clients/packages/cli/CHANGELOG.md + clients/apps/mcp clients/adapters docs :!docs/openapi + server/polar/checkout server/polar/customer_session server/polar/webhook + server/polar/license_key server/polar/merchant_migration server/polar/rate_limit.py + +jobs: + review: + runs-on: ubuntu-latest + timeout-minutes: 60 + defaults: + run: + working-directory: toolkit + steps: + - uses: actions/checkout@v7.0.1 + with: + path: toolkit + fetch-depth: 0 + persist-credentials: false + - uses: actions/checkout@v7.0.1 + with: + repository: polarsource/polar + path: polar + fetch-depth: 0 + filter: blob:none + persist-credentials: false + - uses: actions/setup-node@v7.1.0 + with: + node-version: 24 + - run: npm install -g @polar-sh/cli + + - name: Start from the open drift pull request or main + env: + GH_TOKEN: ${{ github.token }} + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + pr=$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number // empty') + echo "PR=$pr" >> "$GITHUB_ENV" + if [ -n "$pr" ]; then + git checkout "$BRANCH" + git merge --no-edit origin/main + else + git checkout -B "$BRANCH" origin/main + fi + + - name: Collect drift signals + id: signals + env: + GH_TOKEN: ${{ github.token }} + run: | + since=$(gh run list --workflow drift.yml --status success --limit 1 --json createdAt --jq '.[0].createdAt // empty') + since=${since:-$(date -u -d '7 days ago' +%FT%TZ)} + base=$(git -C ../polar rev-list -1 --before="$since" HEAD) + git -C ../polar log --format='%h %s' "$base..HEAD" -- $POLAR_PATHS > "$RUNNER_TEMP/commits.txt" + + failed=false + for args in "" "--cli $(command -v polar)" "--links"; do + node .github/scripts/check-plugin.mjs $args >> "$RUNNER_TEMP/checks.txt" 2>&1 || failed=true + done + node .github/scripts/check-samples.mjs >> "$RUNNER_TEMP/checks.txt" 2>&1 || failed=true + cat "$RUNNER_TEMP/checks.txt" + + { + cat .github/drift-review.md + echo + echo "## This run" + echo + echo "- Monorepo commit: $(git -C ../polar rev-parse HEAD)" + echo "- Polar CLI path: $(command -v polar)" + if [ -n "$PR" ]; then + echo "- Pull request #$PR is open and already bumps the version, so add your lines to the top section of \`CHANGELOG.md\`." + else + echo "- No drift pull request is open, so bump the version with \`bump-version.mjs\` if you change anything." + fi + echo + echo "## Commits since the last review on $since" + echo + echo '```' + cat "$RUNNER_TEMP/commits.txt" + echo '```' + echo + echo "## Check results" + echo + if [ "$failed" = true ]; then + echo '```' + cat "$RUNNER_TEMP/checks.txt" + echo '```' + else + echo "All checks pass." + fi + } > "$RUNNER_TEMP/prompt.md" + + if [ "$failed" = false ] && [ ! -s "$RUNNER_TEMP/commits.txt" ]; then + echo "No failing checks and no monorepo changes since $since" + echo "review=false" >> "$GITHUB_OUTPUT" + else + echo "review=true" >> "$GITHUB_OUTPUT" + fi + + - name: Review the skills with Claude + if: steps.signals.outputs.review == 'true' + env: + ANTHROPIC_BASE_URL: https://gateway-us.pydantic.dev/proxy/anthropic + ANTHROPIC_AUTH_TOKEN: ${{ secrets.PYDANTIC_AI_GATEWAY_API_KEY }} + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1" + run: | + npx -y @anthropic-ai/claude-code@2.1.303 -p \ + --model "$MODEL" \ + --max-budget-usd "$MAX_BUDGET_USD" \ + --output-format json \ + --no-session-persistence \ + --strict-mcp-config \ + --permission-mode dontAsk \ + --add-dir ../polar \ + --allowedTools Read Glob Grep Edit Write \ + "Bash(node .github/scripts/check-plugin.mjs:*)" \ + "Bash(node .github/scripts/check-samples.mjs:*)" \ + "Bash(node .github/scripts/bump-version.mjs:*)" \ + "Bash(git -C ../polar show:*)" \ + "Bash(git -C ../polar log:*)" \ + "Bash(git -C ../polar diff:*)" \ + "Bash(git diff:*)" \ + "Bash(git status:*)" \ + "Bash(npm view:*)" \ + --disallowedTools "Edit(.github/**)" "Edit(.git/**)" \ + < "$RUNNER_TEMP/prompt.md" > "$RUNNER_TEMP/claude.json" || true + jq '{subtype, is_error, num_turns, total_cost_usd, permission_denials, result}' "$RUNNER_TEMP/claude.json" + printf 'COST=%.2f\n' "$(jq -r '.total_cost_usd // 0' "$RUNNER_TEMP/claude.json")" >> "$GITHUB_ENV" + jq -e '.is_error == false' "$RUNNER_TEMP/claude.json" > /dev/null + + - name: Open or update the pull request + if: steps.signals.outputs.review == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + if [ -f DRIFT_SUMMARY.md ]; then mv DRIFT_SUMMARY.md "$RUNNER_TEMP/summary.md"; fi + changed=$(git status --porcelain) + if [ -z "$changed" ]; then + echo "No significant drift" + exit 0 + fi + if [ ! -f "$RUNNER_TEMP/summary.md" ]; then + echo "::error::Claude changed files without writing DRIFT_SUMMARY.md" + exit 1 + fi + unexpected=$(echo "$changed" | cut -c4- | grep -vE '^(skills/|README\.md$|CHANGELOG\.md$|\.claude-plugin/plugin\.json$|\.cursor-plugin/plugin\.json$|openai/plugin\.json$|gemini-extension\.json$)' || true) + if [ -n "$unexpected" ]; then + echo "::error::Claude changed files outside the skills: $unexpected" + exit 1 + fi + + node .github/scripts/check-plugin.mjs + node .github/scripts/check-samples.mjs + node .github/scripts/check-plugin.mjs --cli "$(command -v polar)" + node .github/scripts/check-plugin.mjs --links + if [ "$(jq -r .version .claude-plugin/plugin.json)" = "$(git show origin/main:.claude-plugin/plugin.json | jq -r .version)" ]; then + echo "::error::The version wasn't bumped" + exit 1 + fi + + git add -A + git commit -m "Fix skill drift" + gh auth setup-git + git push --force-with-lease origin "HEAD:$BRANCH" + + { + cat "$RUNNER_TEMP/summary.md" + echo + echo "---" + echo + echo "Found by the [weekly drift review]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) for \$$COST. After merging, update the listings as described in [RELEASE.md]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/blob/main/RELEASE.md)." + echo + echo "@$REVIEWER" + } > "$RUNNER_TEMP/body.md" + if [ -n "$PR" ]; then + gh pr comment "$PR" --body-file "$RUNNER_TEMP/body.md" + else + gh pr create --base main --head "$BRANCH" --title "Fix skill drift" --body-file "$RUNNER_TEMP/body.md" --reviewer "$REVIEWER" + fi + gh workflow run validate.yml --ref "$BRANCH" diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index fdce4c2..1f8151b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -4,6 +4,7 @@ on: pull_request: push: branches: [main] + workflow_dispatch: permissions: contents: read @@ -32,6 +33,26 @@ jobs: - run: npm install -g @polar-sh/cli - run: node .github/scripts/check-plugin.mjs --cli "$(command -v polar)" + samples: + name: TypeScript samples against the published SDK + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7.0.1 + - uses: actions/setup-node@v7.1.0 + with: + node-version: 24 + - run: node .github/scripts/check-samples.mjs + + links: + name: Links in docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7.0.1 + - uses: actions/setup-node@v7.1.0 + with: + node-version: 24 + - run: node .github/scripts/check-plugin.mjs --links + claude: name: Claude Code runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 22b2e7b..440707b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.2.0 + +- Update the skills to `@polar-sh/sdk` 1.x +- Rewrite `polar-migration` around Polar's assisted Stripe migration + ## 0.1.0 - First release: the Polar MCP servers (`polar` and `polar-sandbox`) and the `setup-polar`, `polar-integration`, `polar-testing` and `polar-migration` skills, for Claude Code, Codex, Cursor, Gemini CLI and Antigravity. diff --git a/README.md b/README.md index 1f61259..2416b68 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Then connect the MCP server by following the [Polar MCP guide](https://polar.sh/ ## Data and privacy -The plugin contains instructions and MCP server configuration only. It runs no scripts or hooks on your machine and sends no telemetry itself. The script in `.github/` only runs in this repository's CI. +The plugin contains instructions and MCP server configuration only. It runs no scripts or hooks on your machine and sends no telemetry itself. The scripts in `.github/` are for maintaining this repository, and the plugin never runs them. When you use the MCP servers, your agent sends requests to `mcp.polar.sh` over HTTPS. They read and change data in the Polar organization you authorized, such as products, customers, subscriptions and orders, within the permissions you granted. To disconnect, clear the server's authentication in `/mcp` in Claude Code, run `codex mcp logout ` in Codex, or uninstall the plugin. Polar handles this data under its [Privacy Policy](https://polar.sh/legal/privacy-policy) and [Terms of Service](https://polar.sh/legal/master-services-terms). diff --git a/RELEASE.md b/RELEASE.md index cb2da42..c3cd360 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -7,7 +7,7 @@ Every release gets a version number, a changelog entry, a `vX.Y.Z` tag and a Git On a new branch from `main`, run: ```bash -node .github/scripts/bump-version.mjs patch 'Change 1', 'Change 2' +node .github/scripts/bump-version.mjs patch 'Change 1' 'Change 2' ``` Use `patch`, `minor` or `major`, or an exact version such as `0.2.0`. Each quoted argument becomes one bullet. Use single quotes so backticks stay literal. @@ -25,7 +25,7 @@ The [Validate plugin](https://github.com/polarsource/agent-toolkit/actions/workf Merging runs the [Release](https://github.com/polarsource/agent-toolkit/actions/workflows/release.yml) workflow, which creates the `vX.Y.Z` tag, the GitHub release with your changelog notes, and the `polar-openai-X.Y.Z` ZIP. -## 3. Update each listing +## 4. Update each listing | Where | What to do | | --- | --- | diff --git a/gemini-extension.json b/gemini-extension.json index c2b31fd..b73e742 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "polar", - "version": "0.1.0", + "version": "0.2.0", "description": "Add Polar payments, subscriptions and usage billing to your app. Connects to your Polar organization through the Polar MCP server and adds skills for setup, Checkout and webhook integration, and sandbox testing.", "mcpServers": { "polar": { diff --git a/openai/plugin.json b/openai/plugin.json index a4d7719..3eff574 100644 --- a/openai/plugin.json +++ b/openai/plugin.json @@ -1,6 +1,6 @@ { "name": "polar", - "version": "0.1.0", + "version": "0.2.0", "description": "Add Polar payments, subscriptions and usage billing to your app. Connects to your Polar organization and adds skills for setup, integration, testing and migrating from other payment platforms.", "author": { "name": "Polar",