Commit graph

135 commits

Author SHA1 Message Date
CRT
205ee82296 host: plugins, custom CSS, feature flags, settings and open_panel are host commands
run_app now keeps and serves what every app's panel and page need, with the same caller checks
as the rest (commands::SHELL: shell_only first; testkit::assert_host_guards covers them):

- app.rs: PageState (the plugin store in app data `plugins`, the feature flags, ShellSettings)
  managed by the host; commands plugins_list, plugin_set_enabled, plugins_open_folder,
  custom_css_get/set, features_get/set, settings_get/set (moved from wayBetter for X). The app
  reads the state through app::page(), gets a loaded document's scripts from app::page_scripts()
  (flags, links, custom CSS, plugins) and writes through set_features/set_settings/set_custom_css
  (a backup import). AppConfig takes the app's PluginHost (AppConfig::new(site, title, plugins))
  and an optional home_url. SiteHooks::navigation_started and new_window_mode default to the
  owner's link settings.
- settings.rs (pure, tested): ShellSettings { homeUrl, externalLinks, siteLinks, restoreTabs }
  with its input form (missing fields take the defaults; `xLinks`, the name wayBetter for X used,
  is read as siteLinks), links_script ({ site: mode }), feature validation and features_script.
- commands::SITE + open_panel: a tab on the site's origin asks the shell to open the app's panel
  (site_tab_only first). testkit: assert_site_only(command, site) checks that every capability
  granting a site command is a tab capability limited to the site's URLs; assert_host_commands and
  assert_host_guards include the site commands.
- shell frame backupModel: a settings section that still says xLinks compares as siteLinks.
2026-09-30 14:28:52 +07:00
CRT
cecaf93639 docs: the panel in the framework (what an app supplies, which sections it gets, words, native commands) 2026-09-30 14:03:41 +07:00
CRT
00b193506f shell: the panel, createPanel(site) (moved from wayBetter for X)
packages/shell/src/panel (waybetter/shell/panel): an app's own tab. An app describes itself
(PanelSite: brand and the home page's words, its own sections and their order, its theme store,
catalog and the preview component a theme document is drawn in, Make's examples and docs, the
install controller, its languages, what its native side serves) and createPanel returns the
component for ShellSite.panel. It is in the shell package because it is drawn in the frame and
shares its stores, native bridge and language.

- Panel.tsx (header, settings search over every settings section, navigation, toasts; Accounts
  and Updates), nav.ts (which built-in sections an app gets: each shows only when the app serves
  what it needs; the app's sections in its order), Home.tsx (hero, highlights, About from the
  app's data), controls.tsx + panel.css.
- Appearance.tsx, ThemeBuilder.tsx + builderModel.ts + builder.css, fonts/ (FontBrowser, FontRoles,
  catalog, the offline Google Fonts list; scripts/google-fonts-catalog.mjs regenerates it):
  the theme documents are the runtime's, the store, catalog, accents, draft palette, file suffix
  and preview are the app's (PanelSite.themes).
- Plugins.tsx (the plugins list and custom CSS over the host's plugins_*/custom_css_*),
  StoreSection.tsx, MakePanel.tsx + makeModel.ts + MarkdownDoc.tsx + markdown.ts + make.css (the
  examples, the theme file and the docs are the app's), Settings.tsx (links and session over
  settings_get/set with `siteLinks`, keyword alerts, the media panel), FeatureToggles.tsx
  (useFeatures + FeatureGroups over features_get/set: the app names its flags and groups),
  PowerSettings.tsx (deck defaults from site.deck: its flags and presets; DeckPreset gets `name`
  and `hint`), BackupPanel.tsx + backup.css, DeveloperPanel.tsx, LanguageSettings.tsx, compare.ts.
- frame: language.ts (createLanguage: follow the site / the system / one language, i18n_set;
  moved from the app), appI18n.ts (createAppI18n: the app's typed i18n instance, useT, dates and
  numbers; the app passes React's useSyncExternalStore), formatDate in i18n.ts (ShellI18n.date).
- tests/panel.test.ts: every panel key has English and is used, sections per app, the builder
  model, the font catalog, plugin header rules, the UI kit demos, Markdown, compare.
- npm package: exports ./shell/panel, ./shell/panel/*, ./shell/panel/*.css; the build is
  scripts/build.mjs (the shell is compiled with the runtime sources it imports under one root and
  its imports are pointed at dist/runtime; stylesheets and the font list are copied).
2026-09-30 14:03:40 +07:00
CRT
6ef78c0c30 locales: the panel's words (wb.*), 51 languages
- 668 wb.* messages for the panel (navigation, settings search, accounts, updates, Appearance, the
  Theme Builder, fonts, plugins, custom CSS, Make, Power User, settings, backup and sync, developer
  mode, the controls), moved with every translation from wayBetter for X's catalogs; `{site}`
  stands where the English said "X" (49 keys; the app passes "X", so X reads the same). Keys that
  named X got site-neutral names (settings.links.site*, settings.language.followSite*,
  builder.leadingSite, builder.liveOnSite, fonts.asSite, make.siteDefaultLeading, features.default).
  English source: shell/src/panel/panelMessages.ts.
- One translation could not take `{site}` (hu wb.settings.alerts.hint never named the site) and
  falls back to English.
- locales/en.meta.json: the translator notes of the moved keys (40), among them the one fragment a
  language may leave empty (wb.make.step2Before); the catalog test reads it.
- runtime/tests/i18n.test.ts: en.json is the kit, shell-model, store, shell-frame and panel source.
2026-09-30 14:03:09 +07:00
CRT
9aa3fc9c17 The Windows installer is the framework's: a setup run again opens the installed app
packages/waybetter/windows/installer.nsi (shipped in the npm package) is the NSIS
template wayBetter for X used, made generic: an app that was renamed keeps its
registry keys by defining WAYBETTER_LEGACY_NAME in its installer hooks; without it
the keys are Tauri's defaults.

Run by hand (no /UPDATE) it installs only when it is newer than what is installed.
With the same or a newer version installed it installs nothing, opens the installed
exe (the single-instance guard shows the running window) and exits 0, so an old
setup can no longer replace or downgrade an install the updater has moved on.
/FORCE reinstalls the same version, /NORUN is kept, the updater path is unchanged.

create-waybetter apps use the template (bundle.windows.nsis, per-user).
wayBetter for X's page is waybetter.fyi/x in the READMEs.
2026-09-30 13:55:00 +07:00
CRT
2008967c04 fix(shell): coordinate startup cover and tab stills 2026-09-30 12:25:46 +07:00
CRT
fd99901bb2 runtime + host: the theme engine (theme documents, choice catalog, page runtime, fonts; native theme state)
The site-independent theme engine moves from wayBetter for X into the framework:
- runtime/themeSpec.ts: theme document types, the schema's defaults (BASE_*), sanitizing,
  import, overrides, ensureContrast, font roles/stacks, font choices, backgrounds.
- runtime/themeChoice.ts: ThemeChoice and createThemeCatalog(builtins) (normalize, base,
  resolve, palette, all), choiceForId, serializeChoice.
- runtime/themeRuntime.ts: installThemeRuntime(win, site) (live CSS over the site's rules,
  --wb-* vars, site color mode, first-frame snapshot), collectRules, resolvedFonts.
- runtime/fonts.ts: bundled fonts and owner-downloaded Google Fonts from bytes.
- themeApi exports hexToRgb, mix and MONO_FAMILIES (one copy: themeTokens and themeSpec use them).
- host theme.rs: ThemeChoice/ThemeScopes over a site's ThemeSite (envelope checks against
  theme.schema.json, which theme a tab shows, page color, delivery script).
2026-09-29 13:07:59 +07:00
CRT
3e58a5c11a docs: the shell frame in the framework (what a site supplies, styles, words, native commands)
README: "The shell frame" (createShell, the ShellSite slots and features, frame words and styles,
bootScript, preview mocks, the native commands and events it uses), the layout, the create-waybetter
app, how wayBetter for X consumes it. npm README: waybetter/shell/frame.
2026-09-29 12:47:19 +07:00
CRT
ceee9b7c4f create-waybetter: a new app's shell is the framework's shell frame
The app skeleton's src/shell/main.tsx calls createShell with the site (pages, account rules, search,
address chips, a Home link, a Plugins section) and src/shell/Panel.tsx (the app's own tab: the
plugins, switched on or off live); app.css themes it with the --wb-c-* tokens. build.mjs bundles
the shell with waybetter/build (JSX, CSS into dist/shell.css) and writes bootScript() as boot.js.
desktop.rs keeps the frame's titlebar (custom_titlebar: true) and forwards shortcuts and link drags
(BridgeOptions::ALL); the shell capability grants the frame's window calls. Native features the
skeleton does not wire up (workspaces, sync, developer mode, plugin commands) are off in the site.
Dependencies: react, react-dom, dockview, waybetter ^0.4.0.

Tests: sources import only published subpaths (patterns included), main.tsx uses createShell, the
shell capability has the resize permission, and the skeleton typechecks with the React types.
2026-09-29 12:47:18 +07:00
CRT
068168469c shell: the shell frame, createShell(site) (moved from wayBetter for X)
packages/shell/src/frame (waybetter/shell/frame): the whole shell of an app. An app describes its
site (ShellSite: names and pages, account rules, search, address chips and completions, its panel
tab, the new-tab page, palette items, deck column kinds and flags and an optional compose dock, the
media panel's composer rule, a theme store, overlays, the native features it serves) and passes
its Tauri API and i18n instance; createShell returns the root component.

- Shell.tsx: dockview host (tabs in the titlebar row, splits, drag-link drops, shortcuts, context
  menu, deck back-and-forth, session restore, workspace on start, overlay raise); state.ts (pane
  placeholders, tabs_sync one-in-flight via syncGate, shell_raise layer, profiles, layout).
- WebPanel (address bar), NewTabPage, CommandPalette + paletteModel (frame groups; site items),
  DeckView + AddColumnDialog + deckStore (site column kinds), PaneTheme + themeStore
  (createThemeStore over the app's ThemeAdapter) + chromeTheme (ChromeTheme input) + themeScopes,
  Titlebar + TitlebarExtras + icons + brand (wB mark data URI), AccountSwitcher + accountModel,
  workspaces + workspaceModel, backupModel, syncHost, devHost + devModel, pluginCommandStore,
  MediaPanel + mediaModel, searchInput, hooks, bridge (installPreviewMocks), i18n, boot.ts
  (bootScript: the first-frame boot.js), CSS themed with --wb-* tokens.
- paneModel: paneVisibility, raiseSupported, cssRgb; deckModel: isSourcePage.
- Includes the live-QA titlebar fix (dock ResizeObserver + rAF titlebar marks, dock sized by its
  insets).
- tests/frame.test.ts: every frame key has English and is used, palette order with a site,
  address fallback, layout gate, boot script, chrome variables, switcher rules, workspaces,
  deck settings with site flags.
- npm package 0.4.0: exports ./shell/frame, ./shell/frame/*, ./shell/frame/*.css (copied by the
  build); dockview and acorn optional peers; root devDependencies dockview, acorn.
2026-09-29 12:47:10 +07:00
CRT
892de6cbf4 install screen: where an install comes from, in the owner's language
The source line ("wayBetter Store (signed catalog, sha256 verified)", "Link: <host>", "A file you
dropped") is built from the source kind and URL with the wb.install.source.* messages instead of
showing native code's English label.
2026-09-29 12:47:09 +07:00
CRT
cc5a351fe9 locales: the shell frame's words (wb.*) and the install screen's source line, 51 languages
- 245 wb.* messages for the shell frame (tabs, address bar, new-tab page, palette, account
  switcher, decks, workspaces, chips, media panel, pane themes, backup preview), moved with every
  translation from wayBetter for X's catalogs; `{site}` stands where the English said "X" (10
  keys; the app passes "X", so X reads the same). English source: shell/src/frame/frameMessages.ts.
- wb.install.source.store|link|file: where an install comes from, translated in every locale
  (native code's label is English only).
- runtime/tests/i18n.test.ts: en.json is the kit, shell-model, store and shell-frame source.
2026-09-29 12:46:57 +07:00
CRT
231e18de0a create-waybetter: the app skeleton runs on run_app, testkit, waybetter/build and waybetter release
The generated desktop.rs is config + SiteHooks + its own commands; build.rs uses
commands::manifest; capability files grant the host's commands; tests/security.rs uses testkit;
scripts/build.mjs uses buildRuntime; waybetter.release.json and release scripts (placeholder URLs).
A test keeps HOST_COMMANDS in step with commands.rs.
2026-09-29 11:51:25 +07:00
CRT
4af85299c8 cli: waybetter release windows|macos and waybetter/build (0.3.0)
release: signed NSIS/universal-macOS releases and latest.json (merge, built-in shape check plus the
app's own validator), upload steps printed only, configured by the app's waybetter.release.json;
the key is read only into the build environment or passed to the Tauri signer by path.
build: buildRuntime() bundles a page runtime IIFE with the app's esbuild (?inline CSS as text,
catalog strings limited to the runtime's prefixes). esbuild is an optional peer.
2026-09-29 11:51:24 +07:00
CRT
d3ed72ea4d host: the tab bridge ships from waybetter-host; create-waybetter uses it
tab-bridge.js (moved from wayBetter for X) is served by bridge::SOURCE,
or by bridge::script(BridgeOptions) with shortcut and link-drag
forwarding switched off for a shell that does not handle them (a
forwarded shortcut is taken from the page). Tests: one options line,
only tab_report/tab_shortcut/tab_link_drag, every forwarded shortcut is
one tabs::valid_shortcut accepts. Generated apps now inject
bridge::script(BridgeOptions::REPORT_ONLY) instead of writing their own
duplicated src-tauri/runtime/tab-bridge.js.
2026-09-29 11:22:54 +07:00
CRT
3e6cbe0773 docs: the Store in the framework (shared catalog format, keys, tooling, trust model, adding it)
- docs/STORE.md: one signed catalog for every app (format 2, `apps` per item, field rules), Ed25519
  signing and key rotation, `waybetter store build|sign|verify` with an app config, install links,
  the trust model, and how an app adds the Store (StoreConfig, command wrappers, InstallHost,
  StoreView, tokens, strings).
- README: `store` in the layout and in what the host gives an app; the shell's Store modules.
- npm README: the Store components, models, schema and command.
2026-09-29 11:21:37 +07:00
CRT
3c238d9e2d cli: waybetter store build|sign|verify, the store catalog JSON Schema
Moved from wayBetter for X (scripts/build-store.mjs, scripts/sign-store.mjs) into the `waybetter`
npm package, generic over the app:

- bin/waybetter.mjs + cli/store.mjs. `build --config <store.config.mjs>`: the config names its app
  and returns its items (metadata, file path + bytes, optional preview); build replaces only that
  app's items in the shared catalog (other apps' items and files stay), removes files only its old
  items used, fills url/sha256/size/apps, and validates the whole catalog with the rules apps apply
  natively before anything is written. `sign` (and `sign --init`: create the key once, 0600, never
  overwritten) signs the exact catalog bytes; `verify` checks the signature with any listed public
  key (rotation) and the catalog rules. The private key is never printed, copied or moved; --key
  defaults to $WAYBETTER_STORE_KEY. pluginHeader() for configs.
- store-catalog.schema.json (format 2, `apps` per item), exported with the CLI module.
- Tests: multi-app builds in one folder, refusals (bad items, duplicates, paths outside the folder,
  hosts), schema vs CLI rules, sign/verify round trip incl. rotation and tampering, no key
  material printed. jsonSchema.mjs learns minItems, uniqueItems and allOf.
2026-09-29 11:12:38 +07:00
CRT
f1588c3acd shell: the Store view and install screen as framework React components, strings in the framework catalogs
Moved from wayBetter for X so every wayBetter app gets the Store UI; the app passes its native
bridge, theme adapter, translator and (optionally) its own controls and button classes.

- storeModel.ts: wire types of the native store commands (InstallPreview, StoreCatalogView,
  LinkEvent, StoreItem with `apps`), permission badges in the site's words, categories, item state
  (install/installed/update/changed locally/built in), search, free theme ids, versions, previews.
- installController.ts: the install screen's state machine (links incl. those queued before the
  shell listened, dropped files, store items, cancel, confirm), generic over the app's theme format
  (`ThemeAdapter`: parse, ids, facts, save) and its bridge (`StoreBackend`: invoke/listen).
- InstallDialog.tsx (`InstallHost`): the screen (Install enabled after 1 s, Enter never installs,
  tabs hidden via setOverlay) and the window-wide drop target. StoreView.tsx: search, kinds,
  categories, cards, permission badges, install/update/remove; default controls or the app's.
- store.css: both, themed with framework `--wb-*` tokens (documented; dark defaults).
- storeMessages.ts + every framework catalog: 120 `wb.store.*`, `wb.install.*`, `wb.permission.*`
  messages moved from the app catalogs with all existing translations; the six that named X take
  `{site}`; generic words the components need copied with their translations.
- npm package: exports for the new modules and store.css, optional react/react-dom peers; @types
  for the typecheck. Tests: models, controller flows with a fake bridge, every looked-up key exists.
2026-09-29 11:08:04 +07:00
CRT
b2744c1a45 pageLang: report X's language even when installed before <html> exists or before the IPC bridge
At document start (where the app installs the X runtime) there is no <html> element yet, so
the lang report never ran and "Follow X" never learned X's language (found live: siteLang
stayed null). It now reads lang again at readystatechange/DOMContentLoaded, and a report
that fails (no bridge yet) is retried with a bounded backoff. Tests.
2026-09-29 11:01:53 +07:00
CRT
c686c376ab i18n: framework catalogs for the 51 languages X offers, and tests
Kit and shell-model words (18 keys) per locale, machine-drafted except English. Tests cover
locale normalization, fallback chains, direction, ICU-lite formatting and quoting, the runtime,
catalog rules (plural-only arguments, missing forms, allowEmpty), plugin strings, and that every
framework catalog passes the checks.
2026-09-29 09:53:49 +07:00
CRT
2b8161fedc i18n: dependency-free message runtime, catalog checks, plugin strings, native strings
- runtime/i18n.ts: ICU-lite messages (placeholders as text, Intl.PluralRules plurals with exact
  forms, selectordinal, select, number/date/time), fallback chains (pt-BR -> pt -> en, ar-x-fm ->
  ar), X and legacy code aliases, RTL by locale, lazy catalogs, live onChange. Apostrophes are
  literal except right before { } # or another apostrophe.
- runtime/i18nCheck.ts: rules for contributed catalogs (shape, keys, syntax, placeholder parity,
  select options, markup/control characters, lengths). An argument English only uses to choose a
  plural form may be dropped; missing plural forms are warnings; meta "allowEmpty" fragments.
- runtime/pluginI18n.ts: api.i18n bound per plugin (register/t/locale/dir/onChange/number/date/
  relative/list); the UI kit's own words follow the app's language. pageLang.ts reports the
  site's <html lang>. shell/messages.ts: shell-model words.
- waybetter-host i18n.rs: NativeStrings (validated plain text, caps, one-pass {name} fill, page
  payload by prefix), system_locales via sys-locale; TabState.lang.
- JSON Schemas for catalogs and translator notes; npm exports waybetter/i18n, /i18n/check,
  /i18n/plugin.
2026-09-29 09:53:48 +07:00
CRT
c404dd3dd0 runtime: styles for created roots are constructed sheets (CSP-proof)
- styles.ts: adoptStyles(root, css) adopts a constructed stylesheet into a shadow root or document
  (not governed by a page's CSP, parsed once, stays with the root when its host is moved);
  <style> fallback where constructable sheets are missing or refused.
- UI kit: the kit's shadow root and each dialog's `css` use it (dialog CSS goes with the dialog).
- Plugin API: api.adoptCSS(root, css) and scope.adoptCSS (removed on dispose); injectCSS keeps its
  <style> and, when a CSP leaves it without a sheet, applies the same rules as an adopted sheet.
- tests/styles.test.ts.
2026-09-29 04:09:14 +07:00
CRT
0c1ea611e7 runtime: plugin commands for the command palette (api.commands / scope.commands: register, list, run, owner = the starting plugin, removed on stop, caps, in-page shortcuts); host: start/stop scripts own and drop a plugin's commands; dev_start_script with sourceURL + devError for live reload; devErrors (file:line from a start failure) 2026-09-29 01:35:44 +07:00
CRT
26684e18d7 Plugin permissions and app installs: @permissions header, per-plugin API views, validated install/remove
- host plugins.rs: PERMISSIONS, parse_permissions, ScriptPlugin.permissions/problems (None = legacy,
  full API), validate_plugin (file name, 2 MiB, UTF-8 text without binary bytes, header with @name
  and @version, valid @permissions, network:none refused when the code calls network APIs),
  source_findings, PluginStore::install (atomic rename, never enables, keeps the enabled state on
  update) / remove / is_enabled / file_hash. start/stop scripts run the module body, construction,
  start() and stop() inside window.<global>.withPlugin(id, grants, fn) when the runtime has it.
- runtime permissions.ts: parsePermissions, scopePluginApi (undeclared gated members throw a
  PluginPermissionError; scope().ui gated like api.ui), createPluginContext (the view of the plugin
  whose code runs; legacy = full API). A declaration and guard rail, not a sandbox.
- The `commands` permission name comes from the parallel palette-commands work (its API lands there).
2026-09-29 01:08:52 +07:00
CRT
b6dd47e0d5 runtime: font roles in the theme API (fonts per role, --wb-font-<role> vars, UI kit uses the dialog/mono roles); theme schema: font.roles with Google Fonts source 2026-09-28 23:56:37 +07:00
CRT
434b187638 runtime column: set the column attributes on scan (config delivered at document start has no <html> yet), no scrollbar in columns, unread only above both the read items and what is on screen, a hidden 1 px webview counts as off screen 2026-09-28 23:42:21 +07:00
CRT
4bc8c6a933 create-waybetter: npm create waybetter scaffolds plugins (JS/TS), themes and whole apps
- plugin: *.plugin.js with the store header and start/stop on api.scope, storage, observe,
  onKey, the UI kit (toast with action, ui.h settings dialog) and api.theme/--wb-* vars;
  --ts makes a TypeScript project typed by the waybetter package (build keeps the header first)
- theme: JSON with "$schema" -> theme.schema.json, palette derived like themeFromColors,
  font roles (family, tweet), presets
- app: Tauri 2 + waybetter-host + runtime + shell models: SiteSpec, SiteAdapter, shell/tab-chrome/
  site-tab capabilities, tabs_sync, plugin store, a site-only command; presets for youtube.com,
  kick.com, twitch.tv with placeholder selectors; host crate via submodule, path or git
- tests generate into temp dirs: headers via parse_meta (new plugin_meta example), plugin code
  against createCorePluginApi's members, themes against the schema, app TS with tsc against the
  built package, app Rust with cargo metadata/check/test
- wired into bun run check (typecheck incl. checkJs, build:packages, test:create) and pack:check
2026-09-28 23:17:32 +07:00
CRT
376e74884e Deck columns (Power User Mode): shell deckModel (bounded decks, paging layout, focus, unread totals), runtime column mode (hide site chrome, fill width, filters, unread tracking, no requests), host ColumnConfig bounds, TabRole, deck shortcuts, capped unread in TabState; column boxes skip rail rules 2026-09-28 22:55:57 +07:00
CRT
f6d52512a0 runtime: plugin UI kit (api.ui: toast, alert, confirm, prompt, dialog, modal) and theme API (api.theme, --wb-* vars); theme JSON Schema; waybetter 0.2.0
The kit draws in one shadow DOM host in the active theme's colors, corners and font and repaints
live; accessible dialogs (focus trap and return, Esc/Enter rules, alertdialog for alerts and
confirms), stacking with inert, toasts with actions, reduced motion, text-only content (ui.h),
and scope.ui closes a plugin's dialogs on dispose. api.toast routes to it.
2026-09-28 21:47:09 +07:00
CRT
894a9de48f One system for every app: WhatsApp/Discord-style targets run in the same Tauri shell; site is waybetter.fyi 2026-09-28 06:40:57 +07:00
CRT
8821624241 Public: README links npm and the site; package points at git.crt.fyi (0.1.1) 2026-09-28 06:12:55 +07:00
CRT
e5c91a1563 npm: publish as one package waybetter (waybetter/runtime/*, waybetter/shell/*); @waybetter scope is taken 2026-09-28 05:54:03 +07:00
CRT
faf4e5909e README: projects using wayBetter (wayBetter for X first) 2026-09-28 05:46:46 +07:00
CRT
96512c7bb0 packages: make runtime and shell publishable to npm
Drop private from @waybetter/runtime and @waybetter/shell (root stays
private), add per-module exports with types/import conditions backed by
a tsc build (rewriteRelativeImportExtensions rewrites .ts specifiers to
.js in dist), files/sideEffects/engines/keywords/publishConfig, a
prepublishOnly that builds and tests, and a README + copied LICENSE per
package. Root gains build:packages and pack:check scripts. dist/ is
gitignored; the desktop app keeps importing raw src/*.ts by relative
path, unaffected.
2026-09-28 05:41:01 +07:00
CRT
43a9e2e1a7 Extract the wayBetter framework core from wayBetter for X
Site-agnostic parts of the X app, behind a small site adapter:

- crates/waybetter-host: webview-label security policy and tab rect
  clamp, account profiles with native-owned accounts (AccountRules),
  plugin store with bundled-plugin upgrades (PluginHost), signed
  data-only hotfix channel, update scheduling and crash handshake, tab
  payloads/link routing/tab-chrome validation, and (feature "tauri")
  webview helpers and the Windows system menu.
- packages/runtime: DOM hub, request hub, plugin API core, OKLab theme
  color model, split-view rail hiding, link routing and account
  reporting, each configured by a SiteAdapter.
- packages/shell: address bar, pane, link-drop, profile, palette and
  update-chip models, and window controls with the Tauri API injected.

Tests moved/adapted from the app: 45 Rust (headless), 40 TypeScript.
2026-09-28 03:01:33 +07:00