Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/actions/spelling/allow/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ MENUITEMINFOW
MINIMIZEBOX
MOUSELEAVE
mov
MSSTORE
MULTIPLEUSE
NCHITTEST
NCLBUTTONDBLCLK
Expand Down Expand Up @@ -199,6 +200,8 @@ winstamin
wmemcmp
wpc
wtcli
WSAHOST
WSANO
WSF
WWH
wwinmain
Expand Down
1,025 changes: 916 additions & 109 deletions src/cascadia/TerminalApp/FreOverlay.cpp

Large diffs are not rendered by default.

116 changes: 108 additions & 8 deletions src/cascadia/TerminalApp/FreOverlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "FreAgentEntry.g.h"
#include "FreOverlay.g.h"

#include <mutex>

namespace winrt::TerminalApp::implementation
{
struct FreAgentEntry : FreAgentEntryT<FreAgentEntry>
Expand Down Expand Up @@ -55,21 +57,68 @@ namespace winrt::TerminalApp::implementation
// Things that can block FRE completion, in priority order (lower value
// = higher priority). Only the highest-priority problem is surfaced in
// the bottom-left error area at a time (see _ShowProblem).
//
// WinGet install failures are not in this enum because they carry
// richer structured state (package + failure kind + HRESULT + installer
// exit code); those go through _ShowWingetProblem instead, which uses
// FreWingetPackage + FreWingetFailureKind below.
enum class FreProblemKind
{
WingetMissing = 0, // hard prerequisite — winget itself unavailable
CopilotInstall = 1, // hard prerequisite — winget GitHub.Copilot
NodeInstall = 2, // hard prerequisite — winget OpenJS.NodeJS.LTS
ShellIntegrationExecutionPolicy = 3, // optional feature — error detection blocked by PowerShell execution policy
ShellIntegration = 4, // optional feature — error detection (generic install failure)
Hooks = 5, // optional feature — session management
ShellIntegrationExecutionPolicy = 1, // optional feature — error detection blocked by PowerShell execution policy
ShellIntegration = 2, // optional feature — error detection (generic install failure)
Hooks = 3, // optional feature — session management
};

// Which winget-installed prerequisite a failure refers to. Used by
// _ShowWingetProblem to pick the right package display name and
// manual-fix URL anchor.
enum class FreWingetPackage
{
Copilot = 0, // GitHub.Copilot
Node = 1, // OpenJS.NodeJS.LTS
};

// Categorization of why a winget install failed, derived from the COM
// API's structured status + HRESULT in _WingetInstallAsync. Each kind
// maps to a localized user-facing message that tells the user what
// happened and what to do next (retry, contact IT, install manually).
// The Success sentinel lets _WingetInstallAsync encode success/failure
// in a single IAsyncOperation<int32_t> return value (WinRT projection
// can't carry a richer struct without an IDL type).
enum class FreWingetFailureKind : int32_t
{
Success = -1, // install completed OK
Network = 0, // connect / download failed with a network-like HRESULT
BlockedByPolicy = 1, // winget GP / org policy blocked the install
PackageNotFound = 2, // catalog has no manifest with this ID
NoCompatibleInstaller = 3, // manifest exists but no installer matches this OS/arch
InstallerFailed = 4, // installer ran but reported an error (e.g. MSI 1603)
Timeout = 5, // we hit our own 20-min hard timeout
Generic = 6, // everything else (catalog corruption, internal error, unknown HRESULT, …)
};

// Show a single problem: set the error message + manual-fix link, then
// apply that problem's remediation (toggle off the affected feature, if
// any) and re-enable the Save button. Does not raise Completed.
void _ShowProblem(FreProblemKind kind);

// Show a winget install failure with package-aware, failure-kind-aware
// text. Picks the localized template by `kind`, substitutes the
// package display name and (for InstallerFailed / Generic) a
// pre-formatted error code string. Re-enables Save like _ShowProblem.
void _ShowWingetProblem(FreWingetPackage package,
FreWingetFailureKind kind,
int32_t hr,
uint32_t installerErrorCode);

// Shared tail end of _ShowProblem / _ShowWingetProblem after the
// caller has set ErrorText and computed the help URL: applies the
// URL to the help link, makes the panel visible, refreshes the
// agent dropdown, fires the Narrator notification, re-enables
// editing, and parks focus on the help link.
void _FinalizeProblemDisplay(const std::wstring& url);

// Apply the detection→suggestion master-detail dependency: detection
// off turns the suggestion toggle off and disables it; detection on
// re-enables it (preserving the stored value).
Expand All @@ -85,9 +134,60 @@ namespace winrt::TerminalApp::implementation
static bool _IsNodeInstalled();
static bool _IsWingetInstalled();

// Run a winget install synchronously on a background thread.
// Returns true on success.
static winrt::Windows::Foundation::IAsyncOperation<bool> _WingetInstallAsync(winrt::hstring packageId);
// ── WinGet source pre-warm coordination ─────────────────────
// While the FRE overlay is on screen (Welcome + Settings pages),
// pre-warm winget's source manifest cache in the background so
// the on-Save `winget install` skips the 3-20s source refresh.
// Single-flight per process — reentrant Initialize() calls and
// multi-window FRE coalesce onto one running prewarm. The Save
// handler awaits s_prewarmAction before its own winget call to
// guarantee the two winget operations never run concurrently
// (winget's intra-process locking is not a guaranteed contract).
static std::mutex s_prewarmMutex;
static winrt::Windows::Foundation::IAsyncAction s_prewarmAction;
Comment thread
haonanttt marked this conversation as resolved.

static void _MaybeStartPrewarm(bool copilotMissing, bool nodeMissing);
static winrt::Windows::Foundation::IAsyncAction _RunPrewarmAsync();

// Run a winget install asynchronously on a background thread.
// Returns FreWingetFailureKind cast to int32_t — Success (-1) on
// success, or one of the failure kinds otherwise. On failure, the
// associated HRESULT and installer exit code (if any) are stored in
// the _lastWinget* instance fields below for the caller to read.
//
// Per-instance state, not static: each FreOverlay window has its
// own _lastWinget* slot, so two FRE windows installing concurrently
// (multi-window scenario) can't clobber each other's diagnostics.
// Within one instance, the caller (_SaveAndInstallAsync) awaits
// Copilot before kicking off Node, so no intra-instance race either.
winrt::Windows::Foundation::IAsyncOperation<int32_t> _WingetInstallAsync(winrt::hstring packageId);

// Diagnostic state from the last _WingetInstallAsync call — read by
// the caller right after `co_await` to pass into _ShowWingetProblem.
// Both fields are reset to 0 by _WingetInstallAsync on each entry.
int32_t _lastWingetHr{ 0 };
uint32_t _lastWingetInstallerErrorCode{ 0 };

// Decide whether an HRESULT looks like a network-class failure
// (WinINet / WinHTTP / Winsock). Conservative whitelist of specific
// codes rather than facility-range scans, to avoid misclassifying
// HTTP-status HRESULTs (HTTP 404 is 0x80190194 — not a "check your
// VPN" situation) or RPC failures as network issues.
static bool _IsNetworkLikeHResult(int32_t hr) noexcept;

// Classify a raw HRESULT (from a winget COM exception or from
// InstallResult.ExtendedErrorCode) into the most-specific
// FreWingetFailureKind we can infer. Recognizes the winget-CLI's
// APPINSTALLER_CLI_ERROR_* family for policy blocks, missing
// packages, no-applicable-installer, and falls back to
// _IsNetworkLikeHResult, then Generic.
//
// Without this layer, winget COM exceptions like
// APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY (0x8A15003A — thrown
// when group policy disables winget) would map to a generic
// "(error code 0x8A15003A)" message instead of the actionable
// "blocked by policy — contact your IT admin" message.
static FreWingetFailureKind _ClassifyWingetHResult(int32_t hr) noexcept;

// Run wta.exe hooks install on a background thread.
// Returns true on success.
Expand Down
46 changes: 39 additions & 7 deletions src/cascadia/TerminalApp/Resources/af-ZA/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,49 @@
<data name="FreOverlay_SettingUp" xml:space="preserve">
<value>Word opgestel...</value>
</data>
<data name="FreOverlay_InstallErrorCopilot" xml:space="preserve">
<value>⚠ Kon nie GitHub Copilot installeer nie. Kontroleer jou netwerkverbinding en probeer weer.</value>
<comment>{Locked="GitHub Copilot"}</comment>
<data name="FreOverlay_InstallError_BlockedByPolicy" xml:space="preserve">
<value>⚠ Installering van {0} is deur 'n Windows-pakketbestuurderbeleid geblokkeer. As jy op 'n bestuurde toestel is, kontak jou IT-administrateur.</value>
<comment>FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallError_Generic" xml:space="preserve">
<value>⚠ Kon nie {0} installeer nie (foutkode {1}). Sien die logboek vir besonderhede, of installeer {0} handmatig.</value>
<comment>FRE setup error fallback. {0} is the package display name (appears twice). {1} is a pre-formatted HRESULT string.</comment>
</data>
<data name="FreOverlay_InstallError_GenericNoCode" xml:space="preserve">
<value>⚠ Kon nie {0} installeer nie. Sien die logboek vir besonderhede, of installeer {0} handmatig.</value>
<comment>FRE setup error fallback used when no actionable error code is available. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_InstallerFailed" xml:space="preserve">
<value>⚠ Die {0}-installeerder het ’n fout gerapporteer (kode {1}). Gaan die logboek na vir besonderhede, of installeer {0} handmatig.</value>
<comment>FRE setup error. {0} is the package display name (appears twice). {1} is decimal error code.</comment>
</data>
<data name="FreOverlay_InstallError_Network" xml:space="preserve">
<value>⚠ Kon nie die Windows-pakketbestuurder bereik terwyl {0} geïnstalleer is nie. Kontroleer jou internetverbinding (VPN, instaanbediener of brandmuur blokkeer dit dalk) en probeer weer.</value>
<comment>{Locked="VPN"} FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallError_NoCompatibleInstaller" xml:space="preserve">
<value>⚠ Geen versoenbare installeerder vir {0} is op hierdie stelsel beskikbaar nie (OS-weergawe of argitektuur word dalk nie ondersteun nie). Installeer {0} handmatig.</value>
<comment>FRE setup error. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_PackageNotFound" xml:space="preserve">
<value>⚠ {0} is nie in die Windows-pakketbestuurderkatalogus gevind nie. Probeer winget-bronne verfris, of installeer {0} handmatig.</value>
<comment>{Locked="winget"} FRE setup error. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_Timeout" xml:space="preserve">
<value>⚠ Installering van {0} het langer as 20 minute geneem. Intelligent Terminal het opgehou wag, maar die installeerder loop dalk nog in die agtergrond. Gaan Task Manager na, of probeer later weer.</value>
<comment>{Locked="Intelligent Terminal","Task Manager"} FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallErrorWingetMissing" xml:space="preserve">
<value>⚠ Windows-pakketbestuurder (winget) is nie geïnstalleer nie of is nie beskikbaar nie. Installeer dit eers en probeer dan weer.</value>
<comment>{Locked="winget","PATH"} Error shown in the FRE setup overlay when a prerequisite install was attempted but the winget command is not on PATH.</comment>
<comment>{Locked="winget"} Error shown in the FRE setup overlay when a prerequisite install was attempted but winget itself is not available on this system.</comment>
</data>
<data name="FreOverlay_PackageDisplayName_Copilot" xml:space="preserve">
<value>GitHub Copilot</value>
<comment>{Locked="GitHub Copilot"} Product display name substituted into the FreOverlay_InstallError_* templates when reporting a winget install failure for the Copilot CLI prerequisite.</comment>
</data>
<data name="FreOverlay_InstallErrorNode" xml:space="preserve">
<value>⚠ Kon nie Node.js installeer nie. Kontroleer jou netwerkverbinding en probeer weer.</value>
<comment>{Locked="Node.js"}</comment>
<data name="FreOverlay_PackageDisplayName_Node" xml:space="preserve">
<value>Node.js (LTS)</value>
<comment>{Locked="Node.js","LTS"} Product display name substituted into the FreOverlay_InstallError_* templates when reporting a winget install failure for the Node.js prerequisite.</comment>
</data>
<data name="FreOverlay_ToggleOn" xml:space="preserve">
<value>Aan</value>
Expand Down
46 changes: 39 additions & 7 deletions src/cascadia/TerminalApp/Resources/am-ET/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,49 @@
<data name="FreOverlay_SettingUp" xml:space="preserve">
<value>በማያቄር ላይ...</value>
</data>
<data name="FreOverlay_InstallErrorCopilot" xml:space="preserve">
<value>⚠ GitHub Copilot መጠቀም አልተሳካም። የመረብዎን ይፈትሩ እና እንደገና ይሞክሩ።</value>
<comment>{Locked="GitHub Copilot"}</comment>
<data name="FreOverlay_InstallError_BlockedByPolicy" xml:space="preserve">
<value>⚠ የ{0} ጭነት በWindows Package Manager ፖሊሲ ታግዷል። በሚተዳደር መሣሪያ ላይ ከሆኑ፣ የIT አስተዳዳሪዎን ያግኙ።</value>
<comment>FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallError_Generic" xml:space="preserve">
<value>⚠ {0}ን መጫን አልተቻለም (የስህተት ኮድ {1})። ለዝርዝሮች ሎጉን ይመልከቱ፣ ወይም {0}ን በእጅ ይጫኑ።</value>
<comment>FRE setup error fallback. {0} is the package display name (appears twice). {1} is a pre-formatted HRESULT string.</comment>
</data>
<data name="FreOverlay_InstallError_GenericNoCode" xml:space="preserve">
<value>⚠ {0}ን መጫን አልተቻለም። ለዝርዝሮች ሎጉን ይመልከቱ፣ ወይም {0}ን በእጅ ይጫኑ።</value>
<comment>FRE setup error fallback used when no actionable error code is available. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_InstallerFailed" xml:space="preserve">
<value>⚠ የ{0} ጫኚ ስህተት አሳውቋል (ኮድ {1})። ለዝርዝሮች ሎጉን ይመልከቱ፣ ወይም {0}ን በእጅ ይጫኑ።</value>
<comment>FRE setup error. {0} is the package display name (appears twice). {1} is decimal error code.</comment>
</data>
<data name="FreOverlay_InstallError_Network" xml:space="preserve">
<value>⚠ {0}ን በመጫን ላይ ሳለ Windows Package Managerን መድረስ አልተቻለም። የኢንተርኔት ግንኙነትዎን ይፈትሹ (VPN፣ ፕሮክሲ ወይም ፋየርዎል ሊከለክለው ይችላል) እና እንደገና ይሞክሩ።</value>
<comment>{Locked="VPN"} FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallError_NoCompatibleInstaller" xml:space="preserve">
<value>⚠ በዚህ ስርዓት ላይ ለ{0} ተኳኋኝ ጫኚ አይገኝም (የOS ስሪት ወይም አርክቴክቸር ላይደገፍ ይችላል)። {0}ን በእጅ ይጫኑ።</value>
<comment>FRE setup error. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_PackageNotFound" xml:space="preserve">
<value>⚠ {0} በWindows Package Manager ካታሎግ ውስጥ አልተገኘም። የwinget ምንጮችን ለማደስ ይሞክሩ፣ ወይም {0}ን በእጅ ይጫኑ።</value>
<comment>{Locked="winget"} FRE setup error. {0} is the package display name (appears twice).</comment>
</data>
<data name="FreOverlay_InstallError_Timeout" xml:space="preserve">
<value>⚠ {0}ን መጫን ከ20 ደቂቃ በላይ ወሰደ። Intelligent Terminal መጠበቁን አቁሟል፣ ግን ጫኚው አሁንም ከበስተጀርባ እየሰራ ሊሆን ይችላል። Task Managerን ይፈትሹ፣ ወይም በኋላ እንደገና ይሞክሩ።</value>
<comment>{Locked="Intelligent Terminal","Task Manager"} FRE setup error. {0} is the package display name.</comment>
</data>
<data name="FreOverlay_InstallErrorWingetMissing" xml:space="preserve">
<value>⚠ Windows Package Manager (winget) አልተጫነም ወይም አይገኝም። መጀመሪያ ይጫኑት፣ ከዚያ እንደገና ይሞክሩ።</value>
<comment>{Locked="winget","PATH"} Error shown in the FRE setup overlay when a prerequisite install was attempted but the winget command is not on PATH.</comment>
<comment>{Locked="winget"} Error shown in the FRE setup overlay when a prerequisite install was attempted but winget itself is not available on this system.</comment>
</data>
<data name="FreOverlay_PackageDisplayName_Copilot" xml:space="preserve">
<value>GitHub Copilot</value>
<comment>{Locked="GitHub Copilot"} Product display name substituted into the FreOverlay_InstallError_* templates when reporting a winget install failure for the Copilot CLI prerequisite.</comment>
</data>
<data name="FreOverlay_InstallErrorNode" xml:space="preserve">
<value>Node.js መጠቀም አልተሳካም። የመረብዎን ይፈትሩ እና እንደገና ይሞክሩ።</value>
<comment>{Locked="Node.js"}</comment>
<data name="FreOverlay_PackageDisplayName_Node" xml:space="preserve">
<value>Node.js (LTS)</value>
<comment>{Locked="Node.js","LTS"} Product display name substituted into the FreOverlay_InstallError_* templates when reporting a winget install failure for the Node.js prerequisite.</comment>
</data>
<data name="FreOverlay_ToggleOn" xml:space="preserve">
<value>እንቅ</value>
Expand Down
Loading
Loading