Integrate JS/TS WinRT bindings into winapp init (managed codegen + runtime, kept in version sync)#536
Conversation
There was a problem hiding this comment.
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|generatecommands andinit --js-bindings*flags (npm-only gated viaWINAPP_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.
Build Metrics ReportBinary Sizes
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 Time32ms median (x64, Updated 2026-06-22 10:05:36 UTC · commit |
nmetulev
left a comment
There was a problem hiding this comment.
- Should we have
winapp initdetect 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 thejsbindingscommands which can be removed - we can simply usewinapp initandwinapp restorelike we do for c++ - The
--js-bindings-aifeels odd, why are we adding a single property just for AI and not for anything else? Could we do without this option?
This comment was marked as outdated.
This comment was marked as outdated.
…ilzh/jsbindings
…ilzh/jsbindings
winapp node jsbindings for typed JS/TS WinRT bindings
nmetulev
left a comment
There was a problem hiding this comment.
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?
(There is also two spaces between the icon and the warning - should be one space)
PR Review —
|
| 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-bindingscan exit successfully (exit 0) without adding bindings whenpackage.jsonis missing. - Evidence:
askBindingsKindreturnskind: 'no'for a missingpackage.jsonbefore checkinginputs.addJsBindings(lines 72-77, 90-91);handleInitthen returns onoutcome.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-bindingscases (cli.ts:86-95,cli.ts:104-112), so this path is an inconsistency. - Recommendation: When
addJsBindingsis true andpackage.jsonis 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), theninstallPackageDependency(... 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:
--jsonis folded intoquiet(line 217), but failure paths still callui.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-bindingsstill prompts ("Overwrite?") on projects that already havewinapp.jsBindings, breaking non-interactive use. - Evidence: Existing config enters
if (inputs.existingJsBindings)(line 49) and callsconfirmationPrompt('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-bindingsnon-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:\packagesare rejected as "suspiciously broad," breaking generation whenNUGET_PACKAGESis 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:\nugettests.
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 bareversion:(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.yamlsemantics 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:
:39addsIWinmdsLockfileService;574-580computes YAML hash and writes the lockfile. - Recommendation: Extract into a dedicated
WriteRestoreInventoryAsyncmethod/service soWorkspaceSetupServiceonly 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 resolves0.2.1). - Evidence:
"@microsoft/winappcli": "^0.2.0"withwinapp.jsBindingsadded;package-lock.json:1196-1198resolves0.2.1. - Recommendation: Bump the sample dependency/lockfile to the first winappcli version that ships the
restoreJS-bindings hooks andnode generate-bindings.
M15 — src/winapp-npm/src/winapp-commands.ts:241-270 · packaging, docs-and-samples
- Severity: medium · Confidence: high
- Finding:
--add-js-bindingsis a public npm-wrapper init option but is absent from the typed npm command surface and the autogenerateddocs/cli-schema.json. - Evidence:
WRAPPER_ONLY_FLAGS = new Set(['--add-js-bindings'])(cli-args.ts:12); no match foradd-js-bindings/jsBindingsinwinapp-commands.tsordocs/cli-schema.json, whiledocs/usage.md:38-49documents 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
additionalWinmdsregeneration (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.tscovers 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.tsimports onlybuildWindowsCmdLine; no tests forinstallPackageDependency/runPackageManagerInstallsuccess, 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-hookshelpers, notmain()routing forinit --help,init --setup-sdks none --add-js-bindings,restore --add-js-bindings, or hook forwarding. - Recommendation: Add
cli.test.tsusing 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-664implements PATH fallback;package-manager-detector.ts:38-39separately resolves launchers from trusted PATH entries. - Recommendation: Extract a shared
resolveTrustedExecutableOnPathhelper 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 /cstring with quote-doubling escaping — flagged as potential command injection, but the cross-model pass found no real exploit path. - Evidence:
quoteForCmddoubles quotes (arg.replace(/"/g, '""'), 34) feedingcmd.exe /c buildWindowsCmdLine(...)(64-70). However, callsites pass fixed constants — codegen uses@microsoft/dynwinrt-codegen(cli-hooks.ts:464-466), runtime usesRUNTIME_PACKAGE_NAME(orchestrator.ts:24,269), and the only variable (runtime version) is gated byparseRuntimeDependencySpec, which rejects any name other than@microsoft/dynwinrt(codegen-runner.ts:417-429). - Recommendation: Optional defense-in-depth — prefer
spawnwith an argv array (shell:false) over acmd.exestring 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. 🤖

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:
Related Issue
Type of Change
Checklist
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 initcommand, allowing developers to call WinRT APIs directly from JS/TS without the need for native addons. The new option--add-js-bindingscan 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-bindingsBreaking Change: None.