Skip to content

CmdPal JS/TS Extensions - Phase 6: docs + parity sample extension - #49329

Open
michaeljolley wants to merge 21 commits into
dev/mjolley/phase-5-cmdpal-galleryfrom
dev/mjolley/phase-6-cmdpal-docs-sample
Open

CmdPal JS/TS Extensions - Phase 6: docs + parity sample extension#49329
michaeljolley wants to merge 21 commits into
dev/mjolley/phase-5-cmdpal-galleryfrom
dev/mjolley/phase-6-cmdpal-docs-sample

Conversation

@michaeljolley

Copy link
Copy Markdown
Contributor

Summary

Phase 6 (final) of adding JavaScript/TypeScript extensions to Command Palette. This PR is atomic to Phase 6 and stacks on Phase 5 (PR #49326); its base branch is dev/mjolley/phase-5-cmdpal-gallery, not main. Related issue: #48707.

It stays a draft until reviewed.

Phase 6 delivers three things:

A. Design spec docs (src/modules/cmdpal/doc/json-rpc-spec)

Brings the JSON-RPC design spec into the repo: overview.md plus 01-architecture, 02-typescript-sdk, 03-jsonrpc-protocol, 04-manifest-packaging, and 05-getting-started. The drafts were reviewed against what actually shipped in Phases 1-5 and corrected:

  • Adapter/proxy class names updated to the shipped names (for example JSCommandItemAdapter, JSInvokableCommandAdapter, JSModelMapper, JSCmdPalSection), replacing names that never shipped.
  • JSON-RPC method list reconciled to the shipped surface, and the CommandResult wire serialization (string-union kind serialized to the numeric Kind / Args shape) documented accurately.
  • 05-getting-started was fully rewritten to the real API (CommandProviderBase / InvokableCommandBase / ListPageBase / DynamicListPageBase / ContentPageBase, run(() => new Provider()), string-union results, ExtensionHost.log), Node 22, SDK 0.1.0, ESM / NodeNext.
  • 04-manifest-packaging install flow updated to describe the materialize/hoist step (see C below).
  • Fixed the bogus Last updated date in overview.md and removed every long dash across all six files.

B. Parity sample (src/modules/cmdpal/ext/SampleJSExtension)

A source-only TypeScript sample that mirrors the C# SamplePagesExtension view-for-view using @microsoft/cmdpal-sdk (referenced via a relative file: dependency, so it builds without publishing). npm ci && npm run build succeeds; dist/ and node_modules/ are git-ignored. The README explains how to sideload it into the JSExtensions directory. It was smoke-tested over stdio: initialize, top-level command, the 23-item samples index, a nested list page, and markdown content all respond correctly.

Capabilities intentionally not mirrored (JS protocol does not expose them; no protocol methods were invented):

  • Dock bands (SampleDockBand / SampleButtonsDockBand): GetDockBands is not exposed.
  • Parameter pages and the create-note list-parameters sample: IParameterRun is not exposed.
  • Drag-and-drop / DataPackage in the data transfer sample: clipboard copy is mirrored; drag-drop is not exposed.
  • Toast icon + action button (IToastArgs2), and Details size (Small/Medium/Large): not in the JS ToastArgs / Details shapes.
  • EvilSamplesPage and issue-specific host-ABI repros: reproduce in-process C# ABI edge cases, not applicable to isolated JS extensions.

Approximated (capability exists but differs):

  • Live-updating details and updating-items push: approximated with DynamicListPageBase + notifyItemsChanged on an interval, since JS Details has no observable push.
  • On-load / on-unload lifecycle: approximated by appending an entry per getItems call.
  • Prefix suggestions: simplified demo (no caret tracking); keys off the last token plus textToSuggest.
  • Markdown images: web URL and sizing examples reproduced; large packaged/base64 assets omitted with a note (the sample ships no binary assets).
  • Deeply nested context menus are flattened to one level (ContextItem has no moreCommands).

C. Install-layout reconciliation

Phase 5 flagged that npm install <pkg> lands the package under JSExtensions/<name>/node_modules/<pkg>/package.json, while Phase 4 discovery scans JSExtensions/<name>/package.json. Fixed with the least invasive option: after npm exits successfully, NpmCommandRunner calls JsExtensionPackageLayout.Materialize(targetDirectory), which finds the installed package whose package.json carries a valid cmdpal section and hoists it (including merging node_modules) up to the JSExtensions/<name> root that discovery expects. This matches the spec doc 04 layout. Covered by JsExtensionPackageLayoutTests.

Validation

  • C# (Part C) built clean (exit 0) and the ViewModels unit tests passed in a prior phase run (211 tests; the known SortByAuthorCommand_SortsEntriesByAuthor flake passes on re-run). No C# changed since.
  • Sample: npm ci && npm run build exit 0; stdio smoke test passed.
  • No long dashes anywhere in the docs, sample, or this PR.

Adds the JSON-RPC design spec into the repo, a buildable TypeScript parity
sample that mirrors the C# SamplePagesExtension, and reconciles the gallery
install layout so an npm-installed extension is actually discovered.

Docs (src/modules/cmdpal/doc/json-rpc-spec): overview plus 01-architecture,
02-typescript-sdk, 03-jsonrpc-protocol, 04-manifest-packaging, and a rewritten
05-getting-started. Corrected class/method-name and API drift against the
shipped Phases 1-5 code, fixed the overview date, and removed all long dashes.

Sample (src/modules/cmdpal/ext/SampleJSExtension): source-only project that
builds against the local SDK via a relative file dependency; dist and
node_modules are git-ignored.

Layout reconciliation: JsExtensionPackageLayout.Materialize hoists the package
npm installs under node_modules up to the JSExtensions/<name> root that
discovery scans, with unit tests covering the installed layout.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 9a289c8c-5264-482e-a363-5b4593cf9c73
michaeljolley and others added 4 commits July 15, 2026 12:55
…ry' into dev/mjolley/phase-6-cmdpal-docs-sample
Bound the live-updating sample pages' refresh timers to page visibility and
reconcile the packaging doc's SDK dependency example.

- Add LiveRefresh helper that arms a single timer while a page is being
  observed and stops it once the host stops re-fetching (navigate away),
  restarting on navigate back. Replaces the permanent setInterval in
  liveDetailsPage and updatingItemsPage.
- Cache the two timer-owning pages as singletons in SamplesListPage so
  repeated navigation cannot churn page instances or accumulate timers.
- 04-manifest-packaging.md: reference @microsoft/cmdpal-sdk via a relative
  file: dependency and note that a semver range applies once it is published,
  matching the unpublished-package reality stated elsewhere in the doc.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 9a289c8c-5264-482e-a363-5b4593cf9c73
…ontext, separators, status)

Applies five sample-authoring fixes to SampleJSExtension now that the SDK and
host fixes are merged up to phase 6:

- Sections: emit visible headings with titled Separator entries between groups
  instead of tagging command items with a section field the host ignores.
- Hero image: ship a local assets/hero.png and reference it by an absolute path
  resolved from import.meta.url, so the details hero renders without a network
  connection. The build copies assets into dist/assets.
- Nested context menu: demonstrate a genuine two-level moreCommands submenu on a
  context item now that nested context menus are supported end to end.
- Details separator: use an empty-key separator where a divider line is intended
  so the horizontal rule renders instead of a bold heading.
- Details command buttons: wire the buttons to a visible indeterminate status
  that resolves to a success message, exercising the merged status fixes.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 2ccc215f-7518-4f6f-92a4-1cfd112fb01f
michaeljolley and others added 2 commits July 20, 2026 23:03
Align the documented JS extensions install location in the JSON-RPC spec
and the sample extension README with the CmdPal data folder path segment
change from CommandPalette to CmdPal.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: f69b1dcf-ed86-4e74-8373-b8414e1ac961
@michaeljolley michaeljolley self-assigned this Jul 21, 2026
@michaeljolley
michaeljolley marked this pull request as ready for review July 21, 2026 17:07
michaeljolley and others added 14 commits July 21, 2026 13:31
…bilities

Follow the manifest changes through the JS/TS extension docs and sample:

- 04-manifest-packaging.md: add the top-level npm "author" field to the
  reference, note that cmdpal.publisher falls back to the author name, and
  remove the inert cmdpal.capabilities field from the field list, the tables,
  and the JSON examples.
- 05-getting-started.md: drop cmdpal.capabilities from the walkthrough example.
- SampleJSExtension/package.json: remove the cmdpal.capabilities array.

The runtime initialize-handshake capabilities documented in
03-jsonrpc-protocol.md and the prose in the sample README and samplesListPage.ts
about C# features not yet mirrored are unrelated and left untouched.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: de2fe464-6835-4cd9-9c6b-0ac9351cdb99
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
Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 9470f549-1997-44de-b0a6-1ce4562a51f0
…sample

Propagate the phase-5 fail-closed npm install transaction up into the docs and
sample phase. The only code conflict was in NpmCommandRunner, where phase-6 had
wired the runner success path to JsExtensionPackageLayout.Materialize. Phase-5
moves that hoisting into the installer staging step (AssembleDiscoveryLayout)
as part of the staging-and-atomic-promote transaction, so the runner now returns
the resolved integrity and no longer materializes in place. Phase-6's
JsExtensionPackageLayout helper, its tests, and the json-rpc-spec docs are kept
intact. Added a parameterless NpmCommandResult.Ok() overload so that helper keeps
compiling against the phase-5 result shape.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 234c59f1-a32b-4c98-97bb-ab50a4d07fd9
Address the phase 6 punchlist for the Command Palette JS/TS extensions
feature (docs plus sample extension), staying within CommandPalette.slnf.

- Gallery schema doc (04-manifest-packaging.md) now shows the real gallery
  model (id, title, author, installSources with the jsonrpc npm source
  inside installSources) and documents the required exact version, sha512
  integrity, and optional HTTPS-allowlist registry fields. A parser test
  feeds the exact documentation JSON through the production gallery parser.
- Reconcile package hoisting onto a single identity-aware path:
  JsExtensionPackageLayout resolves the requested package identity (scoped
  and unscoped), enforces containment, and rejects ambiguous layouts. The
  installer calls this one helper.
- Manifest relative icon paths resolve against the manifest directory with
  package containment enforced (reject parent-directory escapes and
  reparse points). Adds installed-package icon tests.
- Sample nested forms carry stable form IDs for recursive routing; status
  commands hide the working status before showing completion using stable
  status handles.
- Document Separator("Title") as the supported grouping mechanism.
- Production packaging guidance no longer tells authors to depend on the
  repo-local SDK; it states registry distribution is not yet supported and
  adds a packed-SDK smoke test (scripts/verify-pack.mjs, verify:pack) that
  installs a tarball into a clean project and type-checks against it. The
  script falls back to a deterministic tarball when npm pack is unavailable.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 3158d6a3-1d4d-4772-882a-91ede0cc7f9b
Propagates the stale-test and golden-fixture corrections so the SDK
typecheck stays green at this layer, including the phase-6 forms tests.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
The re-serialize form identity test destructured sent from createHarness
but never referenced it, tripping eslint no-unused-vars and turning
npm run check red at this layer. Drop the unused binding so the lint
gate passes; the test still asserts on submit and replies.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
r2-p6-01: AssembleDiscoveryLayout treated a hoisted node_modules/@scope
directory as a leaf package, so when the destination scope already existed
(for example a version-pinned scoped dependency the package bundled) the whole
incoming @scope was skipped, silently dropping sibling scoped packages. Merge
scoped dependencies one package at a time so every @scope/pkg is preserved.
Adds a unit test covering mixed unscoped and multiple @scope/pkg entries.

r2-p6-02: reconcile the SDK installation guide with getting-started. The SDK
is not published to npm, so document repo-relative file: consumption and build
steps instead of an unpublished npm version.

r2-p6-03: correct the docs to state that nested context menus are supported;
ContextItem carries its own moreCommands and the SDK serializes nesting
recursively.

r2-p6-04: remove the section field from the command-bearing item example and
clarify that the host ignores section on interactive items.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
Bring the phase-5 gallery installer round-2 fixes down onto phase-6. Resolved NpmJsExtensionInstaller.cs: kept phase-5 RollbackPromotedInstall plus junction-root guard and threaded uninstall token, while keeping phase-6 extraction of layout helpers into JsExtensionPackageLayout.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 311db8aa-f8db-47bb-943f-5447037946c7
@michaeljolley
michaeljolley force-pushed the dev/mjolley/phase-5-cmdpal-gallery branch from 8d8c090 to a20c022 Compare July 27, 2026 21:14
@michaeljolley
michaeljolley force-pushed the dev/mjolley/phase-6-cmdpal-docs-sample branch from efdf0b5 to d76e2b0 Compare July 27, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Command Palette Refers to the Command Palette utility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants