Skip to content

Commit 31945f8

Browse files
authored
Merge pull request #600 from dripnex/develop
chore(release): promote 0.19.0
2 parents 2c71519 + 83d655f commit 31945f8

16 files changed

Lines changed: 1171 additions & 35 deletions

File tree

apps/desktop/src/main/plugins/__tests__/githubInstall.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ describe('parseConnectSpec', () => {
4848
owner: 'dripnex',
4949
repo: 'plugin-math',
5050
});
51+
expect(parseConnectSpec('theme-parchment')).toEqual({
52+
kind: 'github',
53+
owner: 'dripnex',
54+
repo: 'theme-parchment',
55+
});
56+
expect(parseConnectSpec('theme-harbor-dusk')).toEqual({
57+
kind: 'github',
58+
owner: 'dripnex',
59+
repo: 'theme-harbor-dusk',
60+
});
5161
expect(parseConnectSpec('dripnex/plugin-vim')).toEqual({
5262
kind: 'github',
5363
owner: 'dripnex',

apps/desktop/src/main/plugins/githubInstall.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@ export const OFFICIAL_PACK_REPOS: Record<string, `${string}/${string}`> = {
1212
mermaid: 'dripnex/plugin-mermaid',
1313
math: 'dripnex/plugin-math',
1414
stamp: 'dripnex/plugin-stamp',
15+
'theme-parchment': 'dripnex/theme-parchment',
16+
'theme-harbor-dusk': 'dripnex/theme-harbor-dusk',
17+
'theme-wave': 'dripnex/theme-wave',
18+
'theme-night': 'dripnex/theme-night',
19+
'theme-solarized-dark': 'dripnex/theme-solarized-dark',
20+
'theme-solarized-light': 'dripnex/theme-solarized-light',
21+
'theme-gruvbox': 'dripnex/theme-gruvbox',
22+
'theme-glass': 'dripnex/theme-glass',
23+
'theme-midnight': 'dripnex/theme-midnight',
24+
'theme-ember': 'dripnex/theme-ember',
25+
'theme-ion': 'dripnex/theme-ion',
26+
'theme-matcha': 'dripnex/theme-matcha',
27+
'theme-phosphor': 'dripnex/theme-phosphor',
28+
'theme-fog': 'dripnex/theme-fog',
1529
};
1630

1731
export function officialRepoForSlug(slug: string): { owner: string; repo: string } | null {

apps/desktop/src/renderer/pages/settings/sections/plugins/__tests__/communityCatalog.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,45 @@ describe('mergeFallbackCatalog', () => {
8989
expect.arrayContaining(['dripnex-vim-mode', 'mermaid', 'math'])
9090
);
9191
});
92+
93+
it('keeps packed satellite themes when the live registry omitted them', () => {
94+
const packed = [
95+
'theme-parchment',
96+
'theme-harbor-dusk',
97+
'theme-wave',
98+
'theme-night',
99+
'theme-solarized-dark',
100+
'theme-solarized-light',
101+
'theme-gruvbox',
102+
'theme-glass',
103+
'theme-midnight',
104+
'theme-ember',
105+
'theme-ion',
106+
'theme-matcha',
107+
'theme-phosphor',
108+
'theme-fog',
109+
];
110+
for (const id of packed) {
111+
const row = COMMUNITY_CATALOG.find(p => p.id === id);
112+
expect(row?.repository).toBe(`dripnex/${id}`);
113+
}
114+
const merged = mergeFallbackCatalog([
115+
{
116+
slug: 'stamp',
117+
name: 'Stamp',
118+
description: '',
119+
version: '0.1.0',
120+
author: 'Dripnex',
121+
repository: 'dripnex/plugin-stamp',
122+
},
123+
]);
124+
expect(merged.find(p => p.slug === 'theme-harbor-dusk')?.repository).toBe(
125+
'dripnex/theme-harbor-dusk'
126+
);
127+
expect(installSpecFor(merged.find(p => p.slug === 'theme-harbor-dusk')!)).toBe(
128+
'dripnex/theme-harbor-dusk'
129+
);
130+
});
92131
});
93132

