CmdPal JS/TS Extensions - Phase 3: adapters + proxies - #49324
Open
michaeljolley wants to merge 14 commits into
Open
CmdPal JS/TS Extensions - Phase 3: adapters + proxies#49324michaeljolley wants to merge 14 commits into
michaeljolley wants to merge 14 commits into
Conversation
Add the C# translation layer that presents JSON-RPC data from Node.js extensions as native CmdPal WinRT interfaces. Additive library code under Microsoft.CmdPal.UI.ViewModels/Models plus MSTest coverage driven by an in-memory fake extension. No node spawning, discovery, hot-reload, or DI/UI wiring (those are Phase 4). Adapters/proxies: - JSModelMapper, JSCommandResultParser, JSCommandFactory (static mappers) - JSInvokableCommandAdapter, JSCommandItemAdapter, JSListItemAdapter, JSFallbackCommandItemAdapter, JSFiltersAdapter - JSListPageProxy, JSDynamicListPageProxy, JSContentPageProxy, JSFormContentProxy - JSCommandProviderProxy, JSCommandSettingsProxy Reuses the Phase 2 JsonRpcConnection for outbound requests and notifications. Co-authored-by: Copilot App <[email protected]> Copilot-Session: f9b90e37-dcfc-4ea7-8a79-87eb2af072b6
…pc-transport' into dev/mjolley/phase-3-cmdpal-adapters
- Filter separators read the SDK "separator" flag instead of "_isSeparator" (list-item separators still use "_isSeparator" per the SDK serializer). - Grid layout reads the SDK "type" discriminator instead of "layout". - fallback/updateQuery is sent as a request, matching the protocol and SDK. - Scope listPage/itemsChanged routing per connection via a ConditionalWeakTable keyed by the JsonRpcConnection, holding proxies as weak references so ids from different extensions no longer collide and collected proxies are pruned. - Use a ConcurrentDictionary for the fallback adapter map shared between the request path and the JSON-RPC reader thread. - Add tests covering filter separators, grid type, and fallback updateQuery. Co-authored-by: Copilot App <[email protected]> Copilot-Session: f9b90e37-dcfc-4ea7-8a79-87eb2af072b6
ParseContextItem only read title/command/icon and dropped any nested moreCommands array, so JS/TS extensions could not surface nested context-menu commands even when the wire carried them. Recursively parse the moreCommands array (reusing ParseContextItems) and assign the children onto the existing CommandContextItem.MoreCommands, leaving the default empty array when the field is absent. Pairs with the Phase 1 SDK serialization change (8f123a8). Co-authored-by: Copilot App <[email protected]> Copilot-Session: 8e96286c-f6eb-42d5-bcd3-68fc6a76622f
…pc-transport' into HEAD
This was referenced Jul 21, 2026
michaeljolley
marked this pull request as ready for review
July 21, 2026 17:05
…lisher fallback) Co-authored-by: Copilot App <[email protected]> Copilot-Session: 762976e0-2453-40ca-8034-978a04a19d1e
Co-authored-by: Copilot App <[email protected]> Copilot-Session: 3f0875f9-177f-40db-888c-248a044d2bb9
Wire the JS extension proxies and adapters to the locked wire contract: form identity on submit, toast continuation results, per-page proxy routing, pagination state refresh, full settings page metadata, context-menu shortcuts, icon fallback, status identity, provider dispose cleanup, frozen metadata and page accent color. Adds fixture-driven unit tests that consume the shared TS SDK wire fixtures. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 9470f549-1997-44de-b0a6-1ce4562a51f0
Propagates the stale-test and golden-fixture corrections so the SDK typecheck stays green at this layer. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
r2-p3-01 pagination: JSListPageProxy.LoadMore now settles HasMoreItems from the loadMore result and raises ItemsChanged so the host clears its loading state and re-queries appended items end to end. r2-p3-03 registry-init race: the itemsChanged notification handler is now wired via EnsureSubscribed on the retained PageRegistry (pure CWT factory), so a discarded registry can never be the subscribed one. r2-p3-04 context-icon-fallback: a context/more-commands item that omits its own icon now inherits the command icon instead of being cleared to empty. r2-p3-05 status-disposal race: status message bookkeeping is guarded by a lock and Dispose snapshots under the lock before hiding, so enumerate and mutate no longer collide. r2-p3-02 settings-metadata: verified already correct (full serialized settings page is consumed), no change. Adds JSAdapterRemediationTests.Round2.cs covering the above. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
Bring the phase-2 JSON-RPC transport round-2 fixes down onto phase-3. Clean merge. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
Address the round-3 review findings in the C# JS adapters at root cause. r3-p3-01 JSListPageProxy.LoadMore: a failed loadMore (RPC error or transport exception) settled paging to HasMoreItems=false and raises ItemsChanged so the host clears its loading spinner instead of hanging. r3-p3-02 JSListPageProxy.PageRegistry.EnsureSubscribed: register the itemsChanged handler before marking the registry subscribed, under one lock, so a concurrent caller cannot observe the registry as subscribed before the handler is bound and drop a notification. r3-p3-03 JSCommandProviderProxy: buffer host showStatus, hideStatus and logMessage notifications that arrive before InitializeWithHost, then replay them in arrival order once the host is attached. r3-p3-04 JSCommandProviderProxy: consume the initialize handshake id, displayName and icon, falling back to the package manifest when a field is absent, so the palette reflects the extension declared identity. r3-p3-05 JSCommandProviderProxy: dispatch host.ShowStatus while holding the status lock so a dispose-triggered hide serializes strictly after a pending show and cannot strand a status shown but never hidden. r3-p3-06 JSModelMapper.ParseIconInfo: when exactly one theme variant is supplied, mirror it onto the other theme so the icon renders in both light and dark rather than disappearing in the omitted theme. Add Round3 MSTest coverage plus JSFakeExtension error-response support. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
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.
Warning
This PR is one in a series of PRs focused on adding TypeScript/JavaScript extension support to Command Palette.
This PR should not be merged until PR #49325 is merged into it.
Note
To test the final result, run the branch associated with PR #49364.
Summary
Phase 3 of adding JavaScript/TypeScript extensions to Command Palette (CmdPal). This adds the C# translation layer: adapters and proxies that present JSON-RPC 2.0 data (from out-of-process Node.js extensions) as the native CmdPal WinRT interfaces. This is additive library code under
Microsoft.CmdPal.UI.ViewModels/Models; it may be unreferenced by app code for now.Tracking issue: #48707
Note
This PR stacks on Phase 2 (PR #49323) and targets its branch
dev/mjolley/phase-2-cmdpal-jsonrpc-transport, notmain. It stays a draft until reviewed. Please review Phase 2 first.What is in scope
ICommandProvider,ICommand/IInvokableCommand,IListPage/IDynamicListPage,IContentPage,IIconInfo/IconData, tags, details, content, filters, and settings.JsonRpcConnectionfor outbound requests and inbound notifications.What is NOT in scope (Phase 4)
Adapter / proxy surface
Static mappers:
JSModelMapper- materializes leaf/data objects (icons via the four-format pipeline: font glyph, file/URI path, raw base64 to in-memory stream, data URI parse+decode; tags, color, details + detail data, grid layouts, filter items, separators, content items).JSCommandResultParser- maps invoke resultKind0..7 to the ToolkitCommandResult(Dismiss, GoHome, GoBack, Hide, KeepOpen, GoToPage, ShowToast, Confirm).JSCommandFactory- routes command JSON to the right page proxy or invokable adapter (pageType/_typediscriminator).Adapters:
JSInvokableCommandAdapter-Invoketocommand/invokerequest.JSCommandItemAdapter,JSListItemAdapter- lazy command, tags/details/section/moreCommands.JSFallbackCommandItemAdapter- mutableDisplayTitle, reacts tocommand/propChanged.JSFiltersAdapter-CurrentFilterIdtolistPage/setFilter.Proxies:
JSListPageProxy-getItemstolistPage/getItems, filters, grid properties, load more, empty content,listPage/itemsChanged.JSDynamicListPageProxy-setSearchTexttolistPage/setSearchText.JSContentPageProxy-getContenttocontentPage/getContent, details, commands.JSFormContentProxy- form submit toform/submit.JSCommandProviderProxy-TopLevelCommands/FallbackCommands/GetCommand/Settingsoverprovider/*, host notifications (log/status/copy).JSCommandSettingsProxy- exposes the extension settings page id.Tests
Added MSTest coverage in
Microsoft.CmdPal.UI.ViewModels.UnitTests, driven through the publicJSCommandProviderProxyagainst an in-memory fake extension (JSFakeExtension) backed by a realJsonRpcConnectionover pipes. No real Node.js process is spawned. Covers top-level commands, the icon pipeline (all four formats), invokeKindmapping 0..7, list items (tags/details/sections/separators/moreCommands), dynamicsetSearchText+itemsChanged, content types (markdown/plainText/image/form/tree) with form submit, fallbackpropChanged, and settings.Build is clean (x64/Debug, warnings-as-errors, StyleCop, nullable) with no suppressions. All 178 ViewModels unit tests pass.