Skip to content

chore(genui): configure catalog extractor build - #495

Open
PupilTong wants to merge 2 commits into
mainfrom
codex/quirky-extractor
Open

chore(genui): configure catalog extractor build#495
PupilTong wants to merge 2 commits into
mainfrom
codex/quirky-extractor

Conversation

@PupilTong

Copy link
Copy Markdown
Owner

@coderabbitai summary

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

…atalog

Squashed rewrite of the @lynx-js/a2ui-reactlynx package. The previous
design coupled chat UI, IO transport, and renderer behind a singleton
processor + side-effect catalog registry. This commit splits them into
a small set of orthogonal pieces and shrinks the public surface to what
a protocol-naive developer actually needs.

Public surface
- `<A2UI messageStore catalogs onAction />` — the all-in-one entry
  point. Subscribes to a raw-message buffer via useSyncExternalStore,
  processes new tail messages on each render, renders the most recent
  beginRendering surface. Five render slots (wrapSurface, renderEmpty,
  renderFallback, renderError) for theming and lifecycle UI.
- `createMessageStore()` — a pure 4-method buffer:
    interface MessageStore {
      subscribe(cb): () => void;
      getSnapshot(): readonly ServerToClientMessage[];
      push(message | message[]): void;
      clear(): void;
    }
  No SendIO, no SendContext, no resources, no surfaces, no processor —
  the buffer knows nothing about the protocol. The developer's IO
  module pushes raw messages in; <A2UI> processes them.
- Catalog API: `defineCatalog([Text, [Button, buttonManifest], MyCustom])`,
  `mergeCatalogs`, `serializeCatalog`, `resolveCatalog`. CatalogInput is
  either a bare component (name from `displayName ?? component.name`) or
  a `[component, manifest]` tuple where the manifest is the JSON the
  extractor emits at `dist/catalog/<Name>/catalog.json`.
- Built-in components individually re-exported (`Text`, `Button`,
  `Card`, `CheckBox`, `Column`, `Divider`, `Image`, `List`,
  `RadioGroup`, `Row`) so apps pick exactly what they need. There is
  intentionally NO all-in-one aggregate — see
  `src/catalog/README.md` for the paste-able recipe.
- Custom-component-author API: `useAction`, `useDataBinding`,
  `useResolvedProps`, `NodeRenderer`. That is everything a third-party
  catalog component needs to be interactive, data-bound, and
  recursively render children.

Internal architecture
- src/store/: MessageStore (buffer), MessageProcessor (protocol state
  machine), Resource, SignalStore, payloadNormalizer, types.
  MessageProcessor is exposed for protocol-aware consumers who want to
  build their own renderer instead of using <A2UI>.
- src/react/: <A2UI> owns a per-instance MessageProcessor, a
  Map<id, Resource>, an activeMessageId, and a processedCount cursor.
  useEffect on the buffer's snapshot calls
  processor.processMessages(slice). processor.onUpdate updates
  resources + activeMessageId; processor.onEvent forwards user actions
  to props.onAction (fire-and-forget).
- A2UIProvider, A2UIContext, A2UIRenderer, useA2UIContext, useCatalog
  are intentionally NOT exported. They're internal details of how
  <A2UI> wires its catalog-component subtree.

Catalog composition
- Per-component subpath exports (`./catalog/<Name>` -> the component;
  `./catalog/<Name>/catalog.json` -> the extractor manifest).
- `"sideEffects": ["**/*.css"]` in package.json so bundlers can drop
  unused per-component imports while preserving CSS side effects.
- Catalog component CSS imports updated to origin/main's centralized
  `styles/catalog/<Name>.css` location.

Examples (in a2ui-playground/examples/)
- io-mock/mockAgent.ts: createMockAgent(store, opts) returns
  { start, onAction, stop } — streams raw messages into the buffer
  with a configurable delay.
- io-sse/sseAgent.ts: createSseAgent(store, { url }) returns
  { send, onAction, stop } — opens an EventSource, parses
  delta/complete events, pushes into the buffer.
- chat-shell-lynx/: per-turn-store pattern. Each agent response gets
  its own MessageStore + its own <A2UI>. The shell only knows about
  turns; no provider/renderer ceremony.

Playground (lynx-src/App.tsx)
- Rewritten on top of <A2UI> + createMockAgent. Forwards user actions
  back to the mock agent so canned responses appear in the same
  panel. Preserves origin/main's useGlobalProps + effectiveData
  integration for native preview.

Tests (vitest -> rstest)
- store/MessageStore.test.ts: subscribe/push/clear/getSnapshot
  stability, snapshot freezing.
- store/Resource.test.ts: status transitions, subscribe/getSnapshot,
  no throw-suspense regression.
- store/MessageProcessor.test.ts: surface lifecycle, multi-subscriber
  listeners, dispatch.
- store/payloadNormalizer.test.ts: text-fallback + Card/Text wrappers.
- catalog/defineCatalog.test.ts: bare/tuple/resolved inputs,
  mergeCatalogs last-write-wins, serializeCatalog manifest shape.
- 43/43 passing.

Extractor (a2ui-catalog-extractor)
- bin/cli.ts: replaced the require-main entry guard with a portable
  `pathToFileURL`-based check so the bin shim invokes runCli.

Verification
- tsc --build packages/genui clean
- eslint clean across a2ui src + tests + extractor + playground/examples
  (only pre-existing playground/index.tsx errors remain, unchanged)
- pnpm --filter @lynx-js/a2ui-reactlynx test -> 43/43
- pnpm --filter @lynx-js/a2ui-catalog-extractor test -> 6/6
- pnpm --filter @lynx-js/a2ui-reactlynx build -> 10 schemas emitted

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a turbo.json configuration file for the a2ui-catalog-extractor package to define build task parameters. The review feedback suggests including the build configuration file in the task inputs to ensure proper cache invalidation and updating the task dependencies to support workspace-level build ordering.

Comment on lines +5 to +15
"build": {
"dependsOn": [],
"inputs": [
"src/**",
"tsconfig.json",
"package.json"
],
"outputs": [
"dist/**"
]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The build task configuration is missing the build tool's configuration file (rslib.config.ts) in the inputs list. Including it ensures that changes to the build configuration correctly invalidate the cache. Additionally, using dependsOn: ["^build"] instead of an empty array ensures that any future workspace dependencies are built in the correct order, maintaining consistency with the root configuration.

    "build": {
      "dependsOn": ["^build"],
      "inputs": [
        "src/**",
        "rslib.config.ts",
        "tsconfig.json",
        "package.json"
      ],
      "outputs": [
        "dist/**"
      ]
    }

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