Files
platform/.gitignore
T
pastilhasandClaude Opus 5 0d29e242a3 themes are installable, like plugins
`platform/themes/<id>/` — untracked, same rule as `plugins/`, only the instructions
tracked. Drop a directory in and the theme appears in the picker on the next page load.

  themes/my-theme/theme.css     required — `[data-theme='my-theme'] { … }`
  themes/my-theme/theme.json    required — { name, family, dark }
  themes/my-theme/assets/       optional — wallpaper, logo

── Why this is cheaper than installing a plugin ──

A plugin is code: it needs a manifest module, mounting, and a frontend rebuild to reach
the bundler. A theme is a block of CSS custom properties, so it needs none of that. The
server reads the directory at request time and the client adds a `<link>`. No install
step, no rebuild, no restart — which is the whole reason this is eighty lines of
discovery rather than four hundred.

The id is the DIRECTORY NAME, not a manifest field, for the same reason a plugin's
`appName` is not one: an id that can disagree with where its files sit eventually will.
Discovery checks that the CSS actually targets its own directory name, because the
failure is otherwise silent — the theme appears, is selected, and nothing changes.

── Problems are reported, not swallowed ──

A malformed theme returns a reason rather than vanishing:

  broken-probe: theme.css does not target [data-theme='broken-probe']

The client logs those, so an author has somewhere to look instead of wondering why
their theme never appeared.

── Boundaries kept ──

The `theme` package still performs no IO. It gained an `extraThemes` prop; Officer
fetches and injects, exactly as it supplies the panel registry to `workspaces`. A
failure to fetch is not an error — no server, no session, no directory all mean "you get
the built-in themes", which is a complete product.

`/api/themes` is a `core` capability: read-only, and not deniable, because an account
that cannot read the theme list renders unstyled. Installing remains a directory on
disk; an upload endpoint would be a way to write arbitrary CSS into the page from a
request.

Verified in-process: listing, the problem report, CSS served as text/css, and a
traversal attempt answered 404.

── Needs a restart ──

Server-side change. Until then the client's fetch 404s and silently keeps the built-ins,
so nothing breaks in the meantime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 01:52:21 +00:00

115 lines
4.0 KiB
Plaintext

# dependencies (bun install)
node_modules
# output
out
src/videos/**/out
dist
dist_*
.dist
runtime-scripts
*.tgz
# code coverage
coverage
*.lcov
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store
src/config.ts
# Playwright
playwright/
.wwebjs_cache/
# generated from index.html by scripts/gen-index.ts
src/apps/officer-web/index.gen.html
# scratch scripts — never commit these
*.tmp.ts
# Sidecar assets published at install time — copies of files that live in each sidecar's own tree.
public/plugins/
# Written by machine-setup.sh to record completed steps; per-machine, never shared.
.setup-progress
.setup-answers
# Written by officer-setup.sh; per-machine.
scripts/setup/officer-setup/.setup-progress
# Generated by officer-setup, describing THIS install's processes. Never committed:
# the repository has no ecosystem file at all any more, and the next machine
# generates its own. See scripts/setup/officer-setup/lib/services.sh.
ecosystem.config.cjs
# The built SPA and the generated plugin module — both describe THIS install's plugin set and are
# rewritten on every install. See servers/plugins/generate.ts.
build/
build.next/
src/apps/officer-web/Plugins.gen.tsx
src/databases/officer_db/src/plugin-schemas.gen.ts
# drizzle-kit's generated migrations. Nothing applies them — there is no __drizzle_migrations table and
# `drizzle-kit migrate` has never been run here; `bun db:push` diffs the schema code against the live
# database and alters it directly. The schema code is the source of truth (src/databases/CLAUDE.md).
#
# Ignored rather than merely unused, because `bun db:gen` reads src/schema.ts — whose last line imports
# plugin-schemas.gen.ts, itself generated from the plugin DIRECTORIES on this machine. So a generated
# migration describes whichever plugins happen to be checked out here, and committing one would launder
# per-machine state into the repository: run it with music installed and history gains music_*; run it on
# a fresh clone and the next commit deletes them again.
#
# The old 0000_new_princess_powerful.sql is deleted from the WORKING TREE but left in history. It had 36
# tables and described a schema from before capabilities, api_keys, the app store and the plugin system
# existed, including three (task_logs, terminal_containers, queue_jobs) that no longer exist at all.
#
# Purging it from history was tried on 2026-08-15 and deliberately undone. This codebase cites 76 commit
# SHAs in comments and docs as evidence — `totality.ts` points at 2873948 for the websocket incident,
# `registry.ts` at 044aacf4, CLAUDE.md at f35c145 — and a filter-repo run rewrites every one of them.
# Three stale files nobody reads in old commits are not worth 76 dangling citations in a codebase whose
# documentation works by pointing at the commit that proves the claim.
#
# Generate one locally whenever a diff is useful to read. It stays local.
src/databases/officer_db/migrations/
# ── plugins/ holds documentation, not plugins ──
#
# Every plugin is its own repository (gitea.officer.dev/plugins/*) and arrives here by `git clone` when
# somebody installs it. A cloned plugin carries its own .git, so leaving it tracked means `git add -A`
# commits a gitlink — a pointer to a commit this repo does not contain. That happened on 2026-08-15.
#
# The trailing slash matters: this ignores DIRECTORIES only, so files at the top of plugins/ —
# EXTRACTING-A-PLUGIN.md and anything beside it — stay tracked. The documentation about plugins belongs
# to the platform; the plugins do not.
/plugins/*/
# Visual baselines for the theme extraction — large, machine-specific, regenerate with scripts/theme-snapshot.ts
.snapshots/
# Installed themes, same rule as plugins: a theme is somebody's own work dropped into this directory, not
# this repository's content. Only the instructions are tracked.
themes/*
!themes/*.md