feat: split desktop panel and thread locale into skills#2
Merged
Conversation
Remove JSON examples and `question` tool name references from all three
built-in skills. Gate blocks now use natural language flow control
("ask clarifying questions first, then act") instead of binding to a
specific tool, following the Superpowers skill pattern. Models pick the
right tool from the tool list at runtime.
This was referenced Apr 23, 2026
Astro-Han
added a commit
that referenced
this pull request
Apr 23, 2026
Replace the three generic developer-oriented icons with mockup-faithful custom SVGs (folder / bar-chart / pencil) tinted per Skill (warm orange / success green / violet) via semantic design tokens plus one arbitrary hex for violet since no violet token exists in the design system. Card visual switches from vertical card with description text to inline pill (icon + title side by side, no description), matching the mockup's light button style. Neutral chip border at rest, lifted border on hover. Click behavior unchanged. Home shell layout refines to match the #151 mockup: shift content down via pt-[28vh], compact title→subtitle→pills rhythm, restore subtitle with new copy "PawWork 可以帮你处理文件、分析信息、撰写内容并完成各类任务。" and its English counterpart. The upstream Icon component is kept in sidebar-items.tsx for the skill badge (falls back to folder / status / pencil-line), so badge icons differ from home for data-analysis during the PR #1 → PR #2 interval; PR #2 removes the badge entirely. Refs #151 (PR #1 commit 2 of 2).
Astro-Han
added a commit
that referenced
this pull request
Apr 23, 2026
Replace the three generic developer-oriented icons with mockup-faithful custom SVGs (folder / bar-chart / pencil) tinted per Skill (warm orange / success green / violet) via semantic design tokens plus one arbitrary hex for violet since no violet token exists in the design system. Card visual switches from vertical card with description text to inline pill (icon + title side by side, no description), matching the mockup's light button style. Neutral chip border at rest, lifted border on hover. Click behavior unchanged. Home shell layout refines to match the #151 mockup: shift content down via pt-[28vh], compact title→subtitle→pills rhythm, restore subtitle with new copy "PawWork 可以帮你处理文件、分析信息、撰写内容并完成各类任务。" and its English counterpart. The upstream Icon component is kept in sidebar-items.tsx for the skill badge (falls back to folder / status / pencil-line), so badge icons differ from home for data-analysis during the PR #1 → PR #2 interval; PR #2 removes the badge entirely. Refs #151 (PR #1 commit 2 of 2).
This was referenced Apr 25, 2026
Astro-Han
added a commit
that referenced
this pull request
May 4, 2026
…428) Issue #428: SessionTurn used `findLast` over assistant messages, so any user prompt that triggered multiple assistant rounds (compaction, tool retries, multi-tool plans) silently lost earlier file changes from the Changes block. Users could no longer review or undo most of what the agent had written. This PR aggregates every assistant message that shares `parentID === userMessageID` into one turn-level Changes block with a single Undo / Reapply control. ## Backend (packages/opencode) - `RESTORE_LIMIT` raised from 2 MB to 20 MB so multi-step edits in one user turn fit in the restore table; the 2 MB display window still gates the diff panel. - `aggregateTurnInternal` collects all assistant messages under the same userMessageID, collapses RestoreRow entries by absolute path (preserving first-seen `before`, taking last-seen `after`), and runs a second-pass `disambiguateAggregatedRestoreFiles` so two sibling assistants editing different opaque external paths sharing a basename do not collide on the same `displayPath` (e.g. `/tmp/a/config.json` and `/tmp/b/config.json` become `config.json` and `config.json · external #2`). - `preflightTurn` chains a virtual-disk state map across messages so chained same-file edits across two assistants no longer false-conflict; classifies per-message blocked items into three tiers matching single-message `mutate()` (`permission_denied` > `unsupported_size` > `conflict`); returns fatal `unsupported_size` immediately when any target state is non-restorable, so an aggregated undo/redo with one oversized/binary file blocks the whole turn instead of partially mutating sibling assistants under `force=true`. - `mutateTurn` runs preflight first; with `force=false` returns `blocked` on any skip, with `force=true` skips the conflicting message, mid-loop rollbacks completed messages on a per-iteration write failure, and reports `mutatedPaths` (only paths actually written) plus `skipped[]`. Rollback failures surface as a dedicated `rollback_failed` reason rather than being collapsed into `write_failed`. - New HTTP routes: `GET /session/:sessionID/turn/:userMessageID/changes`, `POST .../changes/undo`, `POST .../changes/redo` with `{ force: boolean }` body. `publishTurnChangeFiles` filters to `mutatedPaths` so File events only fire for paths that were really touched. - White-busy filter: files created and then deleted within the same turn drop out of the aggregated display so they never reach the user as a phantom change. - Mixed-state turn (one assistant applied, another undone) keeps both Undo and Reapply available; intentional single-button choice documented inline. ## Frontend (packages/app, packages/ui) - `SessionTurn` no longer uses `findLast`. The Changes block renders the aggregated `display.files` with one Undo / Reapply button, an additions/deletions summary, and per-file status. Status badge for fully undone turns and a Reapply control are new. - New helper module `turn-change-fetch.ts` plus `turn-change-fetch.test.ts` derive the fetch signature and target list from completed assistant siblings, so the timeline re-fetches when a new sibling assistant under the same parent completes. - Conflict path: when preflight returns `blocked` with `reason: "conflict"`, a Kobalte Dialog confirms with the user, lists the skipped paths in a tinted bordered panel (`+N more` overflow label localized via `ui.sessionTurn.turnChanges.confirmListMore` in en + zh), and re-issues the request with `force=true`. A yellow skipped notice on the bottom of the Changes block surfaces partial-skip outcomes after a force apply. - Trailing icons (open file / show in folder) now have `<Tooltip>` wrappers; Changes panel rows tightened (header 48 -> 36, action 28 -> 24, row 44 -> 32, chevron 24 -> 20) to fit denser turns without scrolling. - Retry hardening: a 500 ms re-fetch on initial empty response, plus a `createEffect(on(sessionID, ...))` that cancels pending retry timers and clears `fetchedTurnChanges` when the active session changes, so a stale retry queued under the previous session cannot land on a freshly opened one. - Marks the message dirty when rollback blocks with no files so the UI does not stay in a stuck loading state. - English copy polished for `session.turnChange.blocked.*`: contractions, jargon removed, references the user's brand name. ## Tests New regression coverage in `turn-change-aggregate.test.ts` and `turn-change-aggregate-routes.test.ts`: - collapse two assistants editing different files into one display - collapse same-file edits across two assistants into single net diff - white-busy file (created then deleted) filtered out - ignore assistant messages with a different parent - undo / redo all assistant changes in a turn - block whole turn on conflict by default; `force=true` reports `skipped[]` - chained same-file edits undo cleanly without false conflict - two assistants editing different absolute paths sharing a basename do not merge - opaque external basenames from sibling assistants disambiguate after aggregation - mixed-state turn keeps both undo and redo available - `aggregateTurnUndo` reports `mutatedPaths` only for messages actually written - preflight returns fatal `unsupported_size` when any assistant has an unrestorable target (both `force=false` and `force=true`) - `MutationResultSchema` accepts `rollback_failed` as a blocked reason Plus existing `turn-change.test.ts` extended for the new restore-limit boundaries (medium and huge file states). ## Verification - typecheck across 9 packages (tsgo): green - packages/opencode session + server tests: 594 passed / 4 skipped / 1 todo / 0 failed across 44 files - Manual UI verification (Electron): two-assistant turn with three files (one shared), tampered-file conflict path, force-apply skipped notice - Two rounds of crosscheck (Claude Opus + Codex), one round of CodeRabbit review (4 inline comments addressed) ## Risk Notes - 20 MB per-file restore quota grows the SQLite turn-change tables for sessions with very large edits; existing per-message rows still apply, no migration. - Aggregate route is additive; legacy single-message `/turn-change/:messageID/{undo,redo}` endpoints unchanged. - Force-undo with conflicts is now a partial operation; the UI renders a skipped notice and File events only fire for `mutatedPaths`. Closes #428.
This was referenced May 5, 2026
Astro-Han
added a commit
that referenced
this pull request
May 5, 2026
…ssue #440) Slice #1 of eleven. Establishes the semantic token foundation for all subsequent PawWork UI component slices (#2–#11). This is a permanent carve-out from upstream opencode — see AGENTS.md §Upstream Sync and .gitattributes. ## What changed - theme.css: full rewrite against PawWork STANDARDS (warm neutrals, brand orange #ff5910, 13px dense, system-font). Three-selector structure: :root (light) → [data-color-scheme="dark"] (authoritative dark) → @media mirror Fixes a latent upstream bug: @media-only meant the Settings toggle had no effect. - pawwork.json: rewritten to STANDARDS values with new token names. - colors.txt → tailwind/colors.css: 104 tokens (incl. legacy compat aliases); regenerated Tailwind --color-* bridge via script/tailwind.ts. - 50+ token renames across 144 component files in packages/ui/src and packages/app/src. - HTML entry files (app/index.html, desktop-electron renderer/*.html): updated to var(--bg-base) and synced theme-color meta. Now in .gitattributes carve-out. - UNREGULATED section in theme.css: holds legacy compat aliases (button-brand-*, icon-success-base, icon-info-base, icon-on-interactive-base, surface-base-active) so existing component consumers stay styled without entering STANDARDS managed set. - .gitattributes: added merge=pawwork-keep-ours driver entries for packages/ui/** and key packages/app paths. Driver must be registered per-clone: git config merge.pawwork-keep-ours.driver "true" Verify before upstream sync: bash packages/ui/script/verify-merge-driver.sh ## Tests added - packages/ui/test/theme-parity.test.ts (128 assertions, 0 fail): light root ↔ pawwork.json light.overrides, dark block ↔ dark.overrides, dark completeness (SAME_IN_DARK set), @media mirror exact-match, and two runtime-critical non-regulated token assertions (--text-mix-blend-mode: plus-lighter). - packages/ui/test/undefined-tokens.test.ts: Scans every var(--xxx) in theme.css, Tailwind bridge, and HTML entry files; asserts each resolves to a definition. ## Deferred to slice #2 - colors.txt ↔ colors.css generation consistency test (manual regen + review for now) - TSX/class utility audit (old token utility names, misspelled utilities) - --surface-base-active classification (state token vs. compat bridge) - Legacy runtime token deprecation checklist ## Key decisions for future agents 1. [data-color-scheme="dark"] is authoritative. @media block is mirror-only (first-paint). Both must stay in sync — theme-parity.test.ts enforces this. 2. UNREGULATED section in theme.css is intentional scope. Tokens there are consumed by components but not STANDARDS-managed. Do not promote to regulated without adding to pawwork.json and updating the parity test. 3. The merge driver only fires on two-sided conflicts. One-sided upstream changes still clean-merge. Always review upstream-sync PR diffs for carve-out paths. 4. colors.css is a generated file (do not hand-edit). Regen: bun run script/tailwind.ts.
Astro-Han
added a commit
that referenced
this pull request
May 5, 2026
…ssue #440) Slice #1 of eleven. Establishes the semantic token foundation for all subsequent PawWork UI component slices (#2–#11). This is a permanent carve-out from upstream opencode — see AGENTS.md §Upstream Sync and .gitattributes. ## What changed - theme.css: full rewrite against PawWork STANDARDS (warm neutrals, brand orange #ff5910, 13px dense, system-font). Three-selector structure: :root (light) → [data-color-scheme="dark"] (authoritative dark) → @media mirror Fixes a latent upstream bug: @media-only meant the Settings toggle had no effect. - pawwork.json: rewritten to STANDARDS values with new token names. - colors.txt → tailwind/colors.css: 104 tokens (incl. legacy compat aliases); regenerated Tailwind --color-* bridge via script/tailwind.ts. - 50+ token renames across 144 component files in packages/ui/src and packages/app/src. - HTML entry files (app/index.html, desktop-electron renderer/*.html): updated to var(--bg-base) and synced theme-color meta. Now in .gitattributes carve-out. - UNREGULATED section in theme.css: holds legacy compat aliases (button-brand-*, icon-success-base, icon-info-base, icon-on-interactive-base, surface-base-active) so existing component consumers stay styled without entering STANDARDS managed set. - .gitattributes: added merge=pawwork-keep-ours driver entries for packages/ui/** and key packages/app paths. Driver must be registered per-clone: git config merge.pawwork-keep-ours.driver "true" Verify before upstream sync: bash packages/ui/script/verify-merge-driver.sh ## Tests added - packages/ui/test/theme-parity.test.ts (128 assertions, 0 fail): light root ↔ pawwork.json light.overrides, dark block ↔ dark.overrides, dark completeness (SAME_IN_DARK set), @media mirror exact-match, and two runtime-critical non-regulated token assertions (--text-mix-blend-mode: plus-lighter). - packages/ui/test/undefined-tokens.test.ts: Scans every var(--xxx) in theme.css, Tailwind bridge, and HTML entry files; asserts each resolves to a definition. ## Deferred to slice #2 - colors.txt ↔ colors.css generation consistency test (manual regen + review for now) - TSX/class utility audit (old token utility names, misspelled utilities) - --surface-base-active classification (state token vs. compat bridge) - Legacy runtime token deprecation checklist ## Key decisions for future agents 1. [data-color-scheme="dark"] is authoritative. @media block is mirror-only (first-paint). Both must stay in sync — theme-parity.test.ts enforces this. 2. UNREGULATED section in theme.css is intentional scope. Tokens there are consumed by components but not STANDARDS-managed. Do not promote to regulated without adding to pawwork.json and updating the parity test. 3. The merge driver only fires on two-sided conflicts. One-sided upstream changes still clean-merge. Always review upstream-sync PR diffs for carve-out paths. 4. colors.css is a generated file (do not hand-edit). Regen: bun run script/tailwind.ts.
11 tasks
Astro-Han
added a commit
that referenced
this pull request
May 5, 2026
…#2, issue #440) (#448) ## Slice 02 of issue #440 — token housekeeping, typography wiring, icon CSS, colors-generation test **Commits squashed (7):** - refactor(ui): add icon color state selectors and document size tiers - refactor(ui): replace inline font-size literals with font-size tokens - refactor(ui): remove shadow/blend tokens from Tailwind --color-* namespace - refactor(ui): promote --surface-base-active to REGULATED token section - test(ui): add colors.txt ↔ colors.css generation consistency check - test(ui): align colors-generation parser with generator script - test(ui): add duplicate-token guard to colors-generation test **Why:** - Icon CSS now declares `[data-color]` state selectors for strong/weak/disabled; size tiers (small/normal/medium/large) documented in comment - All inline `font-size` px literals in component CSS replaced with `var(--font-size-*)` tokens; establishes consistent token dependency chain - Shadow, blend, and overlay tokens removed from `--color-*` Tailwind namespace — those utilities were never used and conflated design-token categories - `--surface-base-active` moved from ad-hoc section to REGULATED block so downstream color-generation tests can pick it up - New bidirectional consistency test (colors.txt ↔ tailwind/colors.css) catches stale generated artifacts; parser aligned with generator logic (`split(":")[0].trim().substring(2)`) and token-name charset relaxed to `[^\s:]+` to handle non-kebab names; duplicate-token guards added to prevent silent Set-dedup masking **Key decisions:** - Parser uses same `split(":")[0]` approach as `script/tailwind.ts` — not a regex — so any future token-name character additions are automatically handled - `indexOf`-based dedup check preferred over frequency-map approach: simpler and directly catches the actual failure mode (duplicate in one file) - Desktop-smoke runner flake (11+ min stuck run) diagnosed as GitHub macOS runner congestion, not a code regression; rerun passed in 2m54s
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verification
packages/app:bun test --preload ./happydom.ts ./src/context/layout.test.ts ./src/components/prompt-input/submit.test.ts ./src/components/session/session-new-view.test.tspackages/app:bun x playwright test e2e/commands/panels.spec.tspackages/opencode:bun test ./test/session/system.test.ts ./test/session/prompt.test.ts ./test/skill/skill.test.ts --timeout 30000packages/opencode:bun run typecheckpackages/sdk/js:bun run typecheckNotes
packages/appbun run typecheckin this worktree still resolves@opencode-ai/sdkthrough the shared borrowednode_modulesfrom the main checkout, so it reports stale pre-locale request types instead of the regenerated SDK types in this branch.