marketplace.officer.dev is live, and the plugin repos have READMEs
The site is up on HTTPS with a Let's Encrypt certificate, proxied to :9100, and serving the three plugins out of `officer_marketplace`. An Officer install with no configuration now reads its catalogue from it. ── What is running ── PM2 entry added to THIS machine's ecosystem only. Deliberately not in officer-setup's CORE_PROCESSES: the marketplace is one website officer.dev hosts, not something every install should run — a copy on every machine would serve a stale catalogue on a port nobody asked to open. nginx (NPM host id 7) → 172.20.0.1:9100, with a ufw rule for the docker bridge. That rule is not optional and its absence does not look like a firewall problem: without it nginx HANGS until proxy_connect_timeout rather than being refused, which is how the apptest hosts wasted an hour a few days ago. ── READMEs ── `music`, `offscale` and `example` now have proper READMEs, written against their own code and pushed to their own repos. They render on the plugin's page in the store and are what a self-hoster reads before installing. The example's is a tutorial as much as a shop window — it is the document a plugin author reads first, and every convention in it was verified in `discover.ts` rather than restated from memory. `music`'s remote was HTTPS with no credentials on this box, so it could not be pushed; switched to SSH like the other two. The catalogue still advertises HTTPS — `marketplace-sync` converts — which is the property that matters, since an `ssh://` clone URL only works on the machine that published it. ── Writing them was the cheapest audit available ── Reading each plugin against its own documentation turned up ~20 real defects, all recorded in TODO.md and none fixed here. The pattern worth naming: offscale is still branded "headscale" in user-visible panel names and in a persisted terminal session id, and its PLUGIN.md states outright that the ACL assistant is deliberately unwired — while `sidecar/assist.ts`, `claude-proxy.ts` and `PolicyAssistant.tsx` all ship. Documentation that confidently describes the opposite of the code is worse than none. Also fixed the docs on the frozen lockfile: both CLAUDE.md and bunfig.toml named `bun install --no-frozen-lockfile` as the escape hatch, and bun 1.3.14 has no such flag — it is ignored and the install fails anyway. tsgo clean, 873 pass / 7 fail unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -322,6 +322,70 @@ pane belonging to the folder you left; and the breadcrumb opted out of that last
|
||||
restored. Deliberate as written — a dashboard can hold two browsers and one URL cannot serve both —
|
||||
but worth re-deciding rather than inheriting.
|
||||
|
||||
## Plugin repos — what writing their READMEs turned up
|
||||
|
||||
Three READMEs were written on 2026-08-16 (`music`, `offscale`, `example`) and pushed to their own repos.
|
||||
Writing them meant reading each plugin against its own documentation, which is the cheapest audit there
|
||||
is. Everything below was found that way and none of it is fixed.
|
||||
|
||||
**Offscale is still branded headscale in shipped, user-visible places.**
|
||||
|
||||
- [ ] `web/panels.ts` registers three panels named "Headscale servers", "Headscale", "Headscale" — these
|
||||
are what a user reads in the panel picker.
|
||||
- [ ] `web/OffscaleServerPicker.tsx:26` renders the literal heading `Headscale`.
|
||||
- [ ] `web/ConsoleView.tsx:22` mints terminal session ids as `headscale-console-<id>`. That is persisted
|
||||
state rather than a comment, so renaming it orphans live console sessions — cheap now, less so later.
|
||||
- [ ] ~12 stale `/headscale` route paths in comments across `web/`, plus `App.tsx:78` in the platform.
|
||||
- [ ] `PLUGIN.md` has ~11 stale self-references (`headscale_servers`, `listHeadscaleServers`, permission
|
||||
key `headscale`, `/api/headscale`, panel keys, `useHeadscaleSection()`).
|
||||
|
||||
**Documentation that actively lies.**
|
||||
|
||||
- [ ] `plugins/offscale/PLUGIN.md:445-449` says the ACL assistant is deliberately unwired and must not be
|
||||
wired up. It IS wired — `sidecar/assist.ts`, `claude-proxy.ts`, `web/PolicyAssistant.tsx` and the
|
||||
manifest's `readOnlyWrites` all ship.
|
||||
- [ ] `plugins/offscale/OFFSCALE_API.md` claims to publish the contract "in full" and omits six live
|
||||
surfaces, including all of `/_officer/companion/*` and `/_officer/enroll/invites`.
|
||||
- [ ] `plugins/music/MUSIC_API.md` says favourites and now-playing are served by the platform from
|
||||
Postgres; the sidecar serves them itself, scoped by `X-Officer-User`. It also documents the playlist
|
||||
item key as `<albumRel>/<file>` while the schema and favourites use the home path — the same file
|
||||
contradicts itself.
|
||||
- [ ] `plugins/music/MUSIC_API.md` documents now-playing as one snapshot per user with no mention of
|
||||
`?device=`, which the schema makes part of the primary key. A mobile client written to that doc is
|
||||
correct only by accident.
|
||||
- [ ] `plugins/example/manifest.ts:12` lists `web/Router.tsx` as the frontend convention; discovery
|
||||
requires `web/panels.ts` AND `web/layout.ts`. The same file documents an `ownerOnly` field that does
|
||||
not exist and never did.
|
||||
- [ ] The Companion contract docs the offscale code cites (`COMMS/OFFSCALE_COMPANION_API.md`,
|
||||
`COMMS/OFFSCALE_INVITE_ENROLLMENT.md`) exist nowhere — `COMMS/` was deleted. Two of the plugin's
|
||||
eight sections depend on a service with no published spec.
|
||||
|
||||
**Conventions a plugin author has to guess.** All verified in `discover.ts`/`mount.ts`, none documented
|
||||
outside the example's new README:
|
||||
|
||||
- [ ] Panel `key`s and layout `appType`s must agree, and a mismatch fails SILENTLY — `PluginScreen.tsx`
|
||||
pins `appTypes.allowed` with `fallback: allowed[0]`, so a typo renders the first panel.
|
||||
- [ ] The `<appName>_` table prefix is unenforced. The barrel is `export *` across every plugin into one
|
||||
`public` schema, so two plugins choosing the same unprefixed name collide with no error until push.
|
||||
- [ ] A manifest is module-cached for the process lifetime: editing it does nothing until
|
||||
`pm2 restart officer`, and `outdated` cannot see a version bump either.
|
||||
- [ ] Permission-key prefixing is convention, not validation. Only a collision with a CORE key is refused,
|
||||
silently, at mount, with a console error.
|
||||
|
||||
**Genuinely missing.**
|
||||
|
||||
- [ ] `plugins/offscale` spawns the `ssh` binary (`sidecar/ssh.ts`) but declares no `osDependencies`, so
|
||||
install never checks for it and the Console fails at runtime instead of refusing at install.
|
||||
`PLUGIN.md:421` already lists it as a host dependency — the manifest is the file that is wrong.
|
||||
- [ ] `scripts/reindex-music.ts` resolves its port file from `process.env.DATA_PATH ?? cwd/data`, and
|
||||
`DATA_PATH` stopped being an env var on 2026-08-13. Run from the repo it looks in
|
||||
`platform/data/music/.server` and never finds it. One line.
|
||||
- [ ] `plugins/music/web/MusicPlayerHost.tsx` header says it is mounted once in the persistent
|
||||
DashboardLayout; it moved into `MusicDetail`. That is exactly the comment that would mislead
|
||||
someone about why playback stops off-route.
|
||||
- [ ] A plugin's `assets/icon.png` is only published while installed, so its real icon is invisible in the
|
||||
store before install. The catalogue's `iconUrl` works around it, and an author has to know to add one.
|
||||
|
||||
## Known bugs
|
||||
|
||||
- [ ] **Background job logs appeared INSIDE an open file in the code editor.** Reported 2026-08-16 by the
|
||||
|
||||
Reference in New Issue
Block a user