Skip to content

feat(studio): make the marketplace Install actually install#73

Merged
NagyVikt merged 5 commits into
mainfrom
claude/dashboard-marketplace-full-rog0bn
Jun 24, 2026
Merged

feat(studio): make the marketplace Install actually install#73
NagyVikt merged 5 commits into
mainfrom
claude/dashboard-marketplace-full-rog0bn

Conversation

@NagyVikt

Copy link
Copy Markdown
Contributor

What

The studio Market page already browses, searches, filters, sorts, stars, and "publishes" — but its central action was a stub: the Install → Add to profile picker only flashed a toast and never wrote anything. This PR makes the marketplace fully functional by wiring Install end-to-end so picking a profile actually edits that profile's profile.yaml.

How

Backend

  • src/lib/market-install.ts — new installMarketItem() that edits profiles/<name>/profile.yaml in place, idempotently, mirroring addMcpToProfile's profile validation + path-traversal guard. Each item type routes to its real home:
    addKind where it lands
    skill skills.npx ({ repo, skills: [name] }, repo parsed from the install command)
    mcp mcps (reuses the existing addMcpToProfile)
    plugin plugins
    profile inherits (expands a scalar inherits: core into a list)
    workflow playbooks
    cli no profile.yaml home → returns a manual command for the UI to surface
    • Keeps the file human-authored: splices YAML list items instead of round-tripping through a serializer that would reflow comments/quoting. Creates the skills:/npx: scaffold when absent.
  • dashboard-server.tshandleMarketInstall() + POST /api/v1/market/install on the existing write-side allowlist; busts the market cache on a real edit.

Frontend

  • api.tsinstallMarketItem() helper + MarketInstallResult type.
  • Market.tsx — the picker now calls the endpoint and reports pending / success / already-present / manual (CLI) / error in the toast, then invalidates the profiles-full, profile-detail, and market queries so the rest of the studio reflects the new membership. Local unpublished drafts are blocked from install with a clear message.

Tests

  • market-install.test.ts — every addKind (write + idempotency), scalar-inherits expansion, self-inherit guard, CLI manual path, traversal + missing-profile rejection. Runs against a throwaway CUE_PROFILES_DIR fixture, never the real profiles/.
  • dashboard-server.test.ts — request validation for the new handler (missing-id, invalid-add-kind, missing-profile, CLI manual).

All new tests pass (bun test), the web app builds (vite build), and biome lint is clean on the changed files. The pre-existing suite failures (missing generated resources/mcps/configs/ + network-gated tests) are unchanged by this PR.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 4 commits June 22, 2026 09:38
The studio Market page listed everything addable to a profile but the
"Add to profile" picker only flashed a toast — it never wrote anything.
This wires it end-to-end so installing a marketplace item edits the
target profile.yaml for real.

- src/lib/market-install.ts: installMarketItem() edits profile.yaml in
  place, idempotently, mirroring addMcpToProfile's validation + path
  guard. Routes each addKind to its home — skill → skills.npx,
  mcp → mcps (reuses addMcpToProfile), plugin → plugins,
  profile → inherits (expands a scalar into a list), workflow →
  playbooks. A bare CLI has no profile.yaml home, so it returns a
  `manual` command for the studio to surface instead.
- dashboard-server: handleMarketInstall + POST /api/v1/market/install,
  on the existing write-side allowlist; busts the market cache on a
  real edit.
- web: installMarketItem() api helper + Market.tsx wires the picker to
  call it, shows pending/success/already-present/manual/error in the
  toast, and invalidates the profiles/detail/market queries so the
  rest of the studio reflects the new membership.
- Tests for every addKind (write + idempotency + traversal guard) and
  the handler's request validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178QDX7Jk7CkdGgH7uKfamv
CI was failing at the actions/checkout submodule step for every PR
(and on main since #71): the resources/skills gitlink pinned
4274beaece3a38a4a7a85142b2f09f2b23e3ce89, which no longer exists on
opencue/skills.git (force-pushed / GC'd), so `submodule update` aborted
before lint/test/e2e could run.

Bump the gitlink to a452e5d2892d59d766b1927c9d35a6f806bce79e, the
current tip of the tracked `soul-main` branch, so checkout succeeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178QDX7Jk7CkdGgH7uKfamv
buildUniversalSuggestions spreads UNIVERSAL_DEFAULTS over the caller's
opts, but the defaults object was missing pinnedCompanions, which became
a required key of `Required<Omit<BuildUniversalOptions, ...>>` once that
field was added — so `tsc --noEmit` failed. Default it to
UNIVERSAL_COMPANIONS (the documented default), so the spread actually
supplies it and the type is satisfied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178QDX7Jk7CkdGgH7uKfamv
… skills)

The previous bump pointed resources/skills at soul-main's tip, but that
branch is mid-vault-migration and no longer contains skills the catalog
references — e.g. core/profile.yaml uses tools/ccusage and tools/headroom,
which exist only on the skills repo's `main` branch. That made every
profile fail the e2e resolver dry-run (E3 missing reference).

Repoint the gitlink to opencue/skills main (3c6b2569) and update
.gitmodules to track `branch = main` so `--remote` refreshes stay on the
canonical catalog. `cue validate --all` now passes (exit 0, warnings only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178QDX7Jk7CkdGgH7uKfamv
@NagyVikt NagyVikt marked this pull request as ready for review June 24, 2026 09:03
# Conflicts:
#	resources/skills
#	web/src/studio/views/Market.tsx
@NagyVikt NagyVikt merged commit 233a881 into main Jun 24, 2026
4 checks passed
@NagyVikt NagyVikt deleted the claude/dashboard-marketplace-full-rog0bn branch June 24, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants