Skip to content

chore(branding): strip OpenCode residue for Phase 1#18

Merged
Astro-Han merged 17 commits into
devfrom
worktree-branding-cleanup
Apr 18, 2026
Merged

chore(branding): strip OpenCode residue for Phase 1#18
Astro-Han merged 17 commits into
devfrom
worktree-branding-cleanup

Conversation

@Astro-Han

Copy link
Copy Markdown
Owner

Summary

Sweeps user-visible OpenCode brand residue discovered during the v0.2.3 smoke test (rolled back on 2026-04-17). The published v0.2.3 Release was deleted because the dmg shipped with Apple's design-template placeholder icons and various OpenCode strings in dialogs, settings, update toasts, etc. This PR covers the explicit-brand surfaces and narrows the Phase-1 product scope (1 theme, 2-3 locales) so a future re-release lands clean.

Scope and rationale

Commit What Why
622a648 HTML title, PWA manifest, root + desktop-electron package.json author/homepage/description/repo URL Direct OpenCode strings the user would see in tab title / PWA shortcut / About-panel metadata
ff02a27 Prune theme system from 38 themes to 1 (pawwork only) 38 themes = 38-file sync burden per CSS-token refactor; target user (non-programmer) won't open a theme picker; future-proofs frontend restructure
086deb4 i18n locale set from 17 → en/zh/zht Inherited locales had no active maintainer. Phase 1 audience = zh (纯刻 + 中文市场) + en (global OSS). Non-kept locales would silently display stale OpenCode text once we drifted
b5696b8 Sed sweep of OpenCodePawWork in en/zh/zht values Used sentinel two-pass to preserve OpenCode Zen / OpenCode Go service names and opencode.ai/zen URL — Zen is a real third-party model-routing service PawWork uses as backend, renaming would misattribute upstream
5c346546 Config loader accepts pawwork.json / pawwork.jsonc alongside legacy opencode.json / opencode.jsonc Additive change: 5 loader touchpoints + all user-visible help strings updated. Existing configs keep working, new installs see pawwork.json as the canonical filename

Deliberately out of scope

  • .opencode/ directory-name detection (additive .pawwork/ = larger refactor; legacy still works)
  • @opencode-ai/* import path renames (~574 refs, blocked on Zen proxy header dependency verification per project_rename_blockers memory)
  • opencode-theme-id / opencode.global.dat localStorage keys (DevTools-only visibility, renaming breaks existing user data)
  • JSON schema $id URL in desktop-theme.schema.json
  • CLI TUI theme packages/opencode/src/cli/cmd/tui/context/theme/opencode.json (separate subsystem)
  • Brew/scoop manifest URLs in installation/index.ts (upstream OpenCode distribution channels)
  • Proper pawwork-dark palette — pawwork.json's dark section is currently a copy of light; context.tsx forces light via hardcoded check; designing a real dark variant is follow-up

Verification

  • bun run typecheck green across all 7 packages after each commit
  • Parity test (packages/app/src/i18n/parity.test.ts) now asserts zh + zht translate target keys (down from 16)

Test plan

  • After merge: trigger build.yml with phase=full, channel=prod, arch=arm64
  • Verify draft Release v0.2.X produced with correct paw-print icon visible on mounted dmg
  • Smoke test app launches on clean macOS (Gatekeeper silent, menu bar shows PawWork, About dialog shows PawWork, browser tab — if web dev — shows PawWork)
  • Confirm existing opencode.json configs still load without warnings
  • Confirm app detects pawwork.json when present

Not included in this PR

  • README update (was reverted during v0.2.3 rollback; will redo on next real release)
  • pawwork-dark palette design
  • Public Release republish (do after merge + smoke test pass)

Fixes P0 brand residue discovered during v0.2.3 smoke test:

- packages/app/index.html: <title> OpenCode → PawWork
- packages/ui/src/assets/favicon/site.webmanifest: name + short_name
  → PawWork (controls PWA add-to-homescreen label)
- packages/desktop-electron/package.json: homepage → pawwork.ai
  (Yuhan owns the domain), author → PawWork
- root package.json: name opencode → pawwork, description updated
  from generic dev tool tagline to actual PawWork positioning
  ('Desktop AI workstation for knowledge workers'), repository.url
  pointed to Astro-Han/pawwork
Reduces theme system from 38 themes to 1 (pawwork only):

Motivation
- Target user is non-technical knowledge worker, not developer.
  They won't open a theme picker to choose 'Dracula' vs 'Monokai'.
- Each theme JSON must match desktop-theme.schema.json. Future
  refactors that add CSS tokens would touch 38 files.
- Upstream cherry-picks that adjust color semantics become 38x
  maintenance burden for near-zero user value.
- Aligns with simplicity principle in AGENTS.md.

Changes
- Delete 37 theme JSON files (kept pawwork.json only, which is
  already the default via DEFAULT_THEME_ID).
- default-themes.ts: collapse 38 imports/exports/registrations
  to just pawworkTheme.
- theme/index.ts: drop 37 re-exports, keep DEFAULT_THEMES and
  pawworkTheme.
- context.tsx: remove oc2ThemeJson import + oc-2 seed entry in
  store.themes. (Other oc-2 special-case branches left as dead
  code — they never fire without an oc-2 theme to load, and
  cleaning them up is a separate polish commit.)

Regression audit
- No other file imports the removed theme constants (grep clean).
- User config with 'theme: dracula' falls back gracefully: see
  context.tsx L308 console.warn + default theme fallback.
- CLI TUI theme system (packages/opencode/src/cli/cmd/tui/) is a
  separate subsystem, unaffected by this change.
- Typecheck passes across all 7 packages.

Known gap
- pawwork.json has both 'light' and 'dark' sections but 'dark'
  palette is a copy of 'light' (not actually dark). context.tsx
  L135 hardcodes pawwork → light. Designing a proper dark
  palette is follow-up work.
Drops 14 inherited locales (ar/br/bs/da/de/es/fr/ja/ko/no/pl/ru/th/tr)
that have no active maintainer on the PawWork team, and keeps only
the locales that map to actual target audiences:

  - en: global OSS community
  - zh: 纯刻 internal + 中文市场 (primary)
  - zht: Traditional Chinese fallback for zh-Hant systems

Rationale
- Inherited 16 languages were 'free' from OpenCode but become a
  liability once branding/key-set drifts — non-maintained locales
  silently show stale OpenCode text (confirmed in scan: zh/en have
  ~27 refs each, others unverified, all would need careful sweep).
- Phase 1 audience is Chinese + English (per AGENTS.md '双语产品').
- Recovery is cheap: any removed locale can be restored from git
  history later when real demand appears.

Files deleted
- packages/app/src/i18n/{ar,br,bs,da,de,es,fr,ja,ko,no,pl,ru,th,tr}.ts
- packages/ui/src/i18n/{ar,br,bs,da,de,es,fr,ja,ko,no,pl,ru,th,tr}.ts
- packages/desktop-electron/src/renderer/i18n/{ar,br,bs,da,de,es,fr,ja,ko,no,pl,ru}.ts
  (th/tr never existed in desktop-electron subset)

Loaders updated
- packages/app/src/context/language.tsx: Locale union/LOCALES/INTL/
  LABEL_KEY/loaders/localeMatchers all collapsed to 3 entries.
- packages/desktop-electron/src/renderer/i18n/index.ts: same narrowing.
- packages/app/src/i18n/parity.test.ts: now only asserts zh + zht
  translate the target keys (down from 16 locales).

Typecheck passes across all 7 packages.
Sweeps en/zh/zht i18n values where 'OpenCode' refers to the app
itself (e.g. update toasts, dialog descriptions, settings labels).

Preserved by design:
- 'OpenCode Zen' service name — third-party model routing service
  PawWork uses as backend. Renaming would misrepresent upstream.
- 'opencode.ai/zen' URL — same reason, real Zen service link.
- 'OpenCode Go' service name — same reason.
- 'opencode.json' config file references — will be handled in a
  separate rename commit alongside the actual config loader change.
- All dictionary keys (e.g. 'dialog.provider.opencode.note') —
  keys are identifiers referenced elsewhere in code; renaming them
  is a larger refactor touching consumers, separate pass.

Technique: sed two-pass with sentinels to replace 'OpenCode' while
protecting 'OpenCode Zen' / 'OpenCode Go' phrases from the sweep.
Dry-run diff reviewed per file before applying.

Typecheck passes all 7 packages.
Product-level config file rename: PawWork now prefers pawwork.json
/ pawwork.jsonc but still reads opencode.json / opencode.jsonc for
backward compatibility (existing 纯刻 team installs and any prior
Yuhan-local configs keep working without migration).

Loader additions
- config.ts globalConfigFile candidates array
- config.ts loadGlobal reads (pawwork merged after opencode so it
  overrides if both exist)
- config.ts project + managedDir for-loops (same ordering)
- mcp.ts resolveConfigPath candidates (pawwork first; default-to
  changed from opencode.json to pawwork.json for new installs)

User-facing strings updated to pawwork.json
- cli/error.ts provider/model mismatch hint
- cli/cmd/providers.ts credential-stored warning (x2)
- cli/cmd/mcp.ts OAuth-capable server hint
- cli/cmd/tui/.../tips-view.tsx home tips
- command/template/initialize.txt (AI-generation template)
- app/src/i18n/{en,zh,zht}.ts (2 strings each: plugins empty state
  + checkConfig hint)

Not changed (intentional)
- .opencode/ directory name detection — additive support for
  .pawwork/ would be a scope expansion; legacy path still works.
- CLI TUI theme file 'theme/opencode.json' import — separate
  subsystem theme, no user impact.
- Brew/scoop manifest URLs in installation/index.ts — upstream
  OpenCode distribution channels, not PawWork's.
- Zen service URL 'opencode.ai/zen' — real third-party service.
- Code comments mentioning 'opencode.json' for historical context
  (tui.ts, tui-migrate.ts, provider.ts).

Typecheck passes all 7 packages.
@Astro-Han

Astro-Han commented Apr 17, 2026

Copy link
Copy Markdown
Owner Author

I don't think this is ready to merge.

This change affects the upgrade path for existing installs, not just the settings surface. Startup still trusts opencode-theme-id from localStorage, but this PR removes every bundled theme except pawwork. If an existing user previously selected dracula, nightowl, or still has the old oc-1 / oc-2 path in storage, the app can start with a theme id that no longer exists. In that state, we do not fall back to pawwork, and preload can still apply stale cached CSS.

I'm treating this as P1 and merge-blocking. Before merge, we should migrate unknown stored theme ids to pawwork during startup and add a regression test that covers persisted legacy themes. Otherwise we fix the fresh install default and break the upgrade path for existing users.

Pre-fix path: if a stored opencode-theme-id was dracula, nightowl,
oc-1/oc-2 or any other theme we bundled before this cleanup, the
preload script would inject cached CSS for the missing theme and
context.tsx would silently skip applying anything. Users on upgrade
could be stuck with stale CSS and a data-theme attribute pointing at
a theme that no longer exists.

Treat pawwork as the single valid bundled theme: preload rewrites any
other stored id to pawwork and clears the cached CSS; context init
and onMount gate the stored id against knownThemes() before trusting
it. Regression tests cover oc-1, oc-2, dracula, nightowl, amoled.
- i18n: resolve zh-TW / zh-HK / zh-MO to zht instead of zh.
  Both detectors previously only treated strings containing the
  literal "hant" as Traditional Chinese, so region-form locales
  common on Taiwan/HK/Macao systems fell through to Simplified.
  Fixed in packages/app/src/context/language.tsx and
  packages/desktop-electron/src/renderer/i18n/index.ts with
  matching helpers and unit tests.

- theme: remove dead oc-2 branches and the now-unused normalize()
  remap from the theme context. With only `pawwork` bundled, the
  "known themes" gate is the single rule for onStorage / setTheme /
  previewTheme. Also trim the label map to just `pawwork`, removing
  residual OpenCode-era labels.

- brand: rebrand remaining user-visible "OpenCode" occurrences to
  PawWork: apple-mobile-web-app-title in favicon.tsx, desktop
  theme schema title/description, server-error fallback pointing
  at opencode.json, and the status-popover plugin-empty split
  token that keyed off "opencode.json" while the translation
  already says pawwork.json.
- Rewrite the theme-migration e2e ("legacy oc-1 -> oc-2" -> "legacy
  theme ids -> pawwork"). The old assertion lined up with the pre-
  Phase-1 two-theme world; the new one seeds `dracula` and checks
  migration to pawwork plus cached CSS cleanup, matching the actual
  preload logic.
- Skip two e2es that depended on multi-theme and dark-mode switching
  (color-scheme toggle, theme dropdown with >1 option). Phase-1
  bundles a single light-locked pawwork theme, so these tests can
  not meaningfully run until a dark palette or a second theme
  lands.
- Drop the dark-mode click + assertion from the font-rehydrate e2e
  and rename it accordingly, so the font persistence check still
  runs.
- Update the "changing language" e2e from Deutsch to 简体中文, the
  actual Phase-1 locale.
- Rename the tautological theme-preload test. The previous name
  ("does not touch localStorage when the stored theme is already
  PawWork") was wrong because preload unconditionally writes
  `opencode-color-scheme=light`; the renamed test now asserts that
  write and keeps the dark-mode override check honest.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Addressed the review plus two additional crosscheck rounds. Three follow-up commits pushed:

715612e41 fix(theme): migrate legacy theme ids to pawwork on startup

Fixes the original concern. oc-theme-preload.js and context.tsx now treat any stored theme id other than pawwork as legacy and migrate it to pawwork, clearing the cached CSS keys (opencode-theme-css-light/dark). No more stale dracula/nightowl/oc-1/oc-2 CSS flashing on upgrade. Regression tests in packages/app/src/theme-preload.test.ts cover oc-1, oc-2, dracula, nightowl, amoled.

691404eba fix(review): address crosscheck findings

Second crosscheck round (Codex + Claude) surfaced:

  • P1 zh-TW / zh-HK / zh-MO were resolving to Simplified Chinese because the detectors only matched the literal hant substring. Extracted isTraditionalChinese() helpers in packages/app/src/context/language.tsx and packages/desktop-electron/src/renderer/i18n/index.ts, unit tests added.
  • P2 Removed the dead oc-2 branches and the now-unused normalize() helper from packages/ui/src/theme/context.tsx; trimmed the theme label map to pawwork only.
  • P2 Rebrand residue: apple-mobile-web-app-title in favicon.tsx, schema title/description in desktop-theme.schema.json, server-errors.ts fallback, and the status-popover-body.tsx plugin-empty split token (was splitting the translation by opencode.json after the translation was updated to pawwork.json).

6aa109dcd fix(tests): address fresh crosscheck findings

Third round caught stale e2e tests:

  • Rewrote legacy oc-1 theme migrates to oc-2legacy theme ids migrate to pawwork and clear cached CSS, seeding dracula to match the Phase-1 behavior.
  • Skipped two e2es that depended on multi-theme and dark-mode switching (the color-scheme toggle and theme-dropdown count > 1 assertion). Phase-1 bundles a single light-locked pawwork theme, so these can't meaningfully run until a dark palette or a second theme lands; skip comments flag that.
  • Dropped the Dark-click + dark-mode assertion from the font-rehydrate e2e and renamed it accordingly — font persistence still exercised.
  • changing language e2e switched from Deutsch (removed locale) to 简体中文 / 通用.
  • Renamed the tautological preload test ("does not touch localStorage when the stored theme is already PawWork" was wrong because preload still writes opencode-color-scheme=light) and added the color-scheme assertion.

Pre-existing on dev, not this PR's regression, left for a future PR: zh/zht parity gap for command.project.next/previous and session.review.noBranch/NoUncommittedChanges; Config.update() hardcoded write to config.json; .opencode/ dotfolder rename; JSON schema $id URL; @opencode-ai/* package rename.

All tests green (bun test 330/330 app, 11/11 ui theme/preload, 3/3 electron i18n); bun run typecheck clean across all 7 workspaces.

The project-config loader in loadAll() called projectFiles("opencode", ...)
and stopped there, so a repo-level pawwork.json was never discovered on
startup even though the rest of the PR had switched write paths, help
text, and error messages to that filename. Walk the directory tree twice:
once for opencode.json(c) (legacy), once for pawwork.json(c). Merge
order preserves the rest of the cascade: pawwork files override opencode
files at the same level, matching how globalConfigFile and the managed-
dir loops already behave.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Confirmed — config.ts went through ConfigPaths.projectFiles("opencode", ...) only, so a project-root pawwork.json was invisible on startup.

Fixed in ff0d43105: walk the directory tree twice (opencode.json(c) first, pawwork.json(c) second) and feed both sequences into the existing merge loop. At the same directory level, pawwork wins over opencode, matching the precedence that globalConfigFile and the managed-dir loops already use. .opencode/ dotfolder configs are unchanged — that rename is still deferred.

bun run typecheck clean; bun test in packages/opencode: 1926 pass / 0 fail.

- Sidebar help button opened https://opencode.ai/desktop-feedback, which
  is an OpenCode feedback page and offers nothing to a PawWork user. Send
  it to the PawWork GitHub issues page instead, the actual place we track
  feedback.
- Release-notes highlight fetch pointed at opencode.ai/changelog.json, so
  existing upgrade paths would have shown OpenCode changelog entries in
  the "What's new" dialog. Switch to the GitHub Releases API for this
  repo and synthesize a single highlight per release from the release
  body's first meaningful line (markdown headings skipped, bullet
  markers stripped, truncated to 200 chars). The structured `highlights`
  schema remains supported for any future switch to a hosted
  changelog.json.

Added highlights.test.ts covering the new body-summary path and the
legacy schema regression.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Retargeted two remaining OpenCode URLs in c20614c20:

  • Sidebar help button (bottom-left ⓘ) pointed at opencode.ai/desktop-feedback. Switched to github.com/Astro-Han/pawwork/issues, the actual feedback surface.
  • "What's new" release-notes fetcher pointed at opencode.ai/changelog.json, which would have surfaced OpenCode changelog entries on the next version bump. Switched to the GitHub Releases API for this repo; parseRelease now falls back to synthesizing a single PawWork highlight from body when the structured highlights array is absent (markdown headings skipped, bullet markers stripped, truncated to 200 chars). Structured-schema path is preserved for any future switch to a hosted changelog.json. Tests cover both code paths.

Not touched in this PR (docs links to upstream OpenCode docs that are low-frequency and still useful for advanced users; queued as a separate docs-link-cleanup):

  • dialog-custom-provider.tsxopencode.ai/docs/providers/#custom-provider
  • settings-general.tsxopencode.ai/docs/themes/
  • opencode.ai/zen links are intentionally preserved (Zen is a real third-party provider).

The dev-only DebugBar pinned to the bottom-right corner was overlapping
session UI such as the "next step" button on the Show Case cards, making
parts of the app unreachable during local review. Add a persistent
collapse toggle: clicking the × shrinks the bar to a "debug" pill in the
same corner; clicking the pill re-expands it. State survives reload via
localStorage (`pawwork-debug-bar-collapsed`).
@Astro-Han

Copy link
Copy Markdown
Owner Author

Follow-up fb3d02a36: the dev-only DebugBar in the bottom-right corner was overlapping the "next step" button on Show Case cards during local review. Added a persistent collapse toggle — click × to shrink to a small "debug" pill in the same corner, click the pill to re-expand. State persists via localStorage (pawwork-debug-bar-collapsed). Dev-only (import.meta.env.DEV), no effect in packaged builds.

Separate product bug discovered while reviewing but out of scope for this PR, filed as #21: document-processing and data-analysis Show Case skills skip AskUserQuestion. Root cause is prompt-level (all three SKILL.md files only say "ask the user" in prose; need to name the tool), not code. Writing skill is unaffected.

P1: project config precedence. The `loadAll` loop called
`projectFiles("opencode")` and `projectFiles("pawwork")` separately,
then concatenated root→child sequences. A parent-directory
`pawwork.json` could therefore override a nearer child
`opencode.json`, breaking the "innermost wins" invariant used
elsewhere in the cascade. Extend `projectFiles` to accept an array
of names, interleaving them inside a single `findUp` pass. Callers
pass `["opencode", "pawwork"]`, so per-directory pawwork wins over
opencode while the innermost directory still wins overall.

P2: OAuth + uninstall brand residue. Auth success/failure browser
pages and the uninstall CLI intro/outro text still said "OpenCode".
Rebranded to PawWork.

P2: drop the tautological `oc-theme-preload` null assertions in
`theme-preload.test.ts`. The current preload script never creates
that element (context.tsx only removes it), so the assertions were
always true regardless of behavior.
P2 finish of the brand sweep:
- mcp/oauth-provider.ts: `client_name` and `client_uri` sent during
  OAuth registration were still "OpenCode" and "https://opencode.ai",
  so MCP provider consent screens showed the upstream brand instead
  of PawWork. Rebranded both.
- cli/cmd/tui/app.tsx: terminal window title and post-update dialog
  text still read "OpenCode" (and the session-title prefix was
  "OC | ..."). Rebranded to "PawWork" / "PW | ...".

P3 clean-up in theme-preload.test.ts: the "keeps PawWork light-only
even when system prefers dark" test mocked `matchMedia` to return
dark, but the current preload script never reads `matchMedia` - the
assertion only held because preload hardcodes light. Renamed the
test to describe what is actually verified (stored dark scheme is
overridden to light) and removed the dead mock.

Not in this PR, filed for follow-up:
- `.opencode/` directory cascade in config.ts:1433 merges in
  nearest-to-root order (via `Filesystem.up`), so outer project
  configs override inner ones. Pre-existing upstream behavior;
  untouched by this PR. Separate issue.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Round 6 crosscheck (both reviewers complete, no truncation). Two commits pushed:

34366ca9e fix: address fresh crosscheck findings

  • P1 project config precedenceConfigPaths.projectFiles now accepts an array of names; loadAll passes ["opencode", "pawwork"] so a single findUp pass interleaves them per directory. Innermost directory wins overall (via rootFirst); within the same directory pawwork wins over opencode. Fixes the case where a parent pawwork.json could override a nearer child opencode.json.
  • P2 brand residue in OAuth callback pages (codex.ts, oauth-callback.ts HTML_SUCCESS/ERROR titles + body text) and uninstall.ts CLI intro/outro/describe.
  • P2 tautological test — dropped getElementById("oc-theme-preload") null-checks that were always true (preload.js never creates that element).

27a29f91c fix(brand): MCP OAuth client + TUI terminal title

  • P2 mcp/oauth-provider.tsclient_name / client_uri sent during OAuth registration were still "OpenCode" / https://opencode.ai, visible on MCP provider consent pages. Rebranded.
  • P2 cli/cmd/tui/app.tsx — terminal window title + post-update dialog text + session-title prefix OC | ... rebranded to PawWork / PW | ....
  • P3 theme-preload test — renamed keeps PawWork light-only even when the system prefers dark to describe what's actually verified (stored dark scheme → forced to light). Dropped the dead matchMedia mock; the simplified preload script never reads matchMedia.

Pre-existing upstream bug filed separately as #22: .opencode/ directory cascade merges inner→outer, so outer configs override inner. Filesystem.up yields innermost-first and merge is last-wins, reversing the intended "innermost wins" precedence. PR #18 did not touch this iteration; fix needs its own review + regression tests.

Declined (intentional / out of scope):

  • STORAGE_KEYS / language cookie legacy opencode-* prefixes — preserved for read-compat with existing installs. Sweeping these would require a migration shim.
  • GitHub Releases API rate-limiting (403 silent fall-through in highlights.tsx) — Phase 1 acceptable.
  • Design proposal to centralize brand constants — valid but too invasive for this PR.

TUI brand sweep (5 user-visible strings that the first sweep missed
because they live in the CLI TUI, not the Electron renderer):

- routes/session/permission.tsx: "until OpenCode is restarted" ×2
  and "Tell OpenCode what to do differently" rebranded.
- feature-plugins/sidebar/footer.tsx: the Getting-started footer line
  "OpenCode includes free models" rebranded.
- feature-plugins/home/tips-view.tsx: five prose tips rebranded
  (OAuth auto-handle, auto-format, LSP, plugin example, `opencode
  serve` description). CLI command strings themselves (`opencode
  run`, `opencode serve`, etc.) are left alone because the binary
  name is `opencode`; renaming that belongs with the
  `@opencode-ai/*` package-rename PR.

Comments (no behavior change):
- oc-theme-preload.js: note that unconditional `color-scheme=light`
  write assumes pawwork is the only bundled theme and is
  light-locked; must become theme-aware when a dark-capable theme
  lands (tracked in #23).
- config.ts project-root cascade: expand the precedence comment to
  cross-reference `Filesystem.findUp({ rootFirst: true })` semantics
  so a future refactor does not accidentally flip the invariant.
- config.ts managed-dir cascade: mirror the same "pawwork wins
  within directory" comment that the project-root site already has.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Round 7 (final) crosscheck — both reviewers complete, no truncation. One commit 753357ad3 pushed:

TUI brand sweep (user-visible strings the earlier sweep missed):

  • routes/session/permission.tsx × 3 — "until OpenCode is restarted" × 2 and "Tell OpenCode what to do differently"
  • feature-plugins/sidebar/footer.tsx — "OpenCode includes free models" on the Getting Started footer
  • feature-plugins/home/tips-view.tsx × 5 — prose tips describing OAuth auto-handle, auto-format, LSP, plugin example, and opencode serve

CLI command strings (opencode run, opencode serve, opencode upgrade, etc.) kept as-is because the binary name is still opencode; renaming that lives with the @opencode-ai/* package rename PR.

Comments (no behavior change):

  • oc-theme-preload.js top-of-file note: the unconditional color-scheme=light write assumes pawwork is the only bundled light-locked theme; future dark-capable theme must add a guard. Tracked in #23.
  • config.ts project-root cascade comment expanded to cross-reference Filesystem.findUp({ rootFirst: true }) semantics so a future refactor can't silently flip innermost-wins.
  • config.ts managed-dir cascade now carries the same "pawwork wins within directory" explanation that the project-root site had; the two sites were identical in logic but one was undocumented.

Deferred to #23: the color-scheme settings dropdown shows system/light/dark even though pawwork is light-locked. Pawwork-dark is next up; the dropdown becomes functional when that lands. Not patched in this PR to avoid throwaway interim UI.

Declined as out of scope / intentional:

  • summarizeBody dropping #-only release bodies — test-confirmed intended behavior; real release bodies typically have content bullets under headings.
  • oc_locale cookie name on the write path — kept aligned with the read-compat policy (changing would orphan existing users' language preference).

14 commits total on this branch, 7 crosscheck rounds passed.

P1 defensive / user-visible fixes:
- oc-theme-preload.js: wrap localStorage reads and writes in try/catch.
  Private-mode / storage-disabled browsers would otherwise throw before
  the dataset attributes are set, producing an unstyled first paint.
- highlights.tsx: log the HTTP status when the GitHub releases fetch
  returns non-ok (403 rate-limit, 304 not-modified, 404, etc). Previously
  silently discarded; now at least visible in devtools for diagnosis.

P2 user-visible brand routing:
- error-component.tsx (TUI crash reporter): retarget the "open issue"
  URL from github.com/anomalyco/opencode to github.com/Astro-Han/pawwork
  so PawWork crash reports land in the PawWork repo, not upstream.
  Also rename `opentui: fatal:` title prefix and `opencode-version`
  query param to pawwork equivalents.
- tui/app.tsx "Open docs" action, dialog-custom-provider "Learn more",
  and settings-general theme "Learn more": all retargeted from
  opencode.ai/docs/... to github.com/Astro-Han/pawwork#readme. PawWork
  has no standalone docs site yet; README is the current source of truth.

P2 remove OpenCode Go upsell: PawWork does not resell or integrate with
OpenCode Go paid tier. Deleted `dialog-go-upsell.tsx`, its detection
kv keys and `event.on("session.status", ...)` handler in
routes/session/index.tsx, and the `GO_UPSELL_MESSAGE` constant + its
FreeUsageLimitError branch in session/retry.ts (now just returns a
plain "Free usage exceeded").

P2 dev-only a11y (debug-bar): bumped the collapsed pill and the inline
close button from `opacity-40` → `opacity-60` and added
`focus-visible:ring-2 focus-visible:ring-interactive-base`. Previously
the pill was near-invisible for keyboard users with no focus style.

P3 remove stale tips: two tips-view.tsx entries referenced functionality
we don't ship — `/share` which publishes to opencode.ai and a
`ghcr.io/anomalyco/opencode` docker image. Neither PawWork has its own
share service nor a docker distribution; deleted the tips.
@Astro-Han

Copy link
Copy Markdown
Owner Author

Round 8 crosscheck results addressed in b009a46e4 (11 files, +28 -144, net reduction):

P1 defensive / diagnostic:

  • oc-theme-preload.js: wrap localStorage calls in try/catch so private-mode / blocked-storage browsers don't throw before the dataset attributes are set.
  • highlights.tsx: log HTTP status on non-ok GitHub API response. Previously silent — 403 rate-limit, 304, 404, all dropped without a trace. Now visible in devtools.

P2 brand routing:

  • error-component.tsx (TUI crash reporter): retargeted github.com/anomalyco/opencode/issues/newgithub.com/Astro-Han/pawwork/issues/new so PawWork crash reports land in this repo, plus renamed the opentui: fatal: title prefix and opencode-version query param.
  • tui/app.tsx Open docs, dialog-custom-provider Learn more, settings-general theme Learn more: all three opencode.ai/docs/... links retargeted to github.com/Astro-Han/pawwork#readme. README is the current docs source of truth (no standalone docs site yet).

P2 remove OpenCode Go upsell (net −95 lines):

  • Deleted dialog-go-upsell.tsx entirely.
  • Removed the session.status event handler in routes/session/index.tsx that showed the upsell + its kv dedup keys (go_upsell_last_seen_at, go_upsell_dont_show, go_upsell_window).
  • Removed SessionRetry.GO_UPSELL_MESSAGE constant + the FreeUsageLimitError branch in retry.ts; the error now just returns a plain "Free usage exceeded".
  • PawWork doesn't integrate with or resell OpenCode Go; the upsell pointing to opencode.ai/go was misleading.

P2 dev-only a11y (debug-bar): pill + close button bumped from opacity-40opacity-60 plus focus-visible:ring-2 focus-visible:ring-interactive-base. Keyboard users can now see the pill and focus ring.

P3 stale tips: removed two tips-view.tsx entries referencing unshipped services — /share (publishes to opencode.ai) and ghcr.io/anomalyco/opencode docker image.

Declined / intentional (in order of the review table):

  • Theme context.tsx init vs onMount duplication (P2): non-regression, single-threaded JS between those steps gives no observable flicker. Upstream pattern.
  • ids() memoization (P2): single-theme today, O(1); deferred until a second theme ships.
  • summarizeBody emoji surrogate boundary split (P2): real edge case but impact is cosmetic (half-emoji at position 200), release body first lines rarely contain emoji.
  • debug-bar Show/fallback indent quirk (P3): pure style nit.

15 commits, 8 crosscheck rounds passed.

- error.ts: drop "opencode" subject from MCP failure; remove stale
  `opencode models` hint, keep pawwork.json config pointer
- config.ts: remove $schema auto-inject that silently wrote
  https://opencode.ai/config.json into user files; delete its test
- config.ts + paths.ts: extract PROJECT_CONFIG_NAMES /
  PROJECT_CONFIG_FILENAMES with ordering invariant comment; replace
  4 hardcoded filename arrays (global, project, managed, .opencode)
  so pawwork-wins-over-opencode precedence has a single source
- config.test.ts: add regression test pinning pawwork.json vs
  opencode.json same-directory precedence
- theme context: add canSwitchColorScheme() accessor; settings-general
  hides color-scheme row and layout only registers theme.scheme.* /
  theme.cycle commands when actually switchable, so Phase 1 ships no
  no-op controls or command-palette entries
- initialize.txt: "OpenCode config" -> "PawWork config"
- theme-preload.test: merge duplicate color-scheme locking test
- config.ts: de-brand tui-keys deprecation log
- desktop-electron notification: remove external opencode.ai icon URL;
  Electron falls back to the packaged PawWork app icon
- sidebar project avatar: delete OPENCODE_PROJECT_ID special-case that
  pulled https://opencode.ai/favicon.svg for upstream's demo project
  (PawWork users never have that project ID)
- ACP handshake: rename user-visible labels to PawWork (authMethod name,
  terminal-auth label, agentInfo.name). The `opencode auth login`
  instruction stays literal since the CLI binary is still named
  opencode (rename blocked on Zen proxy header work).

Deliberately not addressed in this PR:
- TUI dialog-provider OpenCode Go copy: TUI is out of Phase 1 GUI scope
- GUI dialog-select-provider opencode-go "Recommended" tag: the service
  name is explicitly preserved per PR scope; the recommendation curation
  is a separate product question, not brand residue
@Astro-Han Astro-Han merged commit 0ae1d45 into dev Apr 18, 2026
11 of 13 checks passed
@Astro-Han Astro-Han deleted the worktree-branding-cleanup branch April 18, 2026 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant