Files
2026-05-27 23:29:53 +01:00

5.5 KiB

Tasks: enterprise-browser-react-command-palette

Change ID: enterprise-browser-react-command-palette Package: @suaveplan/react-command-palette Target path: browser/react/react-command-palette Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/schema-registry


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree per proposal.md.
  • package.json v0.0.0, "sideEffects": false.
    • dependencies: @suaveplan/error workspace:^, @suaveplan/events workspace:^, @suaveplan/logger workspace:^, @suaveplan/schema-registry workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build, react catalog:react
    • peerDependencies: react, react-dom
    • devDependencies: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, happy-dom catalog:testing, @testing-library/react catalog:testing, @suaveplan/testing workspace:^, @suaveplan/testing-dom workspace:^
    • Subpath exports: ".", "./utils/fuzzy-search", "./core/history/history", "./core/command-palette/command-palette", "./components/command-palette"
  • tsconfig.json, vitest.config.ts (pool: forks, happy-dom environment).

2. Error codes

  • HISTORY_STORAGE_FAILED, COMMAND_INVALID.
  • registerCommandPaletteErrorCodes() — call eagerly.

3. Types (src/types/common.ts)

  • CommandItem, CommandPaletteConfig, CommandPaletteState, CommandPaletteActions, CommandPaletteInputProps, FuzzyMatch, HistoryConfig.
  • Write common.md.

  • fuzzy-search.ts — fuzzySearch(items, query) returning ranked FuzzyMatch[]; fuzzyScore(item, query) with configurable weights (exact-match, prefix, subsequence).
  • Write fuzzy-search.test.ts (exact match, prefix, subsequence, empty, special chars). Write fuzzy-search.md.

5. StorageAdapter interface (src/core/storage-adapter/)

  • storage-adapter.ts — StorageAdapter interface: get(): CommandItem[], set(items: CommandItem[]): void, clear(): void.
  • LocalStorageAdapter default implementation; MemoryAdapter for tests.
  • Write storage-adapter.test.ts. Write storage-adapter.md.

6. CommandHistory (src/core/history/)

  • history.ts — CommandHistory(config): injectable StorageAdapter, maxSize, add(item), get(), clear().
  • Validate CommandItem via CommandItemSchema on add(); throw COMMAND_INVALID on failure.
  • Throw HISTORY_STORAGE_FAILED on storage adapter error.
  • Write history.test.ts (add, evict over max, clear, storage failure). Write history.md.

7. useCommandPalette hook (src/core/command-palette/)

  • command-palette.ts — hook: open/close, input binding, keyboard navigation, result filtering, selection.
  • CommandPaletteInputProps includes role="combobox", aria-expanded, aria-activedescendant, aria-autocomplete.
  • Wire OTel counters + histogram palette.filter_ms.
  • Split tests into files ≤ 500 lines by responsibility: open/close, filtering, navigation, history integration, config.
  • Write command-palette.md.

8. CommandItem schema (src/schema/command-item-schema/)

  • command-item-schema.ts — Zod CommandItemSchema; registerCommandItemSchema() in @suaveplan/schema-registry.
  • Write command-item-schema.md.

9. Reference CommandPalette component (src/components/command-palette/)

  • command-palette.tsx — consumes useCommandPalette; renders input + results list.
  • placeholder from props; passes through to i18n resolver for default.
  • Axe-core clean: role="dialog", focus trap, aria-live step announcement.
  • command-palette.stories.tsx — default story, playground, variant: grouped commands, async commands, history.
  • command-palette.test.tsx — render, keyboard navigation, a11y. Write command-palette.md.

10. Integration test (tests/integration.test.ts)

  • Full round-trip: render component, open, type query, navigate with arrows, execute, verify history.
  • Storage adapter swap: MemoryAdapter replaces LocalStorageAdapter without code change.

11. Docs + verify

  • Write .md per module (≥200 words, API reference, examples).
  • Write README.md with subpath table, hook API, storage-adapter guide, a11y notes.
  • bunx turbo lint typecheck test --filter=@suaveplan/react-command-palette — green.
  • bunx turbo test:coverage — 100%.
  • No @ts-expect-error in src/ or tests. No react-dom in runtime deps.
  • Reference component passes axe-core.
  • bun scripts/publish.ts --package @suaveplan/react-command-palette.
  • Archive to openspec/archive/2026-04-24-enterprise-browser-react-command-palette/.