545cd0b599
Move task plugin actions and destinations into the shared mobile Plugins menu, preserving a compact task header and accessible touch targets. Add focused mobile coverage, plugin authoring documentation, and process-probe stability handling.
8.1 KiB
8.1 KiB
id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
| id | title | status | wave | depends_on | plan | requirements | acceptance_criteria | system_design | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-move-task-plugins | Move task plugins into the phone menu | done | 1 | plan.md |
|
|
|
Task 01: Move Task Plugins into the Phone Menu
Summary
Add an explicit responsive contract to the task session plugin slot, move its phone presentation from the fixed task header into the shared menu's Plugins section, and prove it with the packaged plugin fixture. Preserve the inline tablet/desktop surface and all existing task and session context.
In scope
- Add RED component and contract assertions before production changes.
- Export and consume the canonical
ChatTopBarSlotPropsSDK type with a desktop/mobile presentation. - Add the mobile containment wrapper and reactive registration-presence check.
- Thread phone task plugin content through
AppNavSheet,AppNavSections, andMobilePluginNavSection. - Remove the inline phone plugin slot while retaining first-party controls.
- Update the plugin API reference and public authoring guide.
- Extend the packaged fixture and add the mobile Playwright regression after a focused component assertion records the fixed-header placement failure.
- Verify long-title geometry, wrapping, interaction, menu focus/dismissal, and zero document overflow through the managed production build.
- Capture and validate the synthetic closed-header and open-menu PR assets.
Out of scope
- First-party task header action placement.
- Backend or persisted-state changes.
- Publishing screenshot binaries on the PR branch;
/prpublishes ignored capture output on the dedicated media ref. - Reusing the user's attached screenshot in a public PR.
Acceptance
- The fixed phone header never contains a
chat-top-barregistration, and the same registration appears in the shared Plugins section only when present. - Mobile slot props preserve task/session identity, report
presentation: "mobile", wrap within the menu, and give host buttons a minimum 44px active target; desktop reportspresentation: "desktop"and keeps existing markup. - The combined Plugins section renders once, preserves plugin link dismissal, and disappears when it has neither actions nor destinations.
- A real packaged plugin with multiple contributions leaves a synthetic long-title phone header usable, stays inside the menu viewport, activates its control, and produces both expected PR-capture manifest entries.
ASCII UI preview
UI-01: Phone task header with plugin contributions
Full preview: plan.md.
Before: | < | task... | [plugin] [status] | = |
After: | < | task identity + branch... | = |
Menu: Plugins
[plugin action] [session status]
[plugin destination]
The fixed header owns task identity and the menu trigger. The existing menu
owns wrapping plugin content. Maps to
AC-UI-MOBILE-TASK-CHROME-001.5, .6, and .7.
Verification
(cd apps && pnpm install --frozen-lockfile)
(cd apps && pnpm --filter @kandev/web test -- --run components/task/task-top-bar-plugin-actions.test.tsx components/task/mobile/session-mobile-top-bar.test.tsx components/plugins/mobile-plugin-nav-section.test.tsx components/navigation/app-nav-sheet.test.tsx lib/plugins/sdk-contract.test.ts)
(cd apps && pnpm --filter @kandev/plugin-sdk typecheck)
(cd apps && pnpm --filter @kandev/web exec eslint components/task/task-top-bar-plugin-actions.tsx components/task/task-top-bar-plugin-actions.test.tsx components/task/mobile/session-mobile-top-bar.tsx components/task/mobile/session-mobile-top-bar.test.tsx components/plugins/mobile-plugin-nav-section.tsx components/plugins/mobile-plugin-nav-section.test.tsx components/navigation/app-nav-sheet.tsx components/navigation/app-nav-sheet.test.tsx components/navigation/app-nav-sections.tsx lib/plugins/types.ts lib/plugins/sdk-contract.test.ts)
(cd apps/web && pnpm run typecheck)
(cd apps/web && CAPTURE_PR_ASSETS=true pnpm e2e:run --project mobile-chrome e2e/tests/plugins/mobile-plugin-topbar.spec.ts)
test -s apps/web/.pr-assets/manifest.json
node -e 'const fs=require("fs"); const m=JSON.parse(fs.readFileSync("apps/web/.pr-assets/manifest.json","utf8")); const names=m.assets?.map((a)=>a.file??a.name)??[]; for (const expected of ["mobile-task-plugin-header.png","mobile-task-plugin-menu.png"]) { if (!names.some((name)=>String(name).endsWith(expected))) throw new Error(`missing ${expected}`); }'
node --test scripts/validate-public-docs.test.mjs
node scripts/validate-public-docs.mjs
python3 scripts/list-docs.py validate
python3 scripts/lint-spec-files.py --all
git diff --check -- apps/packages/plugin-sdk apps/web docs/public docs/plans/plugins docs/specs/ui docs/plans/mobile-task-plugin-menu
Files likely touched
apps/packages/plugin-sdk/src/index.tsapps/web/lib/plugins/types.tsapps/web/lib/plugins/sdk-contract.test.tsapps/web/components/task/task-top-bar-plugin-actions.tsxapps/web/components/task/task-top-bar-plugin-actions.test.tsxapps/web/components/task/mobile/session-mobile-top-bar.tsxapps/web/components/task/mobile/session-mobile-top-bar.test.tsxapps/web/components/task/mobile/session-mobile-top-bar-repository.test.tsxapps/web/components/navigation/app-nav-sheet.tsxapps/web/components/navigation/app-nav-sheet.test.tsxapps/web/components/navigation/app-nav-sections.tsxapps/web/components/plugins/mobile-plugin-nav-section.tsxapps/web/components/plugins/mobile-plugin-nav-section.test.tsxapps/backend/cmd/plugin-fixture/fixture-package/ui/bundle.jsapps/web/e2e/fixtures/plugins/prompt-history-plugin/bundle.jsapps/web/e2e/tests/plugins/mobile-plugin-topbar.spec.tsdocs/plans/plugins/PLUGIN-API.mddocs/public/plugins-authoring.mdapps/web/.pr-assets/manifest.json(ignored capture output)apps/web/.pr-assets/mobile-plugin-topbar--mobile-task-plugin-header.png(ignored capture output)apps/web/.pr-assets/mobile-plugin-topbar--mobile-task-plugin-menu.png(ignored capture output)
Dependencies
None.
Risks
- The slot accepts opaque plugin markup; enforce host containment without assuming a plugin's internal DOM shape beyond documented host buttons.
- Do not render an empty Plugins heading during registry install/uninstall.
- Fixture registrations are shared by tests that install the package; keep them inert until a task detail page mounts the slot and retain the existing listing scenario in the focused E2E run.
- Wait for finite drawer animations before geometry or screenshot reads.
Parallelism
sequential
Inputs
AC-UI-MOBILE-TASK-CHROME-001.5,.6, and.7.docs/specs/ui/system-design/mobile-task-chrome.md, especially Components and responsibilities, Plugin contribution, and Mobile design contract.apps/web/components/kanban/main-top-bar-plugin-actions.tsxandapps/web/components/kanban/mobile-listing-menu-actions.tsxas the shipped responsive slot exemplar.apps/web/e2e/tests/plugins/mobile-plugin-topbar.spec.ts,apps/web/e2e/helpers/layout-assertions.ts, andapps/web/e2e/helpers/animations.tsfor production-build proof.apps/web/e2e/fixtures/test-base.tsprCapturefixture.
Results
- RED: the phone-header component test failed because the plugin action was
still inside
mobile-topbar-actions; it passed after the menu handoff. - Focused Vitest suite: 49 tests passed.
- Plugin SDK typecheck, web typecheck, and targeted ESLint passed.
- Managed production-build mobile E2E: 2 tests passed with the packaged plugin.
- Both synthetic PR screenshots are present in the capture manifest and were visually checked.
- Review fixup scoped the 44px guarantee to
host.ui.Button, corrected the documented phone placement formain-top-bar, and reran the managed mobile E2E scenarios successfully after updating the fixture action. - Public-doc and specification validation passed; final diff checks passed.