Skip to content
Merged
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
10 changes: 10 additions & 0 deletions apps/desktop/src/main/plugins/__tests__/githubInstall.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ describe('parseConnectSpec', () => {
owner: 'dripnex',
repo: 'plugin-math',
});
expect(parseConnectSpec('theme-parchment')).toEqual({
kind: 'github',
owner: 'dripnex',
repo: 'theme-parchment',
});
expect(parseConnectSpec('theme-harbor-dusk')).toEqual({
kind: 'github',
owner: 'dripnex',
repo: 'theme-harbor-dusk',
});
expect(parseConnectSpec('dripnex/plugin-vim')).toEqual({
kind: 'github',
owner: 'dripnex',
Expand Down
14 changes: 14 additions & 0 deletions apps/desktop/src/main/plugins/githubInstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ export const OFFICIAL_PACK_REPOS: Record<string, `${string}/${string}`> = {
mermaid: 'dripnex/plugin-mermaid',
math: 'dripnex/plugin-math',
stamp: 'dripnex/plugin-stamp',
'theme-parchment': 'dripnex/theme-parchment',
'theme-harbor-dusk': 'dripnex/theme-harbor-dusk',
'theme-wave': 'dripnex/theme-wave',
'theme-night': 'dripnex/theme-night',
'theme-solarized-dark': 'dripnex/theme-solarized-dark',
'theme-solarized-light': 'dripnex/theme-solarized-light',
'theme-gruvbox': 'dripnex/theme-gruvbox',
'theme-glass': 'dripnex/theme-glass',
'theme-midnight': 'dripnex/theme-midnight',
'theme-ember': 'dripnex/theme-ember',
'theme-ion': 'dripnex/theme-ion',
'theme-matcha': 'dripnex/theme-matcha',
'theme-phosphor': 'dripnex/theme-phosphor',
'theme-fog': 'dripnex/theme-fog',
};

export function officialRepoForSlug(slug: string): { owner: string; repo: string } | null {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,45 @@ describe('mergeFallbackCatalog', () => {
expect.arrayContaining(['dripnex-vim-mode', 'mermaid', 'math'])
);
});

it('keeps packed satellite themes when the live registry omitted them', () => {
const packed = [
'theme-parchment',
'theme-harbor-dusk',
'theme-wave',
'theme-night',
'theme-solarized-dark',
'theme-solarized-light',
'theme-gruvbox',
'theme-glass',
'theme-midnight',
'theme-ember',
'theme-ion',
'theme-matcha',
'theme-phosphor',
'theme-fog',
];
for (const id of packed) {
const row = COMMUNITY_CATALOG.find(p => p.id === id);
expect(row?.repository).toBe(`dripnex/${id}`);
}
const merged = mergeFallbackCatalog([
{
slug: 'stamp',
name: 'Stamp',
description: '',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/plugin-stamp',
},
]);
expect(merged.find(p => p.slug === 'theme-harbor-dusk')?.repository).toBe(
'dripnex/theme-harbor-dusk'
);
expect(installSpecFor(merged.find(p => p.slug === 'theme-harbor-dusk')!)).toBe(
'dripnex/theme-harbor-dusk'
);
});
});

describe('matchRemoteForInstalled', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/**
* First-party community plugins. Same shape as Inkdrop: one git repo per
* plugin, installed from its GitHub release tarball. Not a fake marketplace —
* only list plugins that actually exist as public repos with a release.
* only list plugins that actually exist as public repos WITH a GitHub Release
* tarball (`{id}-{version}.tar.gz`). A git tag alone is not enough.
*
* Live Browse comes from GET /plugins on the Worker (dripnex theme-* /
* plugin-* repos with a packed Release tarball). This array is the offline
* fallback when that API is unreachable — do not generate it from GitHub
* in the renderer.
*
* Three strings are not interchangeable (#562):
* id — manifest.json / scan().id (folder name after install)
Expand Down Expand Up @@ -54,6 +60,118 @@ export const COMMUNITY_CATALOG: CatalogPlugin[] = [
author: 'Dripnex',
repository: 'dripnex/plugin-stamp',
},
{
id: 'theme-parchment',
name: 'Parchment',
description: 'Warm paper palette. Official Dripnex theme.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-parchment',
},
{
id: 'theme-harbor-dusk',
name: 'Harbor Dusk',
description: 'Coastal evening palette for long writing sessions.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-harbor-dusk',
},
{
id: 'theme-wave',
name: 'Wave',
description: 'Ink and paper, after dark.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-wave',
},
{
id: 'theme-night',
name: 'Night',
description: 'Violet dusk. Focused writing after hours.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-night',
},
{
id: 'theme-solarized-dark',
name: 'Solarized Dark',
description: 'Ethan Schoonover. The Vim classic.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-solarized-dark',
},
{
id: 'theme-solarized-light',
name: 'Solarized Light',
description: 'Cream paper, cyan marks. Same palette, daylight.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-solarized-light',
},
{
id: 'theme-gruvbox',
name: 'Gruvbox',
description: 'Retro groove. The other Vim default.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-gruvbox',
},
{
id: 'theme-glass',
name: 'Glass',
description: 'Ice. The desktop shows through.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-glass',
},
{
id: 'theme-midnight',
name: 'Midnight',
description: 'OLED navy, electric blue. Frosted.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-midnight',
},
{
id: 'theme-ember',
name: 'Ember',
description: 'Warm black, copper light. Frosted.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-ember',
},
{
id: 'theme-ion',
name: 'Ion',
description: 'Violet glass. Linear-adjacent, frosted.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-ion',
},
{
id: 'theme-matcha',
name: 'Matcha',
description: 'Green-tea paper. Calm reading.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-matcha',
},
{
id: 'theme-phosphor',
name: 'Phosphor',
description: 'Amber CRT. Terminal glow after midnight.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-phosphor',
},
{
id: 'theme-fog',
name: 'Fog',
description: 'Coastal gray morning. Muted blue marks.',
version: '0.1.0',
author: 'Dripnex',
repository: 'dripnex/theme-fog',
},
];

export interface CatalogCard {
Expand Down
12 changes: 6 additions & 6 deletions docs/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

Desktop-only. Phone v1 has no plugin path (`docs/mobile/PLAN.md`).

| Doc | What it is |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [install-path.md](./install-path.md) | Decision: official slug ≡ GitHub `owner/repo`; CLI and packaged app share `Dripnex` userData ([#547](https://github.com/dripnex/app/issues/547) / [#562](https://github.com/dripnex/app/issues/562)) |
| [official-first-party.md](./official-first-party.md) | Research: install/load today, [#547](https://github.com/dripnex/app/issues/547) / [#562](https://github.com/dripnex/app/issues/562) vim slug bug, GFM/editor gaps, ranked next official packs |
| [../PLUGIN_SYSTEM.md](../PLUGIN_SYSTEM.md) | Implementation roadmap (phases 1–4 done). Phase 5 marketplace is later. |
| [../tables-plugin.md](../tables-plugin.md) | How the **built-in** tables plugin works (not a satellite pack) |
| Doc | What it is |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [install-path.md](./install-path.md) | Official slug ≡ GitHub `owner/repo`; satellite publish is `dripnex-plugin pack` → Release `{id}-{version}.tar.gz` → `FIRST_PARTY_PACKAGES` / `COMMUNITY_CATALOG`. Shared `Dripnex` userData ([#547](https://github.com/dripnex/app/issues/547) / [#562](https://github.com/dripnex/app/issues/562)) |
| [official-first-party.md](./official-first-party.md) | Research: install/load today, [#547](https://github.com/dripnex/app/issues/547) / [#562](https://github.com/dripnex/app/issues/562) vim slug bug, GFM/editor gaps, ranked next official packs |
| [../PLUGIN_SYSTEM.md](../PLUGIN_SYSTEM.md) | Implementation roadmap (phases 1–4 done). Phase 5 marketplace is later. |
| [../tables-plugin.md](../tables-plugin.md) | How the **built-in** tables plugin works (not a satellite pack) |

Do not treat `docs/archived/plans-2026/2026-02-19-phase2-plugin-marketplace.md` or issues #315–#343 as a plan. [#542](https://github.com/dripnex/app/issues/542) marks that June dump stale.
16 changes: 16 additions & 0 deletions docs/plugins/install-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,20 @@ Three strings are not interchangeable:

Browse merges the first-party catalog into the live list so Vim cannot vanish when the API omits it. Updates match `scan().id` to registry slug **or** the same GitHub repository.

## Satellite publish path

Inkdrop-style: the registry is the index, the GitHub Release tarball is the artifact. No marketplace.

1. `dripnex-plugin pack` writes `{id}-{version}.tar.gz` (`manifest.id`, not the repo name).
2. Attach that archive to a GitHub Release (`gh release create vX.Y.Z {id}-{version}.tar.gz`).
3. Seed the index in this repo (GitHub-down fallback + slug/name overrides):
- Live `GET /plugins`: `FIRST_PARTY_PACKAGES` in `packages/api/src/routes/plugins.ts`. Deploy with `packages/api` — production is `pnpm --filter @dripnex/api deploy:production` / `.github/workflows/deploy-api.yml` on `main`.
- Browse fallback: `COMMUNITY_CATALOG` in `apps/desktop/src/renderer/pages/settings/sections/plugins/communityCatalog.ts`. `id` must equal `manifest.json` `id`; `repository` is `owner/repo`.

Do not list a pack until the Release has the packed tarball — Browse Install would 404. A git tag alone is not enough. Official palettes stay in `OFFICIAL_THEMES`; satellite themes are packs, not core.

Same three-string rule as Vim. Parchment: id `theme-parchment`, repo `dripnex/theme-parchment`, asset `theme-parchment-0.1.0.tar.gz` on `v0.1.0`.

**First-party Browse auto-list:** `GET /plugins` on the Worker (`packages/api`) discovers public `dripnex/theme-*` and `dripnex/plugin-*` repos whose latest GitHub Release has a packed `.tar.gz` asset (the `{id}-{version}.tar.gz` parchment pattern — never the git tag source tarball). A satellite that only publishes that Release appears in Browse without editing `FIRST_PARTY_PACKAGES`. That seed is the GitHub-down fallback and the slug/name override map (`dripnex-vim-mode` → `dripnex/plugin-vim`). Community marketplace / `services/plugin-registry` (#389 / #397 / #422) is still out.

**userData:** CLI and the packaged app share one folder. Electron would follow package.json `name` `@dripnex/desktop` (`~/.config/@dripnex/desktop`) unless main calls `app.setName('Dripnex')` and `app.setPath('userData', resolveUserDataRoot())` before `createDataPaths` (#572). Default: `~/.config/Dripnex`, `%APPDATA%/Dripnex`, `~/Library/Application Support/Dripnex`. Then `@dripnex/desktop`, then legacy `dripnex`. If more than one exists, prefer `dripnex.db`, then `plugins/` — no silent copy. Overrides: `DRIPNEX_DATA_DIR`, `--user-data-dir`.
24 changes: 24 additions & 0 deletions docs/releases/v0.19.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
version: 0.19.0
date: 2026-08-25
title: Satellite themes in Browse
status: draft
---

Settings → Plugins → Browse lists first-party Dripnex theme and plugin packs
when their latest GitHub Release includes a packed `.tar.gz`. You no longer
have to type those specs by hand. This is not a public community marketplace.

## Plugins

- **Browse auto-lists first-party packs.** `GET /plugins` discovers public
`dripnex/theme-*` and `dripnex/plugin-*` repos whose latest GitHub Release
has a packed `{id}-{version}.tar.gz`. A git tag without that asset is
skipped. Random org repos are not listed.
- **Fallback seed.** If the API is unreachable, Browse still shows parchment
and the packed satellite themes in the desktop catalog.
- **Already on 0.18.0.** Install the same packs today from Other package:
`dripnex/theme-<slug>`. 0.19.0 is Browse listing them.

Official palettes on Settings → Themes are unchanged. Satellite themes stay
packs, not core.
4 changes: 4 additions & 0 deletions packages/api/.dev.vars
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@ STRIPE_WEBHOOK_SECRET="whsec_your_secret_here"
# Put the PRIVATE here (and as the Cloudflare secret in production/staging)
LICENSE_SIGNING_PRIVATE_KEY="hex-encoded-32-byte-ed25519-private-key"

# Optional. GitHub token for first-party Browse discovery (theme-*/plugin-*
# org repos). Unauthenticated public API still works; the token avoids rate limits.
# GITHUB_TOKEN=""

# Environment
ENVIRONMENT="development"
3 changes: 3 additions & 0 deletions packages/api/SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ RESEND_API_KEY="re_your_key_here"
# Stripe (get from: https://dashboard.stripe.com/webhooks)
STRIPE_WEBHOOK_SECRET="whsec_your_secret_here"

# Optional: GitHub token for first-party Browse discovery
# GITHUB_TOKEN="ghp_..."

# Environment
ENVIRONMENT="development"
```
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/db/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export type Env = {
STRIPE_PRICE_ANNUAL?: string;
SITE_URL?: string;
ADMIN_TOKEN?: string;
/** Optional. Raises GitHub REST rate limits for first-party Browse discovery. */
GITHUB_TOKEN?: string;
ENVIRONMENT: string;
// Rate limiting bindings (optional so unit tests / local runs without the
// binding fail open rather than crash — see middleware/rateLimit.ts).
Expand Down
Loading
Loading