94133
describe('matchRemoteForInstalled', () => {

apps/desktop/src/renderer/pages/settings/sections/plugins/communityCatalog.ts

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/**
22
* First-party community plugins. Same shape as Inkdrop: one git repo per
33
* plugin, installed from its GitHub release tarball. Not a fake marketplace —
4-
* only list plugins that actually exist as public repos with a release.
4+
* only list plugins that actually exist as public repos WITH a GitHub Release
5+
* tarball (`{id}-{version}.tar.gz`). A git tag alone is not enough.
6+
*
7+
* Live Browse comes from GET /plugins on the Worker (dripnex theme-* /
8+
* plugin-* repos with a packed Release tarball). This array is the offline
9+
* fallback when that API is unreachable — do not generate it from GitHub
10+
* in the renderer.
511
*
612
* Three strings are not interchangeable (#562):
713
* id — manifest.json / scan().id (folder name after install)
@@ -54,6 +60,118 @@ export const COMMUNITY_CATALOG: CatalogPlugin[] = [
5460
author: 'Dripnex',
5561
repository: 'dripnex/plugin-stamp',
5662
},
63+
{
64+
id: 'theme-parchment',
65+
name: 'Parchment',
66+
description: 'Warm paper palette. Official Dripnex theme.',
67+
version: '0.1.0',
68+
author: 'Dripnex',
69+
repository: 'dripnex/theme-parchment',
70+
},
71+
{
72+
id: 'theme-harbor-dusk',
73+
name: 'Harbor Dusk',
74+
description: 'Coastal evening palette for long writing sessions.',
75+
version: '0.1.0',
76+
author: 'Dripnex',
77+
repository: 'dripnex/theme-harbor-dusk',
78+
},
79+
{
80+
id: 'theme-wave',
81+
name: 'Wave',
82+
description: 'Ink and paper, after dark.',
83+
version: '0.1.0',
84+
author: 'Dripnex',
85+
repository: 'dripnex/theme-wave',
86+
},
87+
{
88+
id: 'theme-night',
89+
name: 'Night',
90+
description: 'Violet dusk. Focused writing after hours.',
91+
version: '0.1.0',
92+
author: 'Dripnex',
93+
repository: 'dripnex/theme-night',
94+
},
95+
{
96+
id: 'theme-solarized-dark',
97+
name: 'Solarized Dark',
98+
description: 'Ethan Schoonover. The Vim classic.',
99+
version: '0.1.0',
100+
author: 'Dripnex',
101+
repository: 'dripnex/theme-solarized-dark',
102+
},
103+
{
104+
id: 'theme-solarized-light',
105+
name: 'Solarized Light',
106+
description: 'Cream paper, cyan marks. Same palette, daylight.',
107+
version: '0.1.0',
108+
author: 'Dripnex',
109+
repository: 'dripnex/theme-solarized-light',
110+
},
111+
{
112+
id: 'theme-gruvbox',
113+
name: 'Gruvbox',
114+
description: 'Retro groove. The other Vim default.',
115+
version: '0.1.0',
116+
author: 'Dripnex',
117+
repository: 'dripnex/theme-gruvbox',
118+
},
119+
{
120+
id: 'theme-glass',
121+
name: 'Glass',
122+
description: 'Ice. The desktop shows through.',
123+
version: '0.1.0',
124+
author: 'Dripnex',
125+
repository: 'dripnex/theme-glass',
126+
},
127+
{
128+
id: 'theme-midnight',
129+
name: 'Midnight',
130+
description: 'OLED navy, electric blue. Frosted.',
131+
version: '0.1.0',
132+
author: 'Dripnex',
133+
repository: 'dripnex/theme-midnight',
134+
},
135+
{
136+
id: 'theme-ember',
137+
name: 'Ember',
138+
description: 'Warm black, copper light. Frosted.',
139+
version: '0.1.0',
140+
author: 'Dripnex',
141+
repository: 'dripnex/theme-ember',
142+
},
143+
{
144+
id: 'theme-ion',
145+
name: 'Ion',
146+
description: 'Violet glass. Linear-adjacent, frosted.',
147+
version: '0.1.0',
148+
author: 'Dripnex',
149+
repository: 'dripnex/theme-ion',
150+
},
151+
{
152+
id: 'theme-matcha',
153+
name: 'Matcha',
154+
description: 'Green-tea paper. Calm reading.',
155+
version: '0.1.0',
156+
author: 'Dripnex',
157+
repository: 'dripnex/theme-matcha',
158+
},
159+
{
160+
id: 'theme-phosphor',
161+
name: 'Phosphor',
162+
description: 'Amber CRT. Terminal glow after midnight.',
163+
version: '0.1.0',
164+
author: 'Dripnex',
165+
repository: 'dripnex/theme-phosphor',
166+
},
167+
{
168+
id: 'theme-fog',
169+
name: 'Fog',
170+
description: 'Coastal gray morning. Muted blue marks.',
171+
version: '0.1.0',
172+
author: 'Dripnex',
173+
repository: 'dripnex/theme-fog',
174+
},
57175
];
58176

59177
export interface CatalogCard {

docs/plugins/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

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

5-
| Doc | What it is |
6-
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7-
| [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)) |
8-
| [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 |
9-
| [../PLUGIN_SYSTEM.md](../PLUGIN_SYSTEM.md) | Implementation roadmap (phases 1–4 done). Phase 5 marketplace is later. |
10-
| [../tables-plugin.md](../tables-plugin.md) | How the **built-in** tables plugin works (not a satellite pack) |
5+
| Doc | What it is |
6+
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7+
| [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)) |
8+
| [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 |
9+
| [../PLUGIN_SYSTEM.md](../PLUGIN_SYSTEM.md) | Implementation roadmap (phases 1–4 done). Phase 5 marketplace is later. |
10+
| [../tables-plugin.md](../tables-plugin.md) | How the **built-in** tables plugin works (not a satellite pack) |
1111

1212
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.

docs/plugins/install-path.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,20 @@ Three strings are not interchangeable:
1414

1515
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.
1616

17+
## Satellite publish path
18+
19+
Inkdrop-style: the registry is the index, the GitHub Release tarball is the artifact. No marketplace.
20+
21+
1. `dripnex-plugin pack` writes `{id}-{version}.tar.gz` (`manifest.id`, not the repo name).
22+
2. Attach that archive to a GitHub Release (`gh release create vX.Y.Z {id}-{version}.tar.gz`).
23+
3. Seed the index in this repo (GitHub-down fallback + slug/name overrides):
24+
- 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`.
25+
- 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`.
26+
27+
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.
28+
29+
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`.
30+
31+
**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.
32+
1733
**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`.

docs/releases/v0.19.0.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
version: 0.19.0
3+
date: 2026-08-25
4+
title: Satellite themes in Browse
5+
status: draft
6+
---
7+
8+
Settings → Plugins → Browse lists first-party Dripnex theme and plugin packs
9+
when their latest GitHub Release includes a packed `.tar.gz`. You no longer
10+
have to type those specs by hand. This is not a public community marketplace.
11+
12+
## Plugins
13+
14+
- **Browse auto-lists first-party packs.** `GET /plugins` discovers public
15+
`dripnex/theme-*` and `dripnex/plugin-*` repos whose latest GitHub Release
16+
has a packed `{id}-{version}.tar.gz`. A git tag without that asset is
17+
skipped. Random org repos are not listed.
18+
- **Fallback seed.** If the API is unreachable, Browse still shows parchment
19+
and the packed satellite themes in the desktop catalog.
20+
- **Already on 0.18.0.** Install the same packs today from Other package:
21+
`dripnex/theme-<slug>`. 0.19.0 is Browse listing them.
22+
23+
Official palettes on Settings → Themes are unchanged. Satellite themes stay
24+
packs, not core.

packages/api/.dev.vars

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,9 @@ STRIPE_WEBHOOK_SECRET="whsec_your_secret_here"
2424
# Put the PRIVATE here (and as the Cloudflare secret in production/staging)
2525
LICENSE_SIGNING_PRIVATE_KEY="hex-encoded-32-byte-ed25519-private-key"
2626

27+
# Optional. GitHub token for first-party Browse discovery (theme-*/plugin-*
28+
# org repos). Unauthenticated public API still works; the token avoids rate limits.
29+
# GITHUB_TOKEN=""
30+
2731
# Environment
2832
ENVIRONMENT="development"

packages/api/SETUP.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ RESEND_API_KEY="re_your_key_here"
5858
# Stripe (get from: https://dashboard.stripe.com/webhooks)
5959
STRIPE_WEBHOOK_SECRET="whsec_your_secret_here"
6060

61+
# Optional: GitHub token for first-party Browse discovery
62+
# GITHUB_TOKEN="ghp_..."
63+
6164
# Environment
6265
ENVIRONMENT="development"
6366
```

packages/api/src/db/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export type Env = {
2525
STRIPE_PRICE_ANNUAL?: string;
2626
SITE_URL?: string;
2727
ADMIN_TOKEN?: string;
28+
/** Optional. Raises GitHub REST rate limits for first-party Browse discovery. */
29+
GITHUB_TOKEN?: string;
2830
ENVIRONMENT: string;
2931
// Rate limiting bindings (optional so unit tests / local runs without the
3032
// binding fail open rather than crash — see middleware/rateLimit.ts).

0 commit comments

Comments
 (0)