Skip to content

Work in progress: msix installer - #732

Draft
kmahone wants to merge 39 commits into
mainfrom
user/kmahone/msix
Draft

Work in progress: msix installer#732
kmahone wants to merge 39 commits into
mainfrom
user/kmahone/msix

Conversation

@kmahone

@kmahone kmahone commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Not yet ready for review.

Design decision

The MSIX legacy install migration decision defines a first-launch, consent-gated Inno-to-MSIX migration owned by the packaged Companion. SetupEngine remains responsible for gateway setup and explicit gateway removal.

@clawsweeper

clawsweeper Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codex review: blocked before merge. Reviewed September 2, 2026, 6:47 PM ET / 22:47 UTC.

ClawSweeper review

What this changes

The PR replaces the Windows Inno/ZIP installer and in-app updater lifecycle with MSIX packages, OS-managed AppInstaller updates, and revised release automation.

Regression provenance

Possible regression — suspected (reviewed change). No predecessor PR is attributed.

Merge readiness

Blocked before merge - 12 items remain

Keep open. This collaborator-authored draft still contains merge-blocking release and upgrade regressions: normal tags do not publish the MSIX assets that installed packages reference, alpha packages persist a contributor-branch feed, rehearsal tags are routed as Alpha, and legacy migration remains documentation only.

Priority: P2
Reviewed head: 7d509b1162eb3106a09b1bc8d31472842b404f87
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The branch has meaningful implementation work, but four release and upgrade correctness blockers make it unready to merge.
Proof confidence 🌊 off-meta tidepool Not applicable: This collaborator-authored draft is not subject to the external-contributor proof gate; the available material nevertheless does not demonstrate release-shaped fresh install, update, or legacy migration behavior.
Patch quality 🧂 unranked krab (1/6) 4 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: This collaborator-authored draft is not subject to the external-contributor proof gate; the available material nevertheless does not demonstrate release-shaped fresh install, update, or legacy migration behavior.
Evidence reviewed 6 items Normal releases lack published MSIX assets: The introduced release job uploads signed MSIX files only as temporary workflow artifacts and creates a GitHub Release only for msixtest tags; the normal Create Release step is commented out. Stable and Alpha packages instead embed GitHub Release asset URLs, so regular tagged releases have no corresponding public asset source.
Alpha updates point at a contributor branch: The embedded AppInstaller target explicitly sets its feed URI to user/kmahone/msix rather than main, despite being included in every non-Dev Alpha MSIX.
Rehearsal tags become Alpha packages: The channel-routing condition includes msixtest tags in the Alpha channel and comments state that this is temporary rehearsal behavior to revert before merge.
Findings 4 actionable findings [P1] Restore normal release publication
[P1] Keep rehearsal tags out of the Alpha channel
[P1] Use the durable feed for Alpha packages
Security None None.

How this fits together

Windows release CI builds and signs Companion packages, which Windows App Installer then installs and updates through a hosted feed. This PR changes that delivery path as well as the relationship between packaged installs, legacy Inno installs, and gateway state.

flowchart LR
A[Release tag] --> B[Release workflow]
B --> C[Signed MSIX packages]
C --> D[AppInstaller update feed]
D --> E[Windows package install or update]
E --> F[Companion startup]
F --> G[Legacy-install migration]
G --> H[Gateway and user state]
Loading

Decision needed

Question Recommendation
Should the project adopt MSIX as the primary lifecycle now, or retain the existing Inno/ZIP path until the documented migration and release gates are implemented and proven? Stage the MSIX transition: Keep the existing installer and updater release path until the MSIX release, feed, and migration acceptance criteria are implemented and proven.

Why: The open packaging-strategy discussion and this PR choose a product-wide upgrade contract that cannot be resolved safely through a mechanical patch alone.

Before merge

  • Restore normal release publication (P1) - Regular tags now upload signed MSIX files only as workflow artifacts, while installed packages resolve their MainPackage URLs from GitHub Releases. Because the normal release step is commented out, a stable or normal alpha tag cannot provide the package that installation and update expect.
  • Keep rehearsal tags out of the Alpha channel (P1) - The channel matcher classifies msixtest rehearsal tags as Alpha packages with update wiring. The surrounding comments identify this as temporary, but merging it would make test tags participate in the user-facing Alpha lifecycle.
  • Use the durable feed for Alpha packages (P1) - The generated embedded AppInstaller URI points at the contributor branch rather than main. Alpha installations persist that URI for later update polling, leaving them dependent on branch lifetime and branch contents after this PR is merged.
  • Implement migration before removing the legacy lifecycle (P1) - This new document correctly states that both a preserve-state uninstaller contract and a runtime migration service are required, but they are explicitly out of scope while the patch deletes the legacy installer and updater. Existing Inno users would have no implemented consent-gated transfer path for state and update ownership.
  • Resolve merge risk (P1) - A regular stable or alpha tag would leave installed packages pointing to GitHub Release MSIX URLs that were never published.
  • Resolve merge risk (P1) - Installed Alpha clients would poll a contributor branch rather than the durable main feed.
  • Resolve merge risk (P1) - Existing Inno/ZIP users have no implemented, consent-gated state-preserving migration before their lifecycle is retired.
  • Complete next step (P2) - Restore the temporary release, rehearsal-tag, and feed overrides; implement the legacy migration; and provide release-shaped Windows install, update, and upgrade evidence before merge.
  • Improve patch quality - Restore normal release publication and remove rehearsal-only routing and feed overrides.
  • Improve patch quality - Implement the documented preserve-state migration before retiring Inno and ZIP delivery.
  • Improve patch quality - Provide redacted real Windows x64 and ARM64 evidence for fresh install, update, migration, rollback, and retained gateway state.
  • Resolve maintainer decision - Resolve the maintainer decision shown above before merge.

Findings

  • [P1] Restore normal release publication — .github/workflows/ci.yml:599-626
  • [P1] Keep rehearsal tags out of the Alpha channel — .github/workflows/ci.yml:425-436
  • [P1] Use the durable feed for Alpha packages — src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj:354-361
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Changed surface 66 files; +2,414 / -3,641 lines The branch changes packaging, release automation, updater behavior, installation guidance, and legacy lifecycle code together.

Merge-risk options

Maintainer options:

  1. Complete the staged cutover (recommended)
    Restore normal release publication and durable feeds, then implement and prove the documented state-preserving migration before removing legacy delivery.
  2. Pause the replacement
    Keep this draft as design work until maintainers decide the permanent Windows packaging and upgrade contract.

Technical review

Best possible solution:

Land MSIX in stages: retain the existing release lifecycle until normal MSIX publication, durable feeds, and a consent-gated Inno-to-MSIX migration have passed real Windows fresh-install and upgrade testing on x64 and ARM64.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible: a normal tag reaches only temporary artifact uploads while generated packages reference GitHub Release asset URLs. Runtime execution was not performed because this is a read-only review.

Is this the best way to solve the issue?

No. The intended MSIX lifecycle is not safe to merge until release publication, durable update feeds, and the documented legacy migration are complete.

Full review comments:

  • [P1] Restore normal release publication — .github/workflows/ci.yml:599-626
    Regular tags now upload signed MSIX files only as workflow artifacts, while installed packages resolve their MainPackage URLs from GitHub Releases. Because the normal release step is commented out, a stable or normal alpha tag cannot provide the package that installation and update expect.
    Confidence: 0.99
  • [P1] Keep rehearsal tags out of the Alpha channel — .github/workflows/ci.yml:425-436
    The channel matcher classifies msixtest rehearsal tags as Alpha packages with update wiring. The surrounding comments identify this as temporary, but merging it would make test tags participate in the user-facing Alpha lifecycle.
    Confidence: 0.98
  • [P1] Use the durable feed for Alpha packages — src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj:354-361
    The generated embedded AppInstaller URI points at the contributor branch rather than main. Alpha installations persist that URI for later update polling, leaving them dependent on branch lifetime and branch contents after this PR is merged.
    Confidence: 0.98
  • [P1] Implement migration before removing the legacy lifecycle — docs/MSIX_LEGACY_INSTALL_MIGRATION.md:153-154
    This new document correctly states that both a preserve-state uninstaller contract and a runtime migration service are required, but they are explicitly out of scope while the patch deletes the legacy installer and updater. Existing Inno users would have no implemented consent-gated transfer path for state and update ownership.
    Confidence: 0.97

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found, but no applicable review policy affected this item.

Codex review notes: model internal, reasoning high; reviewed against 297b6c89bc45.

Labels

Label changes:

  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🌊 off-meta tidepool and patch quality is 🧂 unranked krab.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🧂 unranked krab, so this older rating label is no longer current.

Label justifications:

  • P2: This is a broad but unshipped Windows packaging transition with significant upgrade impact.
  • merge-risk: 🚨 compatibility: The patch removes legacy installer and updater behavior before its required migration path exists.
  • merge-risk: 🚨 automation: The changed release workflow intentionally disables normal release publication and alters package channel routing.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🌊 off-meta tidepool and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: This collaborator-authored draft is not subject to the external-contributor proof gate; the available material nevertheless does not demonstrate release-shaped fresh install, update, or legacy migration behavior.

Evidence

