Skip to content

[Feature]: Modernize the winapp manifest * command surface for CLI v0.6.x #247

Description

Is your feature request related to a problem? Please describe.

The extension's manifest commands were designed against winappcli ~v0.3.1, but scripts/download-cli.ps1 downloads the latest release — currently v0.6.1. We ship a 0.6.x CLI behind a 0.3.x UI, so most of the manifest surface is unreachable from VS Code.

Against the v0.6.1 schema (docs/cli-schema.json in microsoft/winappcli):

Command Surfaced today Unsurfaced
manifest generate --template directory (positional), --package-name, --publisher-name, --version, --description, --logo-path, --executable, --if-exists
manifest update-assets image-path --light-image, --manifest
manifest add-alias (nothing — runs bare) --name, --app-id, --manifest

The naive fix — bolt seven more QuickPick/InputBox steps onto winapp.manifestGenerate — is the wrong fix, because of what this extension already owns.

Describe the solution you'd like

1. Generate is a bootstrap, not a form — "generate minimal, then open the editor"

Recommendation: do not prompt for name/publisher/version/description/logo/executable.

src/manifest-editor/manifest-types.ts already models every one of those values — IdentityData.name/.publisher/.version, PropertiesData.description/.logo/.publisherDisplayName, ApplicationData.executable — with browse buttons (browseImage, browseExe) and XSD-backed validation (manifest-validator.ts, src/manifest-intellisense/). A QuickPick chain for the same six values is a strictly worse, unvalidated, non-revisable duplicate of a UI we already ship. Get the publisher DN wrong in a one-shot prompt and your only recovery is editing the file anyway.

Proposed flow:

  1. Resolve the project dir (existing resolveProjectDirectory).
  2. QuickPick template — packaged / sparse — with real descriptions from the schema ("full MSIX app" / "desktop app with package identity for Windows APIs") rather than today's bare two strings.
  3. Run with the positional directory argument (never passed today) and --if-exists per §3.
  4. On success, show "Manifest created. [Open in Manifest Editor] [Show File]", reusing vscode.openWith … ManifestEditorProvider.viewType.

That makes generate the front door to the editing story rather than a competitor to it.

2. If prompts are wanted, the minimum viable subset

Template → package name (InputBox prefilled with path.basename(projectDir), which is the CLI's own default, plus MSIX name validation in validateInput) → publisher DN (prefilled CN=<os.userInfo().username>; the CLI auto-wraps bare names, so hint rather than hard-validate).

Stop there. --version (defaults 1.0.0.0), --description (defaults My Application), --logo-path and --executable belong in the editor. --executable especially defaults to <package-name>.exe and is usually wrong until after the first build — prompting for it at generate time invites a stale value.

3. --if-exists maps to a VS Code confirmation, not a QuickPick

Don't leak the error/skip/overwrite enum into the UI. Instead, probe for an existing Package.appxmanifest / appxmanifest.xml first (the extension already has isManifestPath and MANIFEST_SELECTOR):

  • None exists → run with --if-exists error. That's the CLI default and acts as a race guard.
  • One exists → skip the CLI and show a modal: "<file> already exists in <dir>." with [Open in Manifest Editor] (default) and [Overwrite]. Only the latter re-runs with --if-exists overwrite, as a showWarningMessage({ modal: true }) since it's destructive and unrecoverable through the extension.
  • skip has no user-facing analogue — "do nothing" is just cancelling the dialog.

This turns the common "I already have one" case into a one-click route into the editor.

4. Reachability, and the init overlap

The manifest editor is a CustomTextEditor bound to an existing document, so it can't host "create a manifest that doesn't exist yet". Keep generate → editor as the primary link and don't add a Generate button inside the webview. Instead, add an explorer/context menu contribution on folders (when: explorerResourceIsFolder) — today winapp.manifestGenerate has no menu contributions at all, palette only.

init overlap — flagging, not redesigning. Per the schema, init also "creates Package.appxmanifest with default assets", and the CLI's own generate description says "For full setup, use 'init' instead." The two commands use different flag spellings for the same concepts: --package-name/--publisher-name vs --name/--publisher; --template sparse vs --sparse; --if-exists overwrite vs --force. Whoever does this work should extract shared helpers (a single package-name prompt, a single publisher-DN prompt, and the §3 "already exists" confirmation) into e.g. src/manifest-prompts.ts so both commands consume them.

Separately flagged: winapp.init today hardcodes --use-defaults and never passes --name/--publisher, so it has the same under-surfacing problem. Out of scope here.

5. Sibling gaps worth folding into the same change

manifest update-assets (extension.ts:1468)

  • Add --light-image — the only way to get theme-specific assets.
  • Pass --manifest explicitly instead of relying on "search current directory". Matters when resolveProjectDirectory picked a non-root project.
  • Accept svg and ico in the file filter. The schema lists SVG, PNG, ICO, JPG, BMP, GIF; the extension's filter omits svg and ico — and the editor's own browseImage filter already includes them, so this is an internal inconsistency.
  • Mirror --light-image/--manifest in the editor's "Regenerate Assets" handler (manifest-editor-provider.ts ~line 392) so both entry points stay equivalent.

manifest add-alias (extension.ts:1635)

  • Runs completely bare today — no way to choose the alias name or target Application.
  • Add an optional alias-name InputBox (empty = CLI infers from Executable).
  • Add --app-id only when the manifest has more than one <Application>; manifest-parser.ts can already enumerate them, so the QuickPick can list real IDs. Single-app manifests get no prompt.
  • Pass --manifest for the same multi-project reason.
  • Consider an "Add Execution Alias" button in the editor's Application card, next to the existing "Regenerate Assets".

Additional context

Mechanical implication: runWinappCommand (extension.ts:220) creates a terminal and sendTexts — fire-and-forget, no exit code. Any post-generate action (open the editor, report "already exists") requires moving to runWinappCapture (extension.ts:281), which spawns with progress + cancellation and resolves { code, output }.

Existing precedent: the editor webview already shells out to the CLI — manifest-editor-provider.ts handles an updateAssets message by execFile-ing winapp manifest update-assets <image> with WINAPP_CLI_CALLER set, driven by the "Regenerate Assets" button (webview-script-applications.ts:247). Editor→CLI invocation is established, not new.

Testability: extract the shared prompt/validation helpers into a module with no vscode import, following the existing project-resolver.ts / winapp-tool.ts dependency-injection convention, so they get unit tests like test/project-resolver.test.ts.

Open questions:

  1. Generate-minimal-then-open-editor (recommended) vs. the middle path in §2 vs. a full prompt chain.
  2. After a successful generate: auto-open the editor, or notification with an "Open in Manifest Editor" action?
  3. Are the explorer/context menu contributions in scope?
  4. Do the update-assets / add-alias gaps belong in the same PR or a follow-up?

Schema referenced: gh api repos/microsoft/winappcli/contents/docs/cli-schema.json?ref=v0.6.1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions