Skip to content

Integrate JS/TS WinRT bindings into winapp init (managed codegen + runtime, kept in version sync)#536

Merged
nmetulev merged 57 commits into
mainfrom
leilzh/jsbindings
Jun 22, 2026
Merged

Integrate JS/TS WinRT bindings into winapp init (managed codegen + runtime, kept in version sync)#536
nmetulev merged 57 commits into
mainfrom
leilzh/jsbindings

Conversation

@lei9444

@lei9444 lei9444 commented May 18, 2026

Copy link
Copy Markdown
Contributor

Description

Call modern Windows Runtime (WinRT) APIs directly from JS or TS inElectron / Node app — no native addon, no node-gyp / MSBuild step, full IntelliSense.

The CLI generates typed .js + .d.ts bindings for WinAppSDK (and any other WinRT) APIs from their .winmd metadata. Bindings call into WinRT at runtime via @microsoft/dynwinrt.

Usage Example

Bootstrap a new project or Add bindings to an existing project:

npx winapp init . --use-defaults --add-js-bindings
image image

Related Issue

Type of Change

  • ✨ New feature

Checklist

  • New tests added for new functionality (if applicable)
  • Tested locally on Windows
  • Main README.md updated (if applicable)
  • docs/usage.md updated (if CLI commands changed)
  • Language-specific guides updated (if applicable)
  • Sample projects updated to reflect changes (if applicable)
  • Agent skill templates updated in docs/fragments/skills/ (if CLI commands/workflows changed)

Screenshots / Demo

Additional Notes

AI Description

This pull request integrates JavaScript (JS) and TypeScript (TS) bindings for Windows Runtime (WinRT) APIs into the winapp init command, allowing developers to call WinRT APIs directly from JS/TS without the need for native addons. The new option --add-js-bindings can be used during project initialization to generate typed bindings for WinAppSDK APIs, simplifying access to various Windows APIs.
Usage example for initializing a project with the new bindings:

npx winapp init . --use-defaults --add-js-bindings

Breaking Change: None.

Copilot AI review requested due to automatic review settings May 18, 2026 06:45
@github-actions github-actions Bot added the enhancement New feature or request label May 18, 2026
Comment thread src/winapp-npm/scripts/generate-commands.mjs Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “JS/TS WinRT bindings” pipeline to WinAppCli, exposing it both as (1) npm-wrapper-only CLI surfaces (winapp init --js-bindings*, winapp node jsbindings ...) and (2) persisted workspace configuration via an opt-in jsBindings: block in winapp.yaml, backed by dynwinrt/dynwinrt-codegen orchestration and a winmd discovery lockfile.

Changes:

  • Introduces winapp node jsbindings add|generate commands and init --js-bindings* flags (npm-only gated via WINAPP_CLI_CALLER).
  • Adds new services/models for jsBindings config parsing/splicing, WinMD discovery/partitioning, lockfile IO, package manager detection, and package.json runtime-dependency injection.
  • Updates docs, CLI schema, samples, and adds extensive unit/integration test coverage for the new pipeline.

Reviewed changes

Copilot reviewed 66 out of 68 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/winapp-npm/src/winapp-commands.ts Exposes new init flags + node jsbindings add/generate through the npm programmatic API wrapper.
src/winapp-npm/src/cli.ts Adds node jsbindings to the npm shim’s command routing/help and forwards to the native CLI.
src/winapp-npm/scripts/generate-docs.mjs Improves JSDoc extraction to avoid truncation at @… and tweaks generated header.
src/winapp-npm/scripts/generate-commands.mjs Escapes problematic doc text and adds naming overrides for generated TS surface.
src/winapp-npm/README.md Documents node jsbindings add in the npm package readme.
src/winapp-npm/package.json Adds @microsoft/dynwinrt-codegen runtime dependency to the npm wrapper.
src/winapp-npm/package-lock.json Locks @microsoft/dynwinrt-codegen dependency and metadata.
src/winapp-CLI/WinApp.Cli/Services/YamlPackagesHasher.cs Adds stable hashing for packages: block for lockfile staleness checks.
src/winapp-CLI/WinApp.Cli/Services/WinmdsLockfileService.cs Adds best-effort read/write of .winapp/winmds.lock.json with schema validation and atomic writes.
src/winapp-CLI/WinApp.Cli/Services/UserPackageJsonService.cs Adds safe editing of user package.json to ensure runtime deps are production deps.
src/winapp-CLI/WinApp.Cli/Services/PackageManagerDetector.cs Detects npm/yarn/pnpm/bun for tailored install hints.
src/winapp-CLI/WinApp.Cli/Services/NpmWrapperVersionProvider.cs Locates npm wrapper’s pinned versions by walking up from the native exe.
src/winapp-CLI/WinApp.Cli/Services/JsBindingsPresets.cs Adds presets + per-package emit/ref/skip classification and winmd partitioning helpers.
src/winapp-CLI/WinApp.Cli/Services/IWorkspaceSetupService.cs Minor comment/doc cleanup.
src/winapp-CLI/WinApp.Cli/Services/IWinmdsLockfileService.cs New interface for winmd lockfile read/write.
src/winapp-CLI/WinApp.Cli/Services/IUserPackageJsonService.cs New interface + outcome enum for package.json injection.
src/winapp-CLI/WinApp.Cli/Services/IPackageManagerDetector.cs New interface for package manager detection.
src/winapp-CLI/WinApp.Cli/Services/INpmWrapperVersionProvider.cs New interface for wrapper-version resolution.
src/winapp-CLI/WinApp.Cli/Services/IJsBindingsWorkspaceService.cs New orchestration interface + context/result models for bindings pipeline.
src/winapp-CLI/WinApp.Cli/Services/IDynWinrtCodegenService.cs New interface for invoking dynwinrt-codegen.
src/winapp-CLI/WinApp.Cli/Services/IConfigService.cs Adds SaveJsBindingsOnly to splice jsBindings while preserving other YAML.
src/winapp-CLI/WinApp.Cli/Services/ConfigService.cs Extends YAML parsing/serialization to support jsBindings: and splicing logic.
src/winapp-CLI/WinApp.Cli/Models/WinmdsLockfile.cs Adds lockfile model + source-gen JSON context.
src/winapp-CLI/WinApp.Cli/Models/WinappConfig.cs Adds JsBindings optional config block to the main config model.
src/winapp-CLI/WinApp.Cli/Models/JsBindingsConfig.cs New model for user-facing jsBindings settings (lang/output/packages/extraTypes/refs).
src/winapp-CLI/WinApp.Cli/Helpers/HostBuilderExtensions.cs Registers new services/commands in DI and command tree.
src/winapp-CLI/WinApp.Cli/Commands/WinAppRootCommand.cs Adds node top-level command category/registration.
src/winapp-CLI/WinApp.Cli/Commands/NodeCommand.cs New node command host for npm-only subtrees.
src/winapp-CLI/WinApp.Cli/Commands/JsBindingsCommand.cs New node jsbindings command host with js-bindings alias.
src/winapp-CLI/WinApp.Cli/Commands/InitCommand.cs Adds --js-bindings* flags, preset alias flags, and npm-only gating.
src/winapp-CLI/WinApp.Cli/Commands/GenerateJsBindingsCommand.cs Implements node jsbindings generate (read-only yaml + codegen).
src/winapp-CLI/WinApp.Cli/Commands/AddJsBindingsCommand.cs Implements node jsbindings add (mutates yaml + codegen) with presets/force/no-prompt logic.
src/winapp-CLI/WinApp.Cli.Tests/YamlPackagesHasherTests.cs Unit tests for hash stability/case/ordering behavior.
src/winapp-CLI/WinApp.Cli.Tests/WorkspaceSetupServiceTests.cs Adds propagation tests for the jsBindings step within workspace setup.
src/winapp-CLI/WinApp.Cli.Tests/WinmdsLockfileServiceTests.cs Unit tests for lockfile schema/atomic write/read behavior and categorization.
src/winapp-CLI/WinApp.Cli.Tests/UserPackageJsonServiceTests.cs Unit tests for package.json injection outcomes + formatting preservation.
src/winapp-CLI/WinApp.Cli.Tests/TestDoubles/FakeJsBindingsWorkspaceService.cs Test double for orchestrator wiring tests.
src/winapp-CLI/WinApp.Cli.Tests/TestDoubles/FakeDynWinrtCodegenService.cs Test double for codegen invocation without spawning binaries.
src/winapp-CLI/WinApp.Cli.Tests/PackageManagerDetectorTests.cs Unit tests for package manager detection precedence.
src/winapp-CLI/WinApp.Cli.Tests/NpmWrapperVersionProviderTests.cs Unit tests for wrapper-version lookup and failure messaging.
src/winapp-CLI/WinApp.Cli.Tests/JsBindingsPresetsTests.cs Unit tests for presets, classification, partitioning, and scope demotion behavior.
src/winapp-CLI/WinApp.Cli.Tests/GenerateJsBindingsCommandTests.cs Command-tree and behavior tests for node jsbindings generate.
src/winapp-CLI/WinApp.Cli.Tests/DynWinrtCodegenStagingTests.cs Tests staging/swap semantics for safe output replacement.
src/winapp-CLI/WinApp.Cli.Tests/DynWinrtCodegenOutputSafetyTests.cs Tests output-dir safety gates (marker/reparse-point/escape rejection).
src/winapp-CLI/WinApp.Cli.Tests/DynWinrtCodegenInvocationTests.cs Tests executable resolution and safe PATH lookup behaviors.
src/winapp-CLI/WinApp.Cli.Tests/DynWinrtCodegenArgvTests.cs Tests argv building and helper list-merge/dedup logic.
src/winapp-CLI/WinApp.Cli.Tests/BaseCommandTests.cs Adds test DI stub for INpmWrapperVersionProvider to avoid layout walking.
scripts/generate-llm-docs.ps1 Updates schema version normalization and skill-command mapping.
samples/electron/test.Tests.ps1 Adds end-to-end smoke tests for jsBindings add flow in Electron sample.
README.md Adds node jsbindings add to root command list.
docs/usage.md Documents init jsBindings flags and node jsbindings add.
docs/npm-usage.md Updates generated npm API docs with new init flags and node jsbindings APIs.
docs/guides/electron/index.md Adds Electron guide path for dynwinrt JS bindings option.
docs/fragments/skills/winapp-cli/setup.md Adds skill snippet describing jsBindings usage.
docs/fragments/skills/winapp-cli/frameworks.md Adds framework guidance for jsBindings in Electron/npm usage.
docs/cli-schema.json Updates CLI schema to include new flags and node jsbindings command tree.
.gitignore Ignores local .claude/ directory.
.github/plugin/skills/winapp-cli/setup/SKILL.md Updates generated skill doc content (includes new init flags and unregister section).
.github/plugin/skills/winapp-cli/frameworks/SKILL.md Updates generated frameworks skill doc with jsBindings guidance.
.github/plugin/agents/winapp.agent.md Updates agent decision tree with jsBindings guidance for Electron.
Files not reviewed (1)
  • src/winapp-npm/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md Outdated
Comment thread src/winapp-npm/README.md
Comment thread docs/usage.md Outdated
Comment thread scripts/generate-llm-docs.ps1 Outdated
@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 31.51 MB 31.57 MB 📈 +57.5 KB (+0.18%)
CLI (x64) 31.85 MB 31.90 MB 📈 +55.5 KB (+0.17%)
MSIX (ARM64) 13.24 MB 13.25 MB 📈 +17.5 KB (+0.13%)
MSIX (x64) 14.06 MB 14.09 MB 📈 +27.6 KB (+0.19%)
NPM Package 27.54 MB 27.65 MB 📈 +111.2 KB (+0.39%)
NuGet Package 27.64 MB 27.68 MB 📈 +40.7 KB (+0.14%)
VS Code Extension 20.43 MB 20.47 MB 📈 +41.5 KB (+0.20%)

Test Results

1324 passed, 1 skipped out of 1325 tests in 424.0s (+48 tests, -39.9s vs. baseline)

Test Coverage

17.4% line coverage, 36.3% branch coverage · ✅ no change vs. baseline

CLI Startup Time

32ms median (x64, winapp --version) · ✅ -7ms vs. baseline


Updated 2026-06-22 10:05:36 UTC · commit ee55141 · workflow run

nmetulev

This comment was marked as outdated.

Comment thread docs/guides/electron/jsbindings.md Outdated
Comment thread docs/guides/electron/jsbindings.md Outdated
Comment thread docs/guides/electron/jsbindings.md Outdated
Comment thread docs/fragments/skills/winapp-cli/frameworks.md Outdated
@lei9444

lei9444 commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

addressed all comments
image

@nmetulev nmetulev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • Should we have winapp init detect when called from npm package and show an option to the user to setup C++, JS, or both bindings? I feel that would simplify the process and remove the need for the jsbindings commands which can be removed - we can simply use winapp init and winapp restore like we do for c++
  • The --js-bindings-ai feels odd, why are we adding a single property just for AI and not for anything else? Could we do without this option?

Comment thread docs/cli-schema.json Outdated
Comment thread docs/cli-schema.json Outdated
Comment thread docs/cli-schema.json Outdated
Comment thread docs/guides/electron/index.md Outdated
Comment thread docs/guides/electron/index.md Outdated
Comment thread docs/guides/electron/jsbindings.md Outdated
Comment thread docs/js-bindings.md Outdated
Comment thread docs/js-bindings.md Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Services/UserPackageJsonService.cs Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Services/DynWinrtCodegenService.cs Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Services/ConfigService.cs Outdated
Comment thread docs/guides/electron/jsbindings.md Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.Prompts.cs Outdated
@nmetulev

This comment was marked as outdated.

@lei9444 lei9444 changed the title Add winapp node jsbindings for typed JS/TS WinRT bindings Integrate JS/TS WinRT bindings into winapp init (managed codegen + runtime, kept in version sync) Jun 15, 2026

@nmetulev nmetulev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, just a minor ux suggestion:

  • on npx winapp init, if I skipp sdk setup, the warning message for js bindings claims the sdks were setup in a different folder, which is wrong - should we skip that step instead and not show anything if the sdks are skipped?

    Image

    (There is also two spaces between the icon and the warning - should be one space)

@nmetulev

Copy link
Copy Markdown
Member

🤖 AI-generated review — produced by the pr-review skill (8 parallel review dimensions + a cross-model verification pass on GPT-5.4, orchestrated by Claude Opus 4.8). This is automated analysis, not a human review: findings may contain false positives, and nothing here has been built or tested. Treat it as a checklist of things to verify, not a merge gate.

PR Review — leilzh/jsbindings vs origin/main (55 commits, 80 files, +9,203 / −805)

Summary

Critical: 0 High: 1 Medium: 15 Low: 2

No release-blockers found. The one High is a real automation/exit-code bug. Most findings are test-coverage gaps and edge cases in the new TS jsbindings modules. The headline security finding (cmd.exe command injection) was disputed and downgraded by the cross-model pass because the package names are fixed constants, not attacker-controlled.

Coverage

Dimension Result
security ⚠ 2 findings (1 downgraded to low by cross-model)
correctness ⚠ 3 findings
cli-ux ⚠ 3 findings
alternative-solution ⚠ 3 findings
test-coverage ⚠ 5 findings
docs-and-samples ⚠ 1 finding
packaging ⚠ 2 findings
multi-model 1/3 highs confirmed · 1 downgraded · 1 disputed

Findings

ID File:lines Domain Finding
H1 src/winapp-npm/src/jsbindings/init-prompt.ts:72-91 cli-ux --add-js-bindings exits 0 without adding bindings when package.json is missing
M1 docs/guides/electron/js-file-picker.md:33-55 test-coverage New JS-binding guide workflows only partially covered by the Electron sample test
M2 samples/electron/package.json:37-47 packaging Sample uses JS bindings but pins winappcli to ^0.2.0 (resolves 0.2.1) — predates the feature
M3 src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs:574-580 alternative-solution Lockfile/hash logic added to an already hard-limit file (~1517 lines)
M4 src/winapp-npm/src/cli.ts:77-115 test-coverage New npm wrapper dispatch/routing has no tests
M5 src/winapp-npm/src/jsbindings/cli-hooks.ts:442-466 security Codegen tooling auto-installed as floating latest (unpinned)
M6 src/winapp-npm/src/jsbindings/cli-hooks.ts:474-517 cli-ux Install-failure hints leak log lines under --json
M7 src/winapp-npm/src/jsbindings/codegen-runner.ts:108-228 test-coverage Destructive staging/swap/wipe safety logic untested
M8 src/winapp-npm/src/jsbindings/init-prompt.ts:48-69 cli-ux --add-js-bindings still prompts interactively when config already exists
M9 src/winapp-npm/src/jsbindings/lockfile-reader.ts:140-145 correctness Valid custom NuGet caches (e.g. D:\packages) rejected as "suspiciously broad"
M10 src/winapp-npm/src/jsbindings/orchestrator.ts:63-117 test-coverage runJsBindingsPipeline has no direct unit coverage (was H, downgraded by cross-model)
M11 src/winapp-npm/src/jsbindings/package-manager-detector.ts:63-65 correctness PATH dirs under cwd skipped — can hide legit npm shims when run from %USERPROFILE%
M12 src/winapp-npm/src/jsbindings/runtime-installer.ts:41-132 test-coverage Package-manager install execution paths untested
M13 src/winapp-npm/src/jsbindings/yaml-packages-hash.ts:56-59 alternative-solution Two lockstep YAML parsers/hashes (TS + C#) must be kept in sync by hand
M14 src/winapp-npm/src/jsbindings/yaml-packages-hash.ts:81-92 correctness TS parser misses - version: list items → false stale-lockfile mismatches vs C#
M15 src/winapp-npm/src/winapp-commands.ts:241-270 packaging, docs-and-samples --add-js-bindings absent from typed npm command surface / autogenerated schema
L1 src/winapp-npm/src/jsbindings/codegen-runner.ts:662-705 alternative-solution Trusted-PATH executable resolution duplicated with package-manager-detector
L2 src/winapp-npm/src/jsbindings/runtime-installer.ts:23-70 security cmd.exe /c string building — defense-in-depth only (cross-model: not exploitable in current dataflow)

Details

H1 — src/winapp-npm/src/jsbindings/init-prompt.ts:72-91 · cli-ux · Multi-model: confirmed

  • Severity: high · Confidence: high
  • Finding: --add-js-bindings can exit successfully (exit 0) without adding bindings when package.json is missing.
  • Evidence: askBindingsKind returns kind: 'no' for a missing package.json before checking inputs.addJsBindings (lines 72-77, 90-91); handleInit then returns on outcome.kind === 'no' (cli-hooks.ts:279-285). In --json/quiet automation the user explicitly asked for bindings but gets a silent exit 0. The wrapper already hard-fails other impossible --add-js-bindings cases (cli.ts:86-95, cli.ts:104-112), so this path is an inconsistency.
  • Recommendation: When addJsBindings is true and package.json is absent, fail non-zero with an actionable "run this in an npm project / no package.json found" message instead of treating it as a skipped optional prompt.

M5 — src/winapp-npm/src/jsbindings/cli-hooks.ts:442-466 · security

  • Severity: medium · Confidence: high
  • Finding: Init auto-installs executable codegen tooling as floating latest.
  • Evidence: // latest (not pinned) on purpose (line 443), then installPackageDependency(... CODEGEN_PACKAGE_NAME, '', ...) (lines 464-466).
  • Recommendation: Install an exact vetted codegen version (or bundle it) and derive runtime sync from that pinned tool, to avoid silently pulling new executable code on every init.

M6 — src/winapp-npm/src/jsbindings/cli-hooks.ts:474-517 · cli-ux

  • Severity: medium · Confidence: high
  • Finding: JS-binding install-failure hints leak human-readable logs under --json.
  • Evidence: --json is folded into quiet (line 217), but failure paths still call ui.log(\⚠️ ${manualHint}`)(line 479) andconsole.warn(...)` (line 517).
  • Recommendation: Track JSON mode separately from quiet; suppress or JSON-encode wrapper diagnostics under --json.

M8 — src/winapp-npm/src/jsbindings/init-prompt.ts:48-69 · cli-ux

  • Severity: medium · Confidence: high
  • Finding: --add-js-bindings still prompts ("Overwrite?") on projects that already have winapp.jsBindings, breaking non-interactive use.
  • Evidence: Existing config enters if (inputs.existingJsBindings) (line 49) and calls confirmationPrompt('package.json already has winapp.jsBindings. Overwrite?') (line 68); the add-flag fast-path is only checked later (lines 90-91).
  • Recommendation: Make explicit --add-js-bindings non-interactive for existing config too — preserve existing settings unless --use-defaults/a reset flag is supplied.

M9 — src/winapp-npm/src/jsbindings/lockfile-reader.ts:140-145 · correctness

  • Severity: medium · Confidence: high
  • Finding: Valid custom NuGet caches like D:\packages are rejected as "suspiciously broad," breaking generation when NUGET_PACKAGES is a shallow path.
  • Evidence: const boundaryDepth = cacheBoundary.split(path.sep).filter(Boolean).length; (143); if (boundaryDepth < 3 || isNetworkPath(cacheBoundary)) { (144).
  • Recommendation: Reject only actual drive/share roots (and UNC), not arbitrary shallow non-root directories; add C:\packages/D:\nuget tests.

M11 — src/winapp-npm/src/jsbindings/package-manager-detector.ts:63-65 · correctness

  • Severity: medium · Confidence: medium
  • Finding: PM resolution skips every PATH directory under cwd, so running from %USERPROFILE% can hide legit npm shims in %USERPROFILE%\AppData\Roaming\npm.
  • Evidence: const resolvedDir = path.resolve(dir); (63); if (isPathUnderOrEqual(resolvedDir, cwdFull) || (workspaceFull && isPathUnderOrEqual(resolvedDir, workspaceFull))) { (64).
  • Recommendation: Keep rejecting workspace-controlled shims, but reject only the exact cwd PATH entry (and relative entries), not all descendants of cwd.

M14 — src/winapp-npm/src/jsbindings/yaml-packages-hash.ts:81-92 · correctness

  • Severity: medium · Confidence: high
  • Finding: TS YAML parsing misses list items starting with - version:, causing false stale-lockfile mismatches vs the native parser.
  • Evidence: - name: is special-cased (matchPrefixCaseInsensitive(t, '- name:'), 82) but version only matches bare version: (matchPrefixCaseInsensitive(t, 'version:'), 90).
  • Recommendation: Add - version: handling matching the C# parser and add cross-language parity tests for version-before-name YAML.

M13 — src/winapp-npm/src/jsbindings/yaml-packages-hash.ts:56-59 · alternative-solution

  • Severity: medium · Confidence: high
  • Finding: The PR maintains two lockstep YAML parsers/hashes instead of keeping winapp.yaml semantics native-owned.
  • Evidence: ConfigService.cs:46-48 "Mirrors the TS parsePackagesFromYaml"; yaml-packages-hash.ts:57-59 "change both parsers together."
  • Recommendation: Move stale/empty-package lockfile decisions into native restore/lockfile writing, or expose one native hash/check path for the npm wrapper. (Root cause shared with M14.)

M3 — src/winapp-CLI/WinApp.Cli/Services/WorkspaceSetupService.cs:574-580 · alternative-solution

  • Severity: medium · Confidence: high
  • Finding: New lockfile/hash logic grows a file that's already at the hard size limit (~1517 lines).
  • Evidence: :39 adds IWinmdsLockfileService; 574-580 computes YAML hash and writes the lockfile.
  • Recommendation: Extract into a dedicated WriteRestoreInventoryAsync method/service so WorkspaceSetupService only orchestrates.

M2 — samples/electron/package.json:37-47 · packaging

  • Severity: medium · Confidence: high
  • Finding: Electron sample now relies on JS-bindings-capable winappcli but is pinned to ^0.2.0 (lockfile resolves 0.2.1).
  • Evidence: "@microsoft/winappcli": "^0.2.0" with winapp.jsBindings added; package-lock.json:1196-1198 resolves 0.2.1.
  • Recommendation: Bump the sample dependency/lockfile to the first winappcli version that ships the restore JS-bindings hooks and node generate-bindings.

M15 — src/winapp-npm/src/winapp-commands.ts:241-270 · packaging, docs-and-samples

  • Severity: medium · Confidence: high
  • Finding: --add-js-bindings is a public npm-wrapper init option but is absent from the typed npm command surface and the autogenerated docs/cli-schema.json.
  • Evidence: WRAPPER_ONLY_FLAGS = new Set(['--add-js-bindings']) (cli-args.ts:12); no match for add-js-bindings/jsBindings in winapp-commands.ts or docs/cli-schema.json, while docs/usage.md:38-49 documents it.
  • Recommendation: This is a wrapper-only flag by design, so confirm it's intentionally excluded from the native schema; if so, document that explicitly, otherwise regenerate the autogenerated artifacts.

M1 — docs/guides/electron/js-file-picker.md:33-55 · test-coverage

  • Severity: medium · Confidence: high
  • Finding: New JS-binding guide workflows are only partially exercised by the Electron sample test.
  • Evidence: Pester checks default binding generation, runtime dep, restore, and stale-hash, but not guide-specific additionalWinmds regeneration (StorageFile, BitmapDecoder) or the notification/Phi/WinML snippets.
  • Recommendation: Extend Electron Phase 1 with guide smoke checks for the added classes; hardware-gate Phi/WinML execution but still assert bindings/config generation.

M10 — src/winapp-npm/src/jsbindings/orchestrator.ts:63-117 · test-coverage · Multi-model: downgraded from High

  • Severity: medium · Confidence: high
  • Finding: runJsBindingsPipeline (the core pipeline driving exit/log behavior) has no direct unit coverage.
  • Evidence: No test imports orchestrator/runJsBindingsPipeline; only leaf modules are tested. Untested branches: stale/missing lockfile, YAML hash mismatch, additionalWinmd/ref policy, no-emit path, runtime-dependency install/update.
  • Recommendation: Add orchestrator tests with stubbed codegen/runtime-installer adapters covering each outcome and the version-sync branch. (Cross-model lowered severity: this is a test-gap, not a shipped defect.)

M7 — src/winapp-npm/src/jsbindings/codegen-runner.ts:108-228 · test-coverage

  • Severity: medium · Confidence: high
  • Finding: Destructive staging/swap/wipe safety logic lacks tests.
  • Evidence: codegen-runner.test.ts covers argv/list helpers only; validateOutputDirIsWipeable, runWithStaging, rollback, marker-required wipe, and symlink-child rejection are untested.
  • Recommendation: Test empty/managed/unmanaged output dirs, reparse-child rejection, generate-failure cleanup, and rename rollback. (Higher value given this code deletes/relocates user directories.)

M12 — src/winapp-npm/src/jsbindings/runtime-installer.ts:41-132 · test-coverage

  • Severity: medium · Confidence: high
  • Finding: Package-manager install execution paths are not covered.
  • Evidence: runtime-installer.test.ts imports only buildWindowsCmdLine; no tests for installPackageDependency/runPackageManagerInstall success, missing-PATH/UNC rejection, spawn errors, or nonzero-stderr handling.
  • Recommendation: Inject spawn/path resolution (or use fake PM executables) to test success/failure/no-PATH cases.

M4 — src/winapp-npm/src/cli.ts:77-115 · test-coverage

  • Severity: medium · Confidence: high
  • Finding: New npm wrapper dispatch behavior is untested.
  • Evidence: Tests cover cli-hooks helpers, not main() routing for init --help, init --setup-sdks none --add-js-bindings, restore --add-js-bindings, or hook forwarding.
  • Recommendation: Add cli.test.ts using an injectable dispatcher (or child-process tests with stubbed native CLI/hook modules).

L1 — src/winapp-npm/src/jsbindings/codegen-runner.ts:662-705 · alternative-solution

  • Severity: low · Confidence: high
  • Finding: Trusted-PATH executable resolution is duplicated between Node lookup and package-manager lookup.
  • Evidence: codegen-runner.ts:662-664 implements PATH fallback; package-manager-detector.ts:38-39 separately resolves launchers from trusted PATH entries.
  • Recommendation: Extract a shared resolveTrustedExecutableOnPath helper with configurable allowed extensions and workspace exclusions.

L2 — src/winapp-npm/src/jsbindings/runtime-installer.ts:23-70 · security · Multi-model: disputed (not exploitable)

  • Severity: low · Confidence: low
  • Finding: Windows installs build a cmd.exe /c string with quote-doubling escaping — flagged as potential command injection, but the cross-model pass found no real exploit path.
  • Evidence: quoteForCmd doubles quotes (arg.replace(/"/g, '""'), 34) feeding cmd.exe /c buildWindowsCmdLine(...) (64-70). However, callsites pass fixed constants — codegen uses @microsoft/dynwinrt-codegen (cli-hooks.ts:464-466), runtime uses RUNTIME_PACKAGE_NAME (orchestrator.ts:24,269), and the only variable (runtime version) is gated by parseRuntimeDependencySpec, which rejects any name other than @microsoft/dynwinrt (codegen-runner.ts:417-429).
  • Recommendation: Optional defense-in-depth — prefer spawn with an argv array (shell:false) over a cmd.exe string so future variable inputs can't reintroduce a breakout. Not a merge blocker.

Generated by the winappcli pr-review skill · 8 specialist passes + GPT-5.4 cross-model verification · 2026-06-19. No code was built or executed; verify findings before acting. 🤖

@lei9444
lei9444 requested a review from nmetulev June 22, 2026 09:47
@nmetulev
nmetulev merged commit 630aaae into main Jun 22, 2026
22 checks passed
@nmetulev
nmetulev deleted the leilzh/jsbindings branch June 22, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants