Commit Graph
3 Commits
Author SHA1 Message Date
pastilhas ad8ed88519 profile settings keyed (425 -> 352)
ProfileSettings reaches zero: api keys, profile, voice, dock, languages and the
model defaults.

Language names now come from Intl.DisplayNames rather than the catalog. The runtime
already knows "German" in English and "alemao" in Portuguese, so 28 names would have
been 56 hand-written entries that Intl gets right for free -- including for locales
not shipped yet. Same reasoning D7 gives for dates and numbers. The tag LIST stays
hardcoded: which languages you may claim to speak is a product choice.

ApiKeys had toLocaleDateString(undefined, ...), which followed the BROWSER locale --
the exact contradiction D7 describes. It uses useFormat().date now. Its revoked-key
toggle hand-rolled a plural with a ternary on n === 1; that is a real plural entry now.

Scanner: an Authorization header value like "Bearer <token>" is not a sentence.
Excluded by auth-scheme prefix; verified the delta is exactly the four such
credentials across both remaining areas.
2026-08-23 04:57:48 +00:00
pastilhasandClaude Opus 5 543e88a9a6 every plugin route renders a workspace, and it is not a rule you can forget
an exclusionary rule, made structural. a plugin does not render a screen: it
contributes panels and says how they are arranged, and the shell renders
WorkspaceView around them.

    web/panels.ts   appRegistryMetas — at least one panel
    web/layout.ts   defaultLayout — how they are arranged

both required the moment web/ exists, and missing either is refused at discovery
by name and with the reason. tested:

    probeplug: has a web/ directory but is missing web/layout.ts.
    Every plugin route renders a Workspace: contribute panels and a layout,
    not a screen.

there is deliberately no way to export a component. one that could would be free
to render a bare div, a full-page form, or its own navigation, and the platform
would become a shell hosting strangers' layouts rather than one application.
non-compliance is not so much refused as unrepresentable — there is nowhere to
put a screen.

the shell registers <prefix> and <prefix>/:section, exactly as the core screens
do, so a plugin's sections stay addressable and cmd-clickable, and panels read
useParams independently rather than passing state between themselves.
appTypes.allowed is pinned to that plugin's own keys, so a persisted layout
naming something else falls back instead of rendering another plugin's panel
inside this screen.

the example plugin is rebuilt to model it — two panels, a layout, one of them
calling its own /api/example/ping through useClient — because the reference
implementation is what everyone copies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 23:47:48 +00:00
pastilhas acd7713c86 projects 2026-02-25 06:59:29 +00:00