What I checked:

  • Normal releases lack published MSIX assets: The introduced release job uploads signed MSIX files only as temporary workflow artifacts and creates a GitHub Release only for msixtest tags; the normal Create Release step is commented out. Stable and Alpha packages instead embed GitHub Release asset URLs, so regular tagged releases have no corresponding public asset source. (.github/workflows/ci.yml:573, 7d509b1162eb)
  • Alpha updates point at a contributor branch: The embedded AppInstaller target explicitly sets its feed URI to user/kmahone/msix rather than main, despite being included in every non-Dev Alpha MSIX. (src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj:354, 7d509b1162eb)
  • Rehearsal tags become Alpha packages: The channel-routing condition includes msixtest tags in the Alpha channel and comments state that this is temporary rehearsal behavior to revert before merge. (.github/workflows/ci.yml:425, 7d509b1162eb)
  • Required migration is unimplemented: The newly added migration decision says both the preserve-state uninstaller switch and the runtime migration service are required but intentionally out of scope, while the PR removes the legacy installer and updater lifecycle. (docs/MSIX_LEGACY_INSTALL_MIGRATION.md:153, 7d509b1162eb)
  • Current main retains the working legacy release path: The fetched main revision still creates ZIP update payloads, builds Inno installers, and creates a normal GitHub Release with those assets; the proposed replacement is not implemented on main. (.github/workflows/ci.yml:790, 297b6c89bc45)
  • Prior blockers remain after the follow-up: The only change since the earlier reviewed head is the migration design document, so the workflow and packaging blockers previously identified remain unchanged. (docs/MSIX_LEGACY_INSTALL_MIGRATION.md:1, 7d509b1162eb)

Likely related people:

  • unknown: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (2 earlier review cycles)
  • reviewed June 12, 2026, 4:11 PM ET / 20:11 UTC sha b05f561 :: found issues before merge. :: [P1] Restore strict tag/version validation | [P1] Restore the MSIX job's test dependencies | [P1] Stop classifying rehearsal tags as Alpha releases | [P1] Point Alpha packages at the durable feed | [P1] Replace the removed uninstall cleanup contract
  • reviewed 2026-09-02T22:14:32.348Z sha b05f561 :: blocked before merge. :: [P1] Restore normal release publication | [P1] Restore MSIX job test prerequisites | [P1] Keep rehearsal tags out of the Alpha channel | [P1] Do not embed the contributor branch as an update source | [P1] Provide a migration before retiring the legacy lifecycle

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. labels Jun 9, 2026
@kmahone
kmahone force-pushed the user/kmahone/msix branch from 3559f81 to 4b0d617 Compare June 9, 2026 18:55
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 9, 2026
Keith Mahoney and others added 17 commits June 10, 2026 09:51
Master shipped sizes 24/32/48/256; Windows down-scaled larger PNGs for
Start Menu / taskbar / Alt+Tab surfaces that prefer 16/20/44. These three
PNGs fill the gap and are auto-discovered by MakePri via the existing
Assets\**\* content include and the targetsize-NN_altform-unplated
filename convention. No code, csproj, or manifest changes required.

Cherry-picked from origin/pr-468 (Square44x44Logo.targetsize-{16,20,44}_altform-unplated.png).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the conditional dispatch that produced an unpackaged
WindowsPackageType=None + app.manifest build for the Inno installer
path. Default packaging mode is now unconditionally MSIX; only the
PackageMsix=true opt-in for .msix file production remains.

Changes:
- Make <WindowsPackageType>MSIX</WindowsPackageType> +
  <WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
  unconditional.
- Delete the <PropertyGroup Condition=\'$(Unpackaged)' == 'true'\>
  block (WindowsPackageType=None + ApplicationManifest=app.manifest).
- Delete the CopyWebView2Loader target (only needed for the unpackaged
  layout; MSIX bundles the loader automatically). The unrelated
  CopyWebView2Loader target in OpenClaw.SetupPreview is untouched.
- Rewrite the explanatory comment block to drop the Unpackaged mode
  paragraph (now describes one opt-in flag instead of two).

src/OpenClaw.Tray.WinUI/app.manifest is now orphaned but left in place;
Phase 3 will delete it together with the Inno installer.

Callers that still pass -p:Unpackaged=true (scripts/build-inno-local.ps1
and the Inno publish job in .github/workflows/ci.yml) are transiently
non-functional between Phase 2 and Phase 3 — the property becomes a
no-op so the build emits an MSIX layout that Inno cannot consume. Both
callers are deleted in Phase 3, per the all-phases-land-together branch
workflow.

Audit of App.xaml.cs:355-405 _isPostSetupRestart retry: KEEP. The
branch is not Inno-specific. The tray itself spawns a fresh tray with
--post-setup-restart --wait-for-pid <oldPid> after in-process
SetupWindow completes (RestartAfterSetupAsync, line 3097). The 15s
retry + AbandonedMutexException handler prevents the new tray from
giving up on the single-instance mutex while the old tray is still
exiting. AppRefactorContractTests:135-140 enforces the call pattern.

Validation (per AGENTS.md):
- build.ps1: all 5 projects built.
- Shared.Tests: 2049 passed, 29 skipped (env-only), 0 failed.
- Tray.Tests: 958 passed, 0 skipped, 0 failed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Delete Inno Setup distribution path now that MSIX is the always-on package
type. Phase 3B will follow up with Updatum removal; Phase 4 will rebuild
the release pipeline around the .msix file produced by `-p:PackageMsix=true`.

Deleted files (5 source + 2 test):
- installer.iss (256 lines)
- scripts/build-inno-local.ps1
- scripts/Uninstall-LocalGateway.ps1
- src/OpenClaw.Tray.WinUI/app.manifest (orphaned by Phase 2)
- tests/PackagingTests/Test-InnoUninstallOrdering.ps1 (parent dir removed)
- tests/OpenClaw.Tray.Tests/InstallerIssAssertionTests.cs (9 tests)
- tests/OpenClaw.Tray.Tests/ReleaseSigningWorkflowTests.cs (4 tests; Phase 5
  will replace with MSIX-signing assertions)

ci.yml: drop -p:Unpackaged=true from build/publish (Phase 2 cleanup), retire
the Download VC Redist + Install Inno Setup + Build x64/arm64 Installer +
Sign Installers steps in the release job, remove .exe entries from the
release files: list and body, and update the paused build-msix comment.

App.xaml.cs: remove the AppMutex coordination comment that referenced
installer.iss; the OpenClawTray mutex itself stays unchanged.

SetupEngine.UI/LogFileLauncher.cs: rewrite the "Unpackaged process" comment
to cover both the no-package-identity and library-only call sites.

Ship-guard ported from installer.iss to MSBuild: two new targets on
OpenClaw.Tray.WinUI.csproj (ValidateSetupEngineUiNotShipped after Build,
ValidateSetupEngineUiNotPublished after Publish) fail the build if
OpenClaw.SetupEngine.UI.exe lands in the tray bin/publish output. Pairs
with a new "Hazards" section in docs/SETUP_ENGINE_REDESIGN.md explaining
the in-process design and pointing at PR #468's bootstrapper diffs as the
worked example anyone splitting SetupEngine into its own process would
need to study first.

Test-ReleaseNativeDependencies.ps1: remove -RequireInstallerVCRedist /
-InstallerVCRedistPath params and their dead handler (only Inno called
them); -RequireAppLocalVCRuntime and -SkipNativeLoadProbe stay (still used
by ci.yml's Verify Native Runtime Payload steps).

Docs: drop the Inno helper section + .exe-installer references from
DEVELOPMENT.md, docs/RELEASING.md, docs/VERSIONING.md, and the Inno
comment in scripts/validate-msix-storage-paths.ps1. README.md + docs/SETUP.md
download tables are replaced with TODO placeholders that Phase 7 will fill
with MSIX-flavored content.

Validation (on user/kmahone/msix, Windows):
- ./build.ps1 green
- Shared.Tests: 2049 passed / 29 skipped (unchanged from Phase 2)
- Tray.Tests: 945 passed (was 958; -13 = 9 InstallerIssAssertion + 4
  ReleaseSigningWorkflow tests removed, as expected)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updatum becomes dead under MSIX-primary publishing once <AutomaticBackgroundTask />
in the .appinstaller XML (Phase 4) is the update mechanism. No in-app updater
under MSIX, no manual "Check for updates" button.

Removed:
- Updatum NuGet PackageReference from OpenClaw.Tray.WinUI.csproj
- App.xaml.cs: using Updatum, AppUpdater static field, BuildInitialUpdateInfo
  call, startup update-check gate, IAppCommands.CheckForUpdates impl, dispatcher
  case "checkupdates", HandleDeepLink wiring, and the entire #region Updates
  block (~460 lines).
- IAppCommands.CheckForUpdates declaration.
- DeepLinkHandler.cs: case "updates"/"update"/"check-updates"/"update-check"
  block + CheckForUpdates Func field.
- AboutPage.xaml CheckUpdatesButton + AboutPage.xaml.cs OnCheckUpdatesClick.
- HubWindow.xaml.cs orphan CheckForUpdatesAction property.
- SettingsData.SkippedUpdateTag + 4 SettingsManager references.
- Dialogs/UpdateDialog.cs (deleted file).
- Dialogs/DownloadProgressDialog.cs (deleted file).
- Update*, CheckUpdates*, DownloadProgress* resource keys from all 5 locale
  resw files (en-us, zh-tw, zh-cn, nl-nl, fr-fr; 18 keys per file).
- ci.yml: Updatum auto-update ZIP comment + x64/arm64 "Create Release ZIP"
  steps + ZIP entries from release files: + Portable bullets from release
  body. Release will have no binary artifacts until Phase 4 MSIX pipeline.
- Test fixtures: SettingsRoundTrip (4 SkippedUpdateTag refs), DeepLinkParser
  (2 InlineData rows + fixture init), TrayMenuWindowMarkup (2 Assert.Contains),
  AppRefactorContract (CheckForUpdatesAsync from AssertInOrder),
  LocalizationValidation (WindowTitle_Update + Update_OK invariants).
- Docs: README.md + docs/SETUP.md (openclaw://check-updates row);
  docs/RELEASING.md (Portable ZIP Updatum block);
  docs/VERSIONING.md (Updatum Library reference).

Kept:
- UpdateCommandCenterInfo DTO in OpenClaw.Shared/Models.cs - public protocol
  type sent to external agent clients; default-initialized (Status="Unknown",
  CurrentVersion=null). AppStateSnapshot.LastUpdateInfo wiring stays.

Validation:
- ./build.ps1 green
- Shared.Tests: 2049 passed, 29 skipped (unchanged)
- Tray.Tests: 943 passed (was 945; -2 = DeepLinkParserTests InlineData rows)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Symptom (caught while smoke-testing the MSIX-primary build): asking the
agent to show a Windows notification throws

  InvalidOperationException: Your app manifest must have a
  toastNotificationActivation extension with a valid
  ToastActivatorCLSID specified.
  at ToastNotificationManagerCompat.CreateToastNotifier()
  at ToastContentBuilder.Show()
  at ToastService.ShowToast(...)

Root cause: Microsoft.Toolkit.Uwp.Notifications (which we still use for
all toasts via App.OnToastActivated + interactive AddButton flows) has
two code paths -- an unpackaged shortcut/COM-self-registration path and
a packaged path that reads ToastActivatorCLSID from the appx manifest.
Phase 2 of the MSIX-primary branch dropped -p:Unpackaged=true, so we now
always hit the packaged path. With no manifest extension declared, the
toolkit cannot find a CLSID and throws on first ShowToast call.

Fix: declare a stable CLSID for the toast activator in the manifest:

- Add desktop:Extension Category="windows.toastNotificationActivation"
  with ToastActivatorCLSID="EF9297B3-EEEB-4E50-8306-D1D118E04BC7".
- Add the matching com:Extension/com:ComServer/com:ExeServer entry so
  the COM server is wired to OpenClaw.Tray.WinUI.exe with the
  conventional -ToastActivated arg.
- Declare the desktop + com namespaces and include them in
  IgnorableNamespaces.

The CommunityToolkit generates the actual activator type at runtime and
binds it to this CLSID; no extra C# is needed. App.ToastActivation.cs
already wires ToastNotificationManagerCompat.OnActivated to
OnToastActivated and parses arguments via ToastArguments.Parse, so the
button-click roundtrip works as soon as the CLSID is reachable.

Validation:
- ./build.ps1 green (manifest passes MakeAppx schema check).
- Tray.Tests still pass (no source changes; manifest-only edit).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously the precheck only warned and the post-build summary suggested `Add-AppxPackage -AllowUnsigned`. That command does not work for this MSIX package on stock Windows (AllowUnsigned only applies to a narrow set of developer-mode scenarios), so users following the suggestion would fail at install time.

Now: missing cert => Write-Error + exit 1 in the preflight, with a clear message pointing at scripts\setup-dev-msix-cert.ps1. The post-build install hint always shows the signed Add-AppxPackage form (the unsigned branch is now unreachable). Docstring updated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… workflow

Adopts the publishing-infrastructure pattern from PR #468 (treated as a
reference design only, not cherry-picked) and adapts it to our
WindowsAppSDKSelfContained=true MSIX. Because the WindowsAppRuntime is
bundled inside the .msix, the AppInstaller feed has no <Dependencies>
block, no runtime-URI rendering, and no separate runtime MSIX release
asset.

What this commit adds
- installer/openclaw-companion.appinstaller.template — 6 placeholders
  (VERSION, PUBLISHER, IDENTITY_NAME, PROCESSOR_ARCHITECTURE, MSIX_URI,
  APPINSTALLER_URI), AutomaticBackgroundTask-only UpdateSettings.
- installer/appinstaller/openclaw-{x64,arm64}.appinstaller — bootstrap
  feed files at version 0.0.0.0; the appinstaller-feed-pr workflow
  rewrites these on each stable release tag.
- installer/appinstaller/README.md — explains the stable-feed model.
- scripts/render-appinstaller.ps1 — substitutes placeholders, asserts
  the rendered XML parses and contains no <Dependencies> block.
- scripts/validate-appinstaller-hosting.ps1 — Content-Type / Content-
  Length / Range checks against the hosted .appinstaller and .msix URLs,
  with -AllowGitHubContentTypes for raw.githubusercontent.com.
- scripts/test-appinstaller-update.ps1 — local HttpListener-backed
  vN -> vN+1 upgrade smoke using PackageManager
  .AddPackageByAppInstallerFileAsync.
- .github/workflows/appinstaller-feed-pr.yml — workflow_dispatch input
  takes a release tag, renders the two feed files, validates them, and
  opens a PR to advance the stable feed. Uses OpenClaw Foundation
  publisher; rejects pre-release tags; here-string PR body uses
  Set-Content -Value so the body renders as Markdown (fixes the
  8-space-indent code-block bug in PR #468's workflow).
- tests/OpenClaw.Tray.Tests/AppInstallerTemplateAssertionTests.cs — 8
  test methods covering template shape, the new
  Template_HasNoDependenciesBlock invariant, the two bootstrap feed
  files, the validation script, the smoke script, and the feed-update
  workflow.
- README.md — replaces the Phase-7 TODO placeholder with x64 and ARM64
  Install links pointing at the raw GitHub .appinstaller URLs.

What this commit does NOT add
- No in-app "Check for updates" button or AppInstallerUpdateService.
  Windows AppInstaller's AutomaticBackgroundTask handles all polling
  at OS level under MSIX.
- No Microsoft.WindowsAppRuntime.2 release asset or feed dependency —
  the runtime is bundled (WindowsAppSDKSelfContained=true).

Validation
- ./build.ps1: green.
- Shared.Tests: 2049 passed / 29 skipped (matches baseline).
- Tray.Tests: 957 passed (was 943; +14 effective test cases from the
  new file).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Phase 4 appinstaller feed workflow expected release assets named

'OpenClawCompanion-<3partVersion>-win-<arch>.msix', which would have required a

rename step in the Phase 5 release job (Option A). Switching to Option B:

match whatever MSBuild emits by default for GenerateAppxPackageOnBuild=true,

i.e. 'OpenClaw.Companion_<4partVersion>_<arch>.msix'.

* appinstaller-feed-pr.yml: Get-RequiredAsset patterns updated to use the

  4-part $version (not the 3-part $versionText), dotted identity, and

  underscore separators. Uses ${version} to keep _ from being absorbed

  into the variable name.

* AppInstallerTemplateAssertionTests: matching Assert.Contains /

  Assert.DoesNotContain updates so the pin reflects the new convention.

Inside the rendered .appinstaller, <MainPackage Uri> uses the actual

GitHub release asset name, so AppInstaller behavior is unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Unpause the build-msix matrix job and wire its outputs into the release
job so that tagged builds produce signed .msix artifacts attached to the
GitHub Release.

- ci.yml build-msix: drop `if: false` paused gate and
  `continue-on-error: true` placeholder; the job is now load-bearing.
- ci.yml release: add `build-msix` to `needs:` plus matching
  `needs.build-msix.result == 'success'` guard.
- Download the per-arch `openclaw-msix-win-{x64,arm64}` artifacts.
- Sign each .msix in place using `azure/artifact-signing-action@v2`
  with `files-folder-filter: msix` (mirrors the existing exe signing
  pattern: same endpoint, signing account, certificate profile, OIDC
  auth via azure/login).
- Attach both signed .msix files to the release via `files:` and
  rewrite the release body so it points users at the AppInstaller links
  in the README (primary install path) and notes the .msix assets as a
  direct-install fallback.

Validation:
- ./build.ps1 green
- Shared.Tests: 2049 passed / 29 skipped (baseline)
- Tray.Tests: 957 passed (baseline)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After Phase 3A removed Inno and Phase 5 wired the MSIX into the release,
the `build` job's loose unpackaged-tray artifact ceased to be shipped
to any user. The release job was still downloading it, signing the
loose exe, and running signature/native-dep validation against bits
that were then discarded. This commit removes that dead infrastructure
and preserves the most valuable validation against what we actually
ship.

ci.yml changes:
- Delete the `build` job in its entirety (loose `dotnet publish`,
  Test-ReleaseNativeDependencies on publish/, GitVersion verify,
  Upload Tray Artifact -> openclaw-tray-{rid}).
- Drop `build` from `release.needs:` and from the corresponding
  `needs.build.result == 'success'` guard.
- In `release`, remove: 2 tray-artifact download steps, 2 stage exe
  for signing steps, 2 sign-loose-exe steps, and 4 verify steps
  (Test-ReleaseExecutableSignatures and Test-ReleaseNativeDependencies
  against artifacts/tray-win-*).
- In `build-msix`, add a new `Verify MSIX Package Contents` step
  that runs immediately after the .msix is produced. It extracts the
  .msix (a zip), confirms `OpenClaw.Tray.WinUI.dll` is present with
  the correct GitVersion ProductVersion, and runs the existing
  Test-ReleaseNativeDependencies.ps1 against the extracted payload so
  the libsodium / VC++ runtime presence canary continues to fire --
  but now against the actual shipped MSIX bits, not a phantom
  unpackaged build.

Net diff: -108 lines from ci.yml; pipeline shape simplified from
six jobs to five (release no longer depends on a parallel build job
whose output it never used).

Validation:
- ./build.ps1 green
- Shared.Tests: 2049 passed / 29 skipped (baseline)
- Tray.Tests: 957 passed (baseline)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 4 AppInstaller infrastructure was authored against master but the default branch was renamed to main (commit 37b0ea6). The stale refs would cause silent failure: AppInstaller polling would forever fetch frozen XML from the now-inactive origin/master branch, and the feed-update PR workflow would target a branch that doesn't accept commits.

Fixed:

- installer/appinstaller/openclaw-{x64,arm64}.appinstaller: <AppInstaller Uri> -> main

- installer/appinstaller/README.md: hosting URLs + prose -> main

- README.md: end-user install links -> main

- .github/workflows/appinstaller-feed-pr.yml: ref/raw URL/PR --base -> main

- scripts/render-appinstaller.ps1: docstring URLs -> main

- scripts/validate-appinstaller-hosting.ps1: docstring -> main

- tests/OpenClaw.Tray.Tests/AppInstallerTemplateAssertionTests.cs: assertions tracking the above

Also swept pre-existing master refs that the rename PR (37b0ea6) missed:

- docs/RELEASING.md, docs/VERSIONING.md: prerelease prose

- tests/.../LocalizationValidationTests.cs: comment

- src/.../ConnectionPage.xaml.cs: comment

Left alone (per main's rename PR intent): dual [main, master] CI

triggers, GitVersion ^(master|main)$ regex, third-party URLs, and all

'Master switch/toggle/control' UX terminology (unrelated to git branch).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
build-msix invokes VS MSBuild without first running GitVersion, so the GitVersion.MsBuild package can't compute version metadata and the WinUI .dll inside the MSIX falls back to AssemblyVersion 1.0.0. The Verify MSIX Package Contents step then correctly fails:

  MSIX-internal ProductVersion '1.0.0' did not match GitVersion SemVer '0.6.4-PullRequest732.54'.

Mirror the gitversion/setup + gitversion/execute steps from the test job before Build MSIX Package. The execute action exports GitVersion_* environment variables that GitVersion.MsBuild picks up to inject Assembly/File/InformationalVersion, satisfying the verify assertion.

fetch-depth: 0 is already set on the checkout, so GitVersion can read git history. The existing manifest-patch step (which sets Appx package identity version) is unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t PR iteration

build-msix only consumed needs.test.outputs.{semVer,majorMinorPatch}, which are now produced locally by the gitversion/execute step inside the job. e2etests was a pure gate (no outputs).

Swap manifest-patch + verify references from needs.test.outputs.* to steps.gitversion.outputs.*, then drop the needs:[] list so build-msix starts in parallel with test/e2etests on every push.

REVERT before merge — release job still gates on all four (line 491), so production releases are unaffected by this temporary change; the only effect is faster PR feedback. Restore 'needs: [test, e2etests]' on build-msix and switch the two version refs back to needs.test.outputs.*.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…X payload

Test-ReleaseNativeDependencies.ps1 -RequireAppLocalVCRuntime fails after the MSIX-payload extract because vcruntime140.dll is missing next to libsodium.dll:
  Missing app-local vcruntime140.dll next to libsodium.dll.

Root cause: the CopyOpenClawVCRuntime* targets in src/Directory.Build.targets only ship a current VS-resolved runtime via CopyOpenClawVCRuntimeToPublish (AfterTargets=Publish). The pre-fix CI step ran 'msbuild /t:Build', which only triggers CopyOpenClawVCRuntimeToOutput - x64-only AND sourced from the stale 14.29 NuGet that the comment explicitly warns is too old for onnxruntime >= 1.20. Worse, the WinUI single-project AppX packaging task collects payload from publish output, not from the build TargetDir, so even the stale copies wouldn't end up inside the MSIX.

Switching to 'dotnet publish ... -p:PackageMsix=true' matches what build.ps1 does locally and what produces working MSIX packages on dev machines. publish triggers CopyOpenClawVCRuntimeToPublish (VS-install resolution -> current 14.40+ DLLs) and ValidateOpenClawVCRuntimePublished, which guarantees vcruntime140.dll lands in PublishDir before the AppX packager collects payload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keith Mahoney and others added 3 commits June 12, 2026 10:41
…hannel/ReleaseTag

Rename the MSBuild property and matching build.ps1 parameter to drop the
OpenClaw prefix. The names are scoped enough to be unambiguous without it and
shorter to type.

  OpenClawChannel  -> ReleaseChannel
  OpenClawReleaseTag -> ReleaseTag

Mechanical rename across 3 files (50 total swaps): src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj, src/OpenClaw.Tray.WinUI/Package.appxmanifest, build.ps1. The internal csproj-local properties (_OpenClawIdentityName, _OpenClawDisplayName, _OpenClawRemoveAutoUpdate, _OpenClawArch, _OpenClawEmbedArch, etc.) keep their _OpenClaw prefix since they are private to the csproj and the convention is that private MSBuild properties are prefixed with _.

No behavior change. build.ps1 -Project WinUI -PackageMsix -ReleaseChannel Alpha -ReleaseTag v0.6.4-alpha.1 produces the same MSIX it did before this commit under the old parameter names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ReleaseTag

Commit 3 of the three-channel embedded-AppInstaller production rollout. Wires CI's build-msix job to the channel mechanism the csproj and build.ps1 now consume.

Changes
=======
.github/workflows/ci.yml (build-msix job):
  - Replaces the inline 'Patch MSIX manifest metadata' pwsh step (which
    hand-rolled the Stable/Alpha identity rewrite via XML manipulation) with
    a tiny 'Determine release channel' step that maps the tag pattern to
    one of Stable / Alpha / Dev:
      v0.6.7              -> Stable
      v0.6.7-alpha.N      -> Alpha
      anything else       -> Dev
  - Build MSIX Package step adds -p:ReleaseChannel=<channel> and
    -p:ReleaseTag=<tag>. SyncAppxManifestVersionTarget (csproj) consumes
    them to set Identity Name / DisplayName / strip-or-keep AutoUpdate, and
    RenderEmbeddedAppInstaller uses them to render the per-channel embedded
    AppInstaller file with the correct release-asset URL.
  - The Channel/IdentityName mapping is now expressed in one place per
    layer instead of three (was: ci.yml inline pwsh + .csproj Sync logic).

Not included in this commit (still TEMP; intentional, per user instruction
to keep the rehearsal pipeline working):
  - build-msix needs:[]    (revert-msix-needs-temp todo)
  - Verify tag version output msixtest skip    (revert-verify-tag-msixtest-skip todo)
  - Upload Signed MSIX (TEMP) artifact-upload steps  (revert-msixtest-prerelease-create todo)
  - Create Prerelease (TEMP - msixtest tags only)    (revert-msixtest-prerelease-create todo)
  - Original Create Release step (still commented out)
All of the above will be reverted in a final cleanup commit before the PR
merges to main.

No push, no tag - user controls CI runs.

Local validation (Commits 1 + 2 + 2.5 + 3) was done end-to-end on a previous build of build.ps1 -PackageMsix -ReleaseChannel Alpha/Stable/Dev; CI exercise of the new channel detection requires pushing a tag, which is left to the user.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mahone/msix branch and treat msixtest tags as Alpha

Four TEMP edits to enable an end-to-end Alpha-channel install + silent-update
rehearsal on the user/kmahone/msix branch without affecting main. All four
are tracked in session todos and will be reverted before merging.

Changes
=======

installer/appinstaller/openclaw-alpha-x64.appinstaller
installer/appinstaller/openclaw-alpha-arm64.appinstaller
  Alpha polled-feed bootstrap files. Self-Uri swapped from .../main/... to
  .../user%2Fkmahone%2Fmsix/... so installed Alpha builds poll this branch's
  copy of the feed during the rehearsal. (revert-alpha-feed-branch-url todo)

src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj
  _OpenClawFeedUri literal swapped from .../main/... to
  .../user%2Fkmahone%2Fmsix/.... XmlPoke writes this into the embedded
  openclaw-update.appinstaller's self-Uri at build time, so each Alpha MSIX
  built from this branch registers the branch's feed as its update-poll
  endpoint. (revert-embedded-feed-branch-url todo)

.github/workflows/ci.yml
  Determine release channel regex now treats vX.Y.Z-msixtest(.N)? as Alpha
  (was: only vX.Y.Z-alpha(.N)?). Lets us push throwaway msixtest tags that
  exercise the full Alpha channel pipeline (signed MSIX, prerelease
  Release, embedded AppInstaller for auto-update) without burning real
  alpha version numbers. (revert-msixtest-as-alpha todo)

Local validation
================
build.ps1 -PackageMsix -ReleaseChannel Alpha -ReleaseTag v0.6.7-msixtest.1
builds an MSIX with the embedded openclaw-update.appinstaller correctly
pointing at user/kmahone/msix's openclaw-alpha-x64.appinstaller. Both
URL forms (with %2F and with literal /) return 200 from raw.githubusercontent.com.

Test plan (executed by hand after this push)
============================================
1. Push v0.6.7-msixtest.1. CI builds Alpha-channel MSIX, signs, publishes
   prerelease. Download and install.
2. Edit installer/appinstaller/openclaw-alpha-x64.appinstaller: bump
   Version + MainPackage Version to 0.6.8.0; MainPackage Uri to point at
   v0.6.8-msixtest.1's release asset (OpenClaw.Tray.WinUI_0.6.8.0_x64.msix).
   Commit + push.
3. Push v0.6.8-msixtest.1. CI publishes new prerelease.
4. Quit and relaunch the installed app; OS prompt should offer the update.
   Verify Get-AppxPackage OpenClaw.Companion.Alpha shows 0.6.8.0.
5. Cleanup: gh release delete v0.6.7-msixtest.1 v0.6.8-msixtest.1 --cleanup-tag,
   Get-AppxPackage OpenClaw.Companion.Alpha | Remove-AppxPackage, then run
   the 7 pending TEMP-revert todos before opening the merge PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kmahone
kmahone temporarily deployed to release-signing June 12, 2026 18:17 — with GitHub Actions Inactive
@kmahone
kmahone temporarily deployed to release-signing June 12, 2026 18:34 — with GitHub Actions Inactive
Keith Mahoney and others added 2 commits June 12, 2026 11:43
UpdateBlocksActivation=false never applies on a persistent tray app -
Windows downloads then deletes the staged package because the app is
still running. Switch to the canonical persistent-app settings and
sync OnLaunch across all six .appinstaller files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kmahone
kmahone temporarily deployed to release-signing June 12, 2026 19:23 — with GitHub Actions Inactive
@kmahone
kmahone temporarily deployed to release-signing June 12, 2026 19:38 — with GitHub Actions Inactive
Keith Mahoney and others added 3 commits June 12, 2026 12:50
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale due to inactivity.
Please update it or it will be closed.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Closing due to inactivity.
If this PR should be revived, reopen it with current context and a fresh validation plan.

@github-actions github-actions Bot closed this Jul 5, 2026
@shanselman shanselman reopened this Sep 2, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Sep 2, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Sep 2, 2026
@github-actions github-actions Bot removed the stale label Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants