feat(marketplace): publish skills/profiles/MCPs from your PC via API token#74
Merged
Merged
Conversation
…token Adds the missing "push to marketplace" path so a user can mint an API token on cuecards.cc and publish from their own machine. Hosted API (web/): - web/lib/db.ts: shared pg pool (singleton, serverless-safe). - web/lib/market.ts: getMarket()/publishMarket(), Postgres-backed, authenticated via auth.api.getSession (session cookie OR Bearer api-key). Install commands are derived server-side (never trusted from the client), every field is clamped/slugged, ids carry a per-user suffix and (user_id, type, name) is unique so re-publishing updates your own item and can't overwrite another user's. Schema is created lazily. - web/api/v1/community.ts: Vercel function (GET list / GET ?mine / POST). - dev-server + check-auth-flow now cover publish + list (the e2e gate). - vite proxy routes /api/v1/community to the auth server in dev. CLI (src/): - cue marketplace login | whoami | publish <type> <name>. - src/lib/cue-credentials.ts: token store (~/.config/cue/credentials.json, 0600), resolution order flag > CUE_API_TOKEN > file; CUE_API_URL / --api override the endpoint. Unit-tested. Studio (web/src/): - Market view: Publish modal now pushes to the hosted API when signed in (falls back to a local draft otherwise), and the browse list merges the community catalog with "yours" flagging. Docs: README "## API" section + updated web/AUTH.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0153P8DbBQg1yPQYhBv8JiWg
The pinned gitlink (4274beae) was force-pushed away on opencue/skills, so actions/checkout failed fetching the submodule on every job — repo-wide, before tests/lint ran. Bump to a452e5d (current soul-main head) so CI can fetch submodules and actually run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0153P8DbBQg1yPQYhBv8JiWg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Users could already mint an API token on cuecards.cc (BetterAuth
apiKey+ the studio API view), but the only thing they could do with it wasGET /api/v1/me. The marketplace Publish button was a localStorage-only stub ("will open a registry PR later").This PR closes the loop: a user gets a token and pushes their skills, cue profiles, and MCPs to the marketplace from their own machine — via the CLI or the studio.
Hosted API (
web/)web/lib/db.ts— shared, serverless-safepgpool singleton (BetterAuth keeps its own).web/lib/market.ts—getMarket()/publishMarket(), Postgres-backed, authenticated throughauth.api.getSessionso a session cookie ORAuthorization: Bearer <api-key>both work (same path as/api/v1/me). Security-minded by design:cue add <handle>/<name>,cue marketplace install-mcp <name>, …) and never read from the request → a submission can't smugglecurl … | bashinto someone's dashboard;sourceUrlmust behttps://;idembeds a per-user suffix and(user_id, type, name)is unique → re-publishing updates your item and can't overwrite another user's;web/api/v1/community.ts— Vercel function:GET(public list),GET ?mine=1(your items, any status),POST(publish). Kept on a distinct path from the local dashboard's/api/v1/marketbrowse catalog so both coexist.check-auth-flow.tsnow exercise publish + list end-to-end (the existing auth gate, extended)./api/v1/communityto the auth server in dev.CLI (
src/)src/lib/cue-credentials.ts— token store + resolution order--token>CUE_API_TOKEN> file;CUE_API_URL/--apipoint at a different deployment. Unit-tested.Studio (
web/src/)Testing
bun test src/lib/cue-credentials.test.ts→ 5 pass (resolution order, 0600 perms, URL precedence).tscclean for all touched files (one pre-existing unrelated error inpair-suggestions.ts).srctscclean for touched files (one pre-existing unrelated error instudio/components/index.tsx).publish/whoamierror paths verified;marketplace --helpupdated.web/scripts/check-auth-flow.ts(needsDATABASE_URL+BETTER_AUTH_SECRETto run live).Notes / follow-ups
status = 'approved'(matches the existing free-signup, no-email-verification posture); thestatuscolumn is the hook for moderation later without a schema change.## APIsection inREADME.md+ expandedweb/AUTH.md.🤖 Generated with Claude Code
Generated by Claude Code