Compare commits

..

88 Commits

Author SHA1 Message Date
Leilei Zhang
5f056343df for demo 2025-10-24 11:12:09 +08:00
Leilei Zhang
dc00095173 Merge branch 'feature/advancedpaste' of https://github.com/microsoft/PowerToys into dev/demo 2025-10-23 10:06:48 +08:00
Gordon Lam (SH)
4b8ca7982e Fix dllmain compilation error by using relative path for AdvancedPasteModuleInterface.vcxproj 2025-10-23 10:00:34 +08:00
Leilei Zhang
5693e6f776 fix xmal style 2025-10-23 09:59:51 +08:00
Shawn Yuan
e126840d83 fix building issue
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-23 09:53:15 +08:00
Leilei Zhang
5b3699b17e Merge branch 'yuleng/imageResizer/pr/1' of https://github.com/microsoft/PowerToys into dev/demo 2025-10-23 09:48:09 +08:00
Leilei Zhang
f47317f056 Merge branch 'leilzh/mcp' of https://github.com/microsoft/PowerToys into dev/demo 2025-10-23 09:45:43 +08:00
Leilei Zhang
9bbc2fff49 update manifest 2025-10-22 21:53:51 +08:00
Niels Laute
4d90e0d7a8 Add local model tag in model selector 2025-10-22 14:38:11 +02:00
vanzue
b5f593ac44 Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-22 20:18:11 +08:00
vanzue
fcc0304f8a fix build 2025-10-22 20:17:51 +08:00
Shawn Yuan
eb65888421 Merge branch 'feature/advancedpaste' of https://github.com/microsoft/PowerToys into feature/advancedpaste 2025-10-22 20:17:37 +08:00
Shawn Yuan
8dc65d2bb3 add advanced AI
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-22 20:17:07 +08:00
Niels Laute
f85141c3ae Minor UX tweaks 2025-10-22 14:10:35 +02:00
vanzue
c1bbfa6035 Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-22 19:56:46 +08:00
Niels Laute
bcbacb6101 Settings UI tweaks 2025-10-22 13:25:56 +02:00
vanzue
0b108efccf is-local-model 2025-10-22 18:24:15 +08:00
Leilei Zhang
a2b4318540 add mcp 2025-10-22 17:57:09 +08:00
Niels Laute
f798e3ff7a Easier debugging + minor styling change 2025-10-22 11:51:10 +02:00
Niels Laute
a4548dd32f SelectionChanged instead of ItemClick 2025-10-22 11:34:53 +02:00
Leilei Zhang
603dfcaa90 update description 2025-10-22 17:02:18 +08:00
Leilei Zhang
8c3649b399 add new tool 2025-10-22 16:48:22 +08:00
vanzue
0e0a831b06 Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-22 15:44:37 +08:00
vanzue
5c95ceedc8 add a refresh button 2025-10-22 15:42:17 +08:00
Shawn Yuan
3541d1f6eb fix runtime issue
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-22 15:41:06 +08:00
vanzue
22f28c40a8 Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-22 15:19:46 +08:00
vanzue
567c63e81b remove check in settings 2025-10-22 15:19:38 +08:00
Shawn Yuan
860bb8cba2 Shawn/advanced paste (#42751)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-10-22 15:17:08 +08:00
Leilei Zhang
254927fec0 remove unused 2025-10-22 14:44:54 +08:00
vanzue
66f8d68a8a azure openai should be able to configure the advanced ai option 2025-10-22 14:42:09 +08:00
Leilei Zhang
f32b2534ce update 2025-10-22 14:36:21 +08:00
vanzue
cbc05b4cfc AP work 2025-10-22 14:06:52 +08:00
vanzue
cd06b73431 fix persist bug 2025-10-22 11:59:12 +08:00
vanzue
1c3b09d6a0 enable advanced AI toggle 2025-10-22 11:56:39 +08:00
vanzue
89864af06e fire&forget for foundry service start 2025-10-22 09:46:32 +08:00
vanzue
58e4a6c83c dev 2025-10-21 23:47:07 +08:00
vanzue
8eb9ef2c14 tune settings 2025-10-21 23:39:45 +08:00
vanzue
d89198d26e wire things up for adding a provider 2025-10-21 18:14:16 +08:00
Yu Leng (from Dev Box)
cceee12583 Fix spelling issue 2025-10-21 16:43:15 +08:00
Yu Leng (from Dev Box)
f56293763c merge main 2025-10-21 16:34:25 +08:00
Niels Laute
86e013df7e [Advanced Paste] Ading endpoint button with flyout (#42681)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-10-21 09:33:16 +08:00
Leilei Zhang
0243f57ea3 update 2025-10-21 00:54:15 +08:00
vanzue
00cd91344d Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-20 22:55:45 +08:00
vanzue
72a6057859 dev for new foundry local panel 2025-10-20 22:55:24 +08:00
Leilei Zhang
6d2b982181 update sparse app 2025-10-20 18:54:47 +08:00
Niels Laute
be07e97cf6 UI tweaks 2025-10-20 10:27:14 +02:00
Shawn Yuan (from Dev Box)
02a60bd098 fix extract and traslate chain issue
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-20 15:26:34 +08:00
Leilei Zhang (from Dev Box)
250f51fe9b add identity 2025-10-20 11:52:48 +08:00
Leilei Zhang (from Dev Box)
84d86b7b9d Merge branch 'main' of https://github.com/microsoft/PowerToys into leilzh/mcp 2025-10-20 09:31:44 +08:00
Leilei Zhang (from Dev Box)
b462b35a43 add mcp 2025-10-20 09:29:29 +08:00
Shawn Yuan
207f294e1e fix ui update issue
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-17 15:00:25 +08:00
Shawn Yuan
03f3206a44 Merge branch 'feature/advancedpaste' of https://github.com/microsoft/PowerToys into feature/advancedpaste 2025-10-17 13:47:53 +08:00
Shawn Yuan
5171b78eae Added terms and privacy policy.
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-17 13:45:06 +08:00
Kai Tao
f36e8747fd Dev/vanzue/foundry local (#42473)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-10-17 13:42:06 +08:00
Shawn Yuan
211cbc6438 add default system prompt to textBox in settings page.
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-10-17 11:56:04 +08:00
Shawn Yuan (from Dev Box)
0e30d2705c remove hugging face and local models
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-16 14:21:31 +08:00
Shawn Yuan (from Dev Box)
4ece86c4d1 legacy config migration
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-16 13:28:18 +08:00
Shawn Yuan (from Dev Box)
55d8e726a0 UI improvement
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-15 17:14:22 +08:00
Shawn Yuan (from Dev Box)
b3c1170040 added checkbox for openAI moderation config
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-15 12:55:23 +08:00
Shawn Yuan (from Dev Box)
ef1717c97f added ai provider icons
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-15 09:52:37 +08:00
Shawn Yuan (from Dev Box)
bfff31e657 remove model for advanced ai
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-14 11:22:33 +08:00
Shawn Yuan (from Dev Box)
b761f95ba3 added other models
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-14 10:30:04 +08:00
Yu Leng (from Dev Box)
1c73f0c518 init 2025-10-13 16:35:55 +08:00
Shawn Yuan (from Dev Box)
dda9cd8e18 fix restore issue
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-10-13 11:16:23 +08:00
Leilei Zhang (from Dev Box)
14282b9df1 Merge branch 'feature/advancedpaste' of https://github.com/microsoft/PowerToys into feature/advancedpaste 2025-10-11 10:31:29 +08:00
Leilei Zhang (from Dev Box)
81a6e3bfdc update paste AI logic 2025-10-11 10:30:58 +08:00
Kai Tao
06279a2102 Merge branch 'feature/advancedpaste' of github.com:microsoft/PowerToys into feature/advancedpaste 2025-10-11 09:43:32 +08:00
Kai Tao
6fb3ee5e3a foundry stuff 2025-10-11 09:42:32 +08:00
Niels Laute
4df18234a7 More UX tweaks, adding list items for Foundry Local / Windows ML 2025-10-10 12:17:46 +02:00
Niels Laute
571cb3cb22 Cleaning up AP actions UX 2025-10-10 11:17:02 +02:00
Leilei Zhang (from Dev Box)
9c76d8a667 update AdvancedAI Logic 2025-10-09 22:55:48 +08:00
Niels Laute
e8cbb1bd66 Moving provider configs 2025-10-08 21:23:13 +02:00
Niels Laute
5734afcf89 Merge branch 'main' into feature/advancedpaste 2025-10-08 11:39:40 +02:00
Leilei Zhang (from Dev Box)
c63b29a777 Add support for multiple LLMs 2025-09-30 20:01:55 +08:00
Shawn Yuan (from Dev Box)
4309006a92 Merge branch 'main' into feature/advancedpaste 2025-09-29 09:09:28 +08:00
Leilei Zhang (from Dev Box)
d24a1d99ad add paste ai provider 2025-09-28 13:18:19 +08:00
Leilei Zhang
439023af68 Merge branch 'main' of https://github.com/microsoft/PowerToys into shawn/upgradeSemanticKernel 2025-09-23 12:23:43 +08:00
Shuai Yuan
4e5a2db985 Init and added simple ui change.
Signed-off-by: Shuai Yuan <shuai.yuan.zju@gmail.com>
2025-09-22 16:36:43 +08:00
Leilei Zhang
8a7c944ec9 Merge branch 'shawn/upgradeSemanticKernel' of https://github.com/shuaiyuanxx/PowerToys into shawn/upgradeSemanticKernel 2025-09-09 14:48:48 +08:00
Leilei Zhang
49cfcb1349 add custom actions to kernal function 2025-09-09 14:48:36 +08:00
Shawn Yuan
320b7eca7c update modele name
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-09 14:16:13 +08:00
Shawn Yuan
d60923bc9a update model
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-09 14:06:42 +08:00
Shawn Yuan
a5097c7525 remove unused files
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-09 10:54:31 +08:00
Shawn Yuan
7ccbef0298 migrate chat complection to semantic kernel
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-09 10:51:37 +08:00
Shawn Yuan
665d7ca535 update functional call settings
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-08 14:54:32 +08:00
Shawn Yuan
debbc72825 update nuget.config
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-08 13:58:10 +08:00
Shawn Yuan
46a4e32fb6 update code
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-08 11:12:53 +08:00
Shawn Yuan
c832862b9a upgrade pkg version
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-09-08 10:46:28 +08:00
379 changed files with 6128 additions and 13388 deletions

View File

@@ -7,13 +7,6 @@ body:
- type: markdown
attributes:
value: Please make sure to [search for existing issues](https://github.com/microsoft/PowerToys/issues) before filing a new one!
- type: markdown
attributes:
value: |
We are aware of the following high-volume issues and are actively working on them. Please check if your issue is one of these before filing a new bug report:
* **PowerToys Run crash related to "Desktop composition is disabled"**: This may appear as `COMException: 0x80263001`. For more details, see issue [#31226](https://github.com/microsoft/PowerToys/issues/31226).
* **PowerToys Run crash with `COMException (0xD0000701)`**: For more details, see issue [#30769](https://github.com/microsoft/PowerToys/issues/30769).
* **PowerToys Run crash with a "Cyclic reference" error**: This `System.InvalidOperationException` is detailed in issue [#36451](https://github.com/microsoft/PowerToys/issues/36451).
- id: version
type: input
attributes:

View File

@@ -321,10 +321,3 @@ REGSTR
# Misc Win32 APIs and PInvokes
INVOKEIDLIST
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
DDDD
FFF
HHH
riday
YYY

View File

@@ -22,7 +22,6 @@ ADate
ADDSTRING
ADDUNDORECORD
ADifferent
adjacents
ADMINS
adml
admx
@@ -35,7 +34,6 @@ AFX
AGGREGATABLE
AHK
AHybrid
AIUI
akv
ALarger
ALIGNRIGHT
@@ -47,7 +45,6 @@ Allmodule
ALLOWUNDO
ALLVIEW
ALPHATYPE
amazonbedrock
AModifier
amr
ANDSCANS
@@ -97,10 +94,8 @@ ASSOCSTR
ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
atl
ATX
ATRIOX
aumid
authenticode
Authenticode
AUTOBUDDY
AUTOCHECKBOX
@@ -115,13 +110,9 @@ AValid
AWAYMODE
azcliversion
azman
azureaiinference
azureinference
azureopenai
bbwe
BCIE
bck
backticks
BESTEFFORT
bezelled
bhid
@@ -149,7 +140,6 @@ bmi
BNumber
BODGY
BOklab
Bootstrappers
BOOTSTRAPPERINSTALLFOLDER
BOTTOMALIGN
boxmodel
@@ -177,12 +167,9 @@ BYPOSITION
CALCRECT
CALG
callbackptr
cabstr
calpwstr
caub
Cangjie
CANRENAME
Carlseibert
Canvascustomlayout
CAPTUREBLT
CAPTURECHANGED
@@ -210,7 +197,6 @@ CIBUILD
cidl
CIELCh
cim
claude
CImage
cla
CLASSDC
@@ -243,7 +229,6 @@ CODENAME
codereview
Codespaces
Coen
cognitiveservices
COINIT
colid
colorconv
@@ -258,7 +243,6 @@ cominterop
commandnotfound
commandpalette
compmgmt
COMPOSITIONDISABLED
COMPOSITIONFULL
CONFIGW
CONFLICTINGMODIFIERKEY
@@ -284,14 +268,12 @@ countof
covrun
cpcontrols
cph
cppcoreguidelines
cplusplus
CPower
cpptools
cppvsdbg
cppwinrt
createdump
creativecommons
CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
@@ -315,8 +297,6 @@ CURRENTDIR
CURSORINFO
cursorpos
CURSORSHOWING
CURSORWRAP
CursorWrap
customaction
CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER
@@ -356,7 +336,6 @@ Deact
debugbreak
decryptor
Dedup
dfx
Deduplicator
Deeplink
DEFAULTBOOTSTRAPPERINSTALLFOLDER
@@ -431,7 +410,6 @@ DROPFILES
DSTINVERT
DString
DSVG
dto
DTo
DUMMYUNIONNAME
dutil
@@ -531,12 +509,10 @@ EXTRINSICPROPERTIES
eyetracker
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
FNumber
FARPROC
fdx
fesf
FFFF
Figma
FILEEXPLORER
fileexploreraddons
fileexplorerpreview
@@ -563,7 +539,6 @@ FIXEDSYS
flac
flyouts
FMask
foundrylocal
fmtid
FOF
FOFX
@@ -628,8 +603,6 @@ GValue
gwl
GWLP
GWLSTYLE
googleai
googlegemini
hangeul
Hanzi
Hardlines
@@ -692,7 +665,6 @@ hmonitor
homies
homljgmgpmcbpjbnjpfijnhipfkiclkd
HOOKPROC
huggingface
HORZRES
HORZSIZE
Hostbackdropbrush
@@ -719,7 +691,6 @@ HTCLIENT
hthumbnail
HTOUCHINPUT
HTTRANSPARENT
hutchinsoniana
HVal
HValue
Hvci
@@ -741,9 +712,7 @@ IDCANCEL
IDD
idk
idl
IIM
idlist
ifd
IDOK
IDOn
IDR
@@ -760,7 +729,6 @@ Ijwhost
ILD
IMAGEHLP
IMAGERESIZERCONTEXTMENU
IPTC
IMAGERESIZEREXT
imageresizerinput
imageresizersettings
@@ -779,7 +747,7 @@ INITDIALOG
INITGUID
INITTOLOGFONTSTRUCT
INLINEPREFIX
inlines
Inlines
INPC
inproc
INPUTHARDWARE
@@ -900,7 +868,6 @@ LOCKTYPE
LOGFONT
LOGFONTW
logon
lon
LOGMSG
LOGPIXELSX
LOGPIXELSY
@@ -980,6 +947,7 @@ maxversiontested
mber
MBM
MBR
mcp
MDICHILD
MDL
mdtext
@@ -992,7 +960,6 @@ MENUITEMINFOW
MERGECOPY
MERGEPAINT
Metadatas
metadatamatters
metafile
mfc
Mgmt
@@ -1060,7 +1027,6 @@ msiexec
MSIFASTINSTALL
MSIHANDLE
MSIRESTARTMANAGERCONTROL
MSIs
msixbundle
MSIXCA
MSLLHOOKSTRUCT
@@ -1152,11 +1118,9 @@ NONCLIENTMETRICSW
NONELEVATED
nonspace
nonstd
nullrefs
NOOWNERZORDER
NOPARENTNOTIFY
NOPREFIX
NPU
NOREDIRECTIONBITMAP
NOREDRAW
NOREMOVE
@@ -1216,9 +1180,6 @@ opencode
OPENFILENAME
opensource
openxmlformats
ollama
Olllama
onnx
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
ORSCANS
@@ -1313,7 +1274,6 @@ pnid
PNMLINK
Poc
Podcasts
Photoshop
POINTERID
POINTERUPDATE
Pokedex
@@ -1408,8 +1368,6 @@ pwsz
pwtd
QDC
qit
QNN
Qualcomm
QITAB
QITABENT
qoi
@@ -1518,7 +1476,6 @@ sacl
safeprojectname
SAMEKEYPREVIOUSLYMAPPED
SAMESHORTCUTPREVIOUSLYMAPPED
samsung
sancov
SAVEFAILED
scanled
@@ -1881,7 +1838,6 @@ USEINSTALLERFORTEST
USESHOWWINDOW
USESTDHANDLES
USRDLL
utm
UType
uuidv
uwp
@@ -1958,7 +1914,6 @@ wcsicmp
wcsncpy
wcsnicmp
WCT
WCRAPI
WDA
wdm
wdp
@@ -1972,7 +1927,6 @@ wgpocpl
WHEREID
wic
wifi
wikimedia
wikipedia
WIL
winapi
@@ -2002,8 +1956,6 @@ WINL
winlogon
winmd
WINNT
windowsml
winml
winres
winrt
winsdk
@@ -2069,9 +2021,7 @@ XAxis
XButton
xclip
xcopy
xap
XDeployment
XDimension
xdf
XDocument
XElement
@@ -2089,7 +2039,6 @@ xsi
XSpeed
XStr
xstyler
xmp
XTimer
XUP
XVIRTUALSCREEN
@@ -2097,7 +2046,6 @@ xxxxxx
YAxis
ycombinator
YIncrement
YDimension
yinle
yinyue
YPels

View File

@@ -1,59 +1,43 @@
---
description: PowerToys AI contributor guidance.
applyTo: pullRequests
---
# PowerToys - Copilot guide (concise)
# PowerToys Copilot guide (concise)
This is the top-level guide for AI changes. Keep edits small, follow existing patterns, and cite exact paths in PRs.
# Repo map (1-line per area)
Repo map (1line per area)
- Core apps: `src/runner/**` (tray/loader), `src/settings-ui/**` (Settings app)
- Shared libs: `src/common/**`
- Modules: `src/modules/*` (one per utility; Command Palette in `src/modules/cmdpal/**`)
- Build tools/docs: `tools/**`, `doc/devdocs/**`
# Build and test (defaults)
Build and test (defaults)
- Prerequisites: Visual Studio 2022 17.4+, minimal Windows 10 1803+.
- Build discipline:
- One terminal per operation (build -> test). Do not switch or open new ones mid-flow.
- One terminal per operation (build test). Dont switch/open new ones mid-flow.
- After making changes, `cd` to the project folder that changed (`.csproj`/`.vcxproj`).
- Use scripts to build, synchronously block and wait in foreground for completion: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages).
- Treat build exit code 0 as success; any non-zero exit code is a failure. Read the errors log in the build folder (such as `build.*.*.errors.log`) and surface problems.
- Do not start tests or launch Runner until the previous step succeeded.
- Tests (fast and targeted):
- Find the test project by product code prefix (for example FancyZones, AdvancedPaste). Look for a sibling folder or one to two levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
- Build the test project, wait for exit, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
- Add or adjust tests when changing behavior; if skipped, state why (for example comment-only or string rename).
- Use script(s) to build, synchronously block and wait in foreground for it to finish: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages)
- Treat build **exit code 0** as success; any non-zero exit code is a failure, have Copilot read the errors log in the build folder (e.g., `build.*.*.errors.log`) and surface problems.
- Dont start tests or launch Runner until the previous step succeeded.
- Tests (fast + targeted):
- Find the test project by product code prefix (e.g., FancyZones, AdvancedPaste). Look for a sibling folder or 12 levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
- Build the test project, wait for **exit**, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
- Add/adjust tests when changing behavior; if skipped, state why (e.g., comment-only, string rename).
# Pull requests (expectations)
- Atomic: one logical change; no drive-by refactors.
- Describe: problem, approach, risk, test evidence.
Pull requests (expectations)
- Atomic: one logical change; no driveby refactors.
- Describe: problem / approach / risk / test evidence.
- List: touched paths if not obvious.
# When to ask for clarification
When to ask for clarification
- Ambiguous spec after scanning relevant docs (see below).
- Cross-module impact (shared enum or struct) not clear.
- Security, elevation, or installer changes.
- Cross-module impact (shared enum/struct) not clear.
- Security / elevation / installer changes.
# Logging (use existing stacks)
- C++ logging lives in `src/common/logger/**` (`Logger::info`, `Logger::warn`, `Logger::error`, `Logger::debug`). Keep hot paths quiet (hooks, tight loops).
- C# logging goes through `ManagedCommon.Logger` (`LogInfo`, `LogWarning`, `LogError`, `LogDebug`, `LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
Logging (use existing stacks)
- C++: `src/common/logger/**` (`Logger::info|warn|error|debug`). Keep hot paths quiet (hooks, tight loops).
- C#: `ManagedCommon.Logger` (`LogInfo|LogWarning|LogError|LogDebug|LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
# Docs to consult
Docs to consult
- `tools/build/BUILD-GUIDELINES.md`
- `doc/devdocs/core/architecture.md`
- `doc/devdocs/core/runner.md`
- `doc/devdocs/core/settings/readme.md`
- `doc/devdocs/modules/readme.md`
- `doc/devdocs/core/architecture.md`, `doc/devdocs/core/runner.md`, `doc/devdocs/core/settings/readme.md`, `doc/devdocs/modules/readme.md`
# Language style rules
- Always enforce repo analyzers: root `.editorconfig` plus any `stylecop.json`.
- C# code follows StyleCop.Analyzers and Microsoft.CodeAnalysis.NetAnalyzers.
- C++ code honors `.clang-format` plus `.clang-tidy` (modernize/cppcoreguidelines/readability).
- Markdown files wrap at 80 characters and use ATX headers with fenced code blocks that include language tags.
- YAML files indent two spaces and add comments for complex settings while keeping keys clear.
- PowerShell scripts use Verb-Noun names and prefer single-quoted literals while documenting parameters and satisfying PSScriptAnalyzer.
# Done checklist (self review before finishing)
- Build clean? Tests updated or passed? No unintended formatting? Any new dependency? Documented skips?
Done checklist (self review before finishing)
- Build clean? Tests updated/passed? No unintended formatting? Any new dependency? Documented skips?

View File

@@ -1,16 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate an 80-character git commit title for the local diff.'
---
**Goal:** Provide a ready-to-paste git commit title (<= 80 characters) that captures the most important local changes since `HEAD`.
**Workflow:**
1. Run a single command to view the local diff since the last commit:
```@terminal
git diff HEAD
```
2. From that diff, identify the dominant area (reference key paths like `src/modules/*`, `doc/devdocs/**`, etc.), the type of change (bug fix, docs update, config tweak), and any notable impact.
3. Draft a concise, imperative commit title summarizing the dominant change. Keep it plain ASCII, <= 80 characters, and avoid trailing punctuation. Mention the primary component when obvious (for example `FancyZones:` or `Docs:`).
4. Respond with only the final commit title on a single line so it can be pasted directly into `git commit`.

View File

@@ -1,22 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate a PowerToys-ready pull request description from the local diff.'
---
**Goal:** Produce a ready-to-paste PR title and description that follows PowerToys conventions by comparing the current branch against a user-selected target branch.
**Repo guardrails:**
- Treat `.github/pull_request_template.md` as the single source of truth; load it at runtime instead of embedding hardcoded content in this prompt.
- Preserve section order from the template but only surface checklist lines that are relevant for the detected changes, filling them with `[x]`/`[ ]` as appropriate.
- Cite touched paths with inline backticks, matching the guidance in `.github/copilot-instructions.md`.
- Call out test coverage explicitly: list automated tests run (unit/UI) or state why they are not applicable.
**Workflow:**
1. Determine the target branch from user context; default to `main` when no branch is supplied.
2. Run `git status --short` once to surface uncommitted files that may influence the summary.
3. Run `git diff <target-branch>...HEAD` a single time to review the detailed changes. Only when confidence stays low dig deeper with focused calls such as `git diff <target-branch>...HEAD -- <path>`.
4. From the diff, capture impacted areas, key file changes, behavioral risks, migrations, and noteworthy edge cases.
5. Confirm validation: list tests executed with results or state why tests were skipped in line with repo guidance.
6. Load `.github/pull_request_template.md`, mirror its section order, and populate it with the gathered facts. Include only relevant checklist entries, marking them `[x]/[ ]` and noting any intentional omissions as "N/A".
7. Present the filled template inside a fenced ```markdown code block with no extra commentary so it is ready to paste into a PR, clearly flagging any placeholders that still need user input.

View File

@@ -1,22 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Resolve Code scanning / check-spelling comments on the active PR.'
---
**Goal:** Clear every outstanding GitHub pull request comment created by the `Code scanning / check-spelling` workflow by explicitly allowing intentional terms.
**Guardrails:**
- Update only discussion threads authored by `github-actions` or `github-actions[bot]` that mention `Code scanning results / check-spelling`.
- Resolve findings solely by editing `.github/actions/spell-check/expect.txt`; reuse existing entries.
- Leave all other files and topics untouched.
**Prerequisites:**
- Install GitHub CLI if it is not present: `winget install GitHub.cli`.
- Run `gh auth login` once before the first CLI use.
**Workflow:**
1. Determine the active pull request with a single `gh pr view --json number` call (default to the current branch).
2. Fetch all PR discussion data once via `gh pr view --json comments,reviews` and filter to check-spelling comments authored by `github-actions` or `github-actions[bot]` that are not minimized; when several remain, process only the most recent comment body.
3. For each flagged token, review `.github/actions/spell-check/expect.txt` for an equivalent term (for example an existing lowercase variant); when found, reuse that normalized term rather than adding a new entry, even if the flagged token differs only by casing. Only add a new entry after confirming no equivalent already exists.
4. Add any remaining missing token to `.github/actions/spell-check/expect.txt`, keeping surrounding formatting intact.

3
.gitignore vendored
View File

@@ -349,7 +349,10 @@ src/common/Telemetry/*.etl
/src/modules/powerrename/ui/RCb24464
# Generated installer file for Monaco source files.
/installer/PowerToysSetup/MonacoSRC.wxs
/installer/PowerToysSetup/DscResources.wxs
/installer/PowerToysSetupVNext/MonacoSRC.wxs
/installer/PowerToysSetupVNext/DscResources.wxs
# MSBuildCache
/MSBuildCacheLogs/

View File

@@ -5,6 +5,7 @@
{
"MatchedPath": [
"*.resources.dll",
"WinUI3Apps\\Assets\\Settings\\Scripts\\*.ps1",
"PowerToys.ActionRunner.exe",
@@ -26,7 +27,6 @@
"PowerToys.GPOWrapper.dll",
"PowerToys.GPOWrapperProjection.dll",
"PowerToys.AllExperiments.dll",
"LanguageModelProvider.dll",
"Common.Search.dll",
@@ -181,7 +181,6 @@
"PowerToys.MousePointerCrosshairs.dll",
"PowerToys.MouseJumpUI.dll",
"PowerToys.MouseJumpUI.exe",
"PowerToys.CursorWrap.dll",
"PowerToys.MouseWithoutBorders.dll",
"PowerToys.MouseWithoutBorders.exe",
@@ -238,7 +237,9 @@
"PowerToys.DSC.dll",
"PowerToys.DSC.exe",
"PowerToysSparse.msix"
"PowerToysSparse.msix",
"PowerToys.McpServer.dll",
"PowerToys.McpServer.exe"
],
"SigningInfo": {
"Operations": [
@@ -347,8 +348,6 @@
"Testably.Abstractions.FileSystem.Interface.dll",
"WinUI3Apps\\Testably.Abstractions.FileSystem.Interface.dll",
"ColorCode.Core.dll",
"Microsoft.SemanticKernel.Connectors.Ollama.dll",
"OllamaSharp.dll",
"UnitsNet.dll",
"UtfUnknown.dll",

View File

@@ -0,0 +1,53 @@
{
"Version": "1.0.0",
"UseMinimatch": false,
"SignBatches": [
{
"MatchedPath": [
"PowerToysSetupCustomActionsVNext.dll",
"SilentFilesInUseBAFunction.dll",
"PowerToys*Setup-*.exe",
"PowerToys*Setup-*.msi"
],
"SigningInfo": {
"Operations": [
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolSign",
"Parameters": [
{
"parameterName": "OpusName",
"parameterValue": "Microsoft"
},
{
"parameterName": "OpusInfo",
"parameterValue": "http://www.microsoft.com"
},
{
"parameterName": "FileDigest",
"parameterValue": "/fd \"SHA256\""
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
}
],
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolVerify",
"Parameters": [],
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
}
}
]
}

View File

@@ -65,28 +65,21 @@ if (-not (Test-Path $outputDir)) {
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
}
# DSC v3 manifests go to DSCModules subfolder
$dscOutputDir = Join-Path $outputDir 'DSCModules'
if (-not (Test-Path $dscOutputDir)) {
Write-Host "Creating DSCModules subfolder at '$dscOutputDir'."
New-Item -Path $dscOutputDir -ItemType Directory -Force | Out-Null
}
Write-Host "DSC manifests will be generated to: '$outputDir'"
Write-Host "DSC manifests will be generated to: '$dscOutputDir'"
Write-Host "Cleaning previously generated DSC manifest files from '$outputDir'."
Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
Write-Host "Cleaning previously generated DSC manifest files from '$dscOutputDir'."
Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $dscOutputDir)
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $outputDir)
Write-Host "Invoking DSC manifest generator: '$exePath' $($arguments -join ' ')"
& $exePath @arguments
if ($LASTEXITCODE -ne 0) {
throw "PowerToys.DSC.exe exited with code $LASTEXITCODE"
}
$generatedFiles = Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
$generatedFiles = Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
if ($generatedFiles.Count -eq 0) {
throw "No DSC manifest files were generated in '$dscOutputDir'."
throw "No DSC manifest files were generated in '$outputDir'."
}
Write-Host "Generated $($generatedFiles.Count) DSC manifest file(s):"

View File

@@ -32,7 +32,7 @@ parameters:
- name: enableMsBuildCaching
type: boolean
displayName: "Enable MSBuild Caching"
default: false
default: true
- name: runTests
type: boolean
displayName: "Run Tests"

View File

@@ -73,11 +73,10 @@ extends:
parameters:
pool:
name: SHINE-INT-L
demands:
# Our INT agents have a large disk mounted at P:\
- WorkFolder -equals P:\_work
- ${{ if eq(parameters.useVSPreview, true) }}:
- ImageOverride -equals SHINE-VS17-Preview
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
${{ else }}:
image: SHINE-VS17-Latest
os: windows
variables:
IsPipeline: 1 # The installer uses this to detect whether it should pick up localizations

View File

@@ -266,26 +266,6 @@ jobs:
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: VSBuild@1
displayName: Generate DSC artifacts for ARM64
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs:
solution: PowerToys.sln
vsVersion: 17.0
msbuildArgs: >-
-restore
/p:Configuration=$(BuildConfiguration)
/p:Platform=x64
/t:DSC\PowerToys_Settings_DSC_Schema_Generator
/bl:$(LogOutputDirectory)\build-dsc-generator.binlog
${{ parameters.additionalBuildOptions }}
$(MSBuildCacheParameters)
$(RestoreAdditionalProjectSourcesArg)
platform: x64
configuration: $(BuildConfiguration)
msbuildArchitecture: x64
maximumCpuCount: true
# Build PowerToys.DSC.exe for ARM64 (x64 uses existing binary from previous build)
- task: VSBuild@1
displayName: Build PowerToys.DSC.exe (x64 for generating manifests)
@@ -532,6 +512,14 @@ jobs:
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
- template: steps-build-installer-vnext.yml
parameters:
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
buildUserInstaller: true # NOTE: This is the distinction between the above and below rules
# This saves ~1GiB per architecture. We won't need these later.
# Removes:
# - All .pdb files from any static libs .libs (which were only used during linking)

View File

@@ -2,6 +2,9 @@ parameters:
- name: versionNumber
type: string
default: "0.0.1"
- name: buildUserInstaller
type: boolean
default: false
- name: codeSign
type: boolean
default: false
@@ -22,26 +25,43 @@ steps:
arguments: 'install --global wix --version 5.0.2'
- pwsh: |-
Write-Host "##vso[task.setvariable variable=InstallerMachineRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\MachineSetup"
Write-Host "##vso[task.setvariable variable=InstallerUserRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\UserSetup"
Write-Host "##vso[task.setvariable variable=InstallerMachineBasename]PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
Write-Host "##vso[task.setvariable variable=InstallerUserBasename]PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
displayName: Prepare Installer variables
& git clean -xfd -e *exe -- .\installer\
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Clean installer to reduce cross-contamination
- pwsh: |-
# Determine whether this is a per-user build
$IsPerUser = $${{ parameters.buildUserInstaller }}
# Build slug used to locate the artifacts
$InstallerBuildSlug = if ($IsPerUser) { 'UserSetup' } else { 'MachineSetup' }
# VNext bundle folder; base name intentionally omits the VNext suffix
$InstallerFolder = 'PowerToysSetupVNext'
if ($IsPerUser) {
$InstallerBasename = "PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
else {
$InstallerBasename = "PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
# Export variables for downstream steps
Write-Host "##vso[task.setvariable variable=InstallerBuildSlug]$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerRelativePath]$(BuildPlatform)\$(BuildConfiguration)\$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerBasename]$InstallerBasename"
Write-Host "##vso[task.setvariable variable=InstallerFolder]$InstallerFolder"
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Prepare Installer variables
# This dll needs to be built and signed before building the MSI.
# The Custom Actions project contains a pre-build event that prepares the .wxs files
# by filling them out with all our components. We pass RunBuildEvents=true to force
# that logic to run.
- task: VSBuild@1
displayName: Build Shared Support DLLs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build PowerToysSetupCustomActionsVNext
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
/p:RunBuildEvents=true;RestorePackagesConfig=true;CIBuild=true
/t:PowerToysSetupCustomActionsVNext
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-actions.binlog
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-actions.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -50,53 +70,28 @@ steps:
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign Shared Support DLLs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign PowerToysSetupCustomActionsVNext
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: |-
**/PowerToysSetupCustomActionsVNext.dll
**/SilentFilesInUseBAFunction.dll
inputs:
FolderPath: 'installer/PowerToysSetupCustomActionsVNext/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
## INSTALLER START
#### MSI BUILDING AND SIGNING
#
# The MSI build contains code that reverts the .wxs files to their in-tree versions.
# This is only supposed to happen during local builds. Since this build system is
# supposed to run side by side--machine and then user--we do NOT want to destroy
# the .wxs files. Therefore, we pass RunBuildEvents=false to suppress all of that
# logic.
#
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
- task: VSBuild@1
displayName: 💻 Build VNext MSI
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the CustomActions dll
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-msi.binlog
/p:RunBuildEvents=false;PerUser=${{parameters.buildUserInstaller}};BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -105,66 +100,77 @@ steps:
maximumCpuCount: true
- script: |-
wix msi decompile $(InstallerMachineRoot)\$(InstallerMachineBasename).msi -x $(build.sourcesdirectory)\extractedMachineMsi
wix msi decompile $(InstallerUserRoot)\$(InstallerUserBasename).msi -x $(build.sourcesdirectory)\extractedUserMsi
dir $(build.sourcesdirectory)\extractedMachineMsi
dir $(build.sourcesdirectory)\extractedUserMsi
displayName: "WiX5: Extract and verify MSIs"
wix msi decompile installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).msi -x $(build.sourcesdirectory)\extractedMsi
dir $(build.sourcesdirectory)\extractedMsi
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract and verify MSI"
# Check if deps.json files don't reference different dll versions.
- pwsh: |-
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
displayName: Audit deps.json in MSI extracted files
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Audit deps.json in MSI extracted files
- ${{ if eq(parameters.codeSign, true) }}:
- pwsh: |-
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\Binary'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\Binary'
git clean -xfd ./extractedMachineMsi ./extractedUserMsi
displayName: Verify all binaries are signed and versioned
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\Binary'
git clean -xfd ./extractedMsi
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Verify all binaries are signed and versioned
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign VNext MSIs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign VNext MSI
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: '**/PowerToys*Setup-*.msi'
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END MSI
#### BOOTSTRAP BUILDING AND SIGNING
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
#### BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
- task: VSBuild@1
displayName: 💻 Build VNext Bootstrapper
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build SilentFilesInUseBAFunction
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:SilentFilesInUseBAFunction
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-SilentFilesInUseBAFunction.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the msi
msbuildArchitecture: x64
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign SilentFilesInUseBAFunction
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/$(BuildPlatform)/$(BuildConfiguration)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
#### BOOTSTRAP BUILDING AND SIGNING
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysBootstrapperVNext
/p:PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-bootstrapper.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysBootstrapperVNext
/p:PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-bootstrapper.binlog
/p:PerUser=${{parameters.buildUserInstaller}};CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-bootstrapper.binlog
-restore -graph
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -175,41 +181,54 @@ steps:
# The entirety of bundle unpacking/re-packing is unnecessary if we are not code signing it.
- ${{ if eq(parameters.codeSign, true) }}:
- script: |-
wix burn detach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe
wix burn detach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe
displayName: "WiX5: Extract Engines from Bundles"
wix burn detach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract Engine from Bundle"
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign WiX Engines
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign WiX Engine
signingIdentity: ${{ parameters.signingIdentity }}
folder: "installer"
pattern: '*-engine.exe'
inputs:
FolderPath: "installer"
Pattern: engine.exe
signConfigType: inlineSignParams
inlineOperation: |
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
- script: |-
wix burn reattach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe -o $(InstallerMachineRoot)\$(InstallerMachineBasename).exe
wix burn reattach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe -o $(InstallerUserRoot)\$(InstallerUserBasename).exe
displayName: "WiX5: Reattach Engines to Bundles"
wix burn reattach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe -o installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Reattach Engine to Bundle"
- pwsh: |-
& wix burn extract -oba installer\ba\m "$(InstallerMachineRoot)\$(InstallerMachineBasename).exe"
& wix burn extract -oba installer\ba\u "$(InstallerUserRoot)\$(InstallerUserBasename).exe"
Get-ChildItem installer\ba -Recurse -Include *.exe,*.dll | Get-AuthenticodeSignature | ForEach-Object {
If ($_.Status -Ne "Valid") {
Write-Error $_.StatusMessage
} Else {
Write-Host $_.StatusMessage
}
}
& git clean -fdx installer\ba
displayName: "WiX5: Verify Bootstrapper content is signed"
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign Final Bootstrappers
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign Final Bootstrapper
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: '**/PowerToys*Setup-*.exe'
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END BOOTSTRAP
## END INSTALLER

View File

@@ -1,45 +0,0 @@
parameters:
- name: displayName
type: string
default: Sign Specific Files
- name: folder
type: string
- name: pattern
type: string
- name: signingIdentity
type: object
default: {}
steps:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{ parameters.displayName }}
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: ${{ parameters.folder }}
Pattern: ${{ parameters.pattern }}
UseMinimatch: true
signConfigType: inlineSignParams
inlineOperation: |-
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]

13
.vscode/launch.json vendored
View File

@@ -38,17 +38,6 @@
"env": {},
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Run AdvancedPaste (managed, no build, ARCH configurable)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}\\${input:arch}\\Debug\\WinUI3Apps\\PowerToys.AdvancedPaste.exe",
"args": [],
"cwd": "${workspaceFolder}",
"env": {},
"console": "internalConsole",
"stopAtEntry": false
},
}
]
}

View File

@@ -1,56 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Hybrid CRT configuration -->
<PropertyGroup Condition="'$(HybridCrtConfiguration)'==''">
<HybridCrtConfiguration>$(Configuration)</HybridCrtConfiguration>
</PropertyGroup>
<!-- Skip Hybrid CRT for AppContainer/UWP projects as they require MultiThreadedDLL -->
<PropertyGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop'">
<HybridCrtConfiguration></HybridCrtConfiguration>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(HybridCrtConfiguration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(HybridCrtConfiguration)'=='Release'">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- AppContainer/UWP projects must use MultiThreadedDLL -->
<ItemDefinitionGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop' And '$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(AppContainerApplication)'=='true' and '$(_VC_Target_Library_Platform)'!='Desktop' And '$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<!-- Project configurations -->
<ItemGroup Label="ProjectConfigurations">
@@ -123,6 +73,7 @@
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -132,6 +83,7 @@
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>

View File

@@ -34,21 +34,18 @@
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageVersion Include="MessagePack" Version="3.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.240111.5" />
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.1-preview.1.25474.6" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.10" />
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.3.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Amazon" Version="1.66.0-alpha" />
@@ -60,9 +57,9 @@
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.8" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.10" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.8" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
<!--
@@ -76,6 +73,7 @@
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageVersion Include="ModelContextProtocol" Version="0.4.0-preview.2" />
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
<!-- Moq to stay below v4.20 due to behavior change. need to be sure fixed -->
<PackageVersion Include="Moq" Version="4.18.4" />
@@ -95,29 +93,29 @@
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.CodeDom" Version="9.0.10" />
<PackageVersion Include="System.CodeDom" Version="9.0.8" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.10" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.10" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.10" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.8" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.8" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.8" />
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
<PackageVersion Include="System.Data.SqlClient" Version="4.9.0" />
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.10" />
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.8" />
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.10" />
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.10" />
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.8" />
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.8" />
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
<PackageVersion Include="System.Management" Version="9.0.10" />
<PackageVersion Include="System.Management" Version="9.0.8" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.10" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.8" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.8" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
<PackageVersion Include="UnitsNet" Version="5.56.0" />
@@ -139,4 +137,4 @@
<PackageVersion Include="Microsoft.VariantAssignment.Client" Version="2.4.17140001" />
<PackageVersion Include="Microsoft.VariantAssignment.Contract" Version="3.0.16990001" />
</ItemGroup>
</Project>
</Project>

View File

@@ -330,6 +330,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AwakeModuleInterface", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Awake", "src\modules\awake\Awake\Awake.csproj", "{D940E07F-532C-4FF3-883F-790DA014F19A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerToys.McpServer", "src\McpServer\PowerToys.McpServer.csproj", "{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.csproj", "{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}"
@@ -822,8 +824,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CursorWrap", "src\modules\MouseUtils\CursorWrap\CursorWrap.vcxproj", "{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
@@ -1458,6 +1458,14 @@ Global
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|ARM64.Build.0 = Release|ARM64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Debug|ARM64.Build.0 = Debug|ARM64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Debug|x64.ActiveCfg = Debug|x64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Debug|x64.Build.0 = Debug|x64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Release|ARM64.ActiveCfg = Release|ARM64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Release|ARM64.Build.0 = Release|ARM64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Release|x64.ActiveCfg = Release|x64
{8A6F5D3B-F59E-4F34-A1D3-3F69D3FDBD9D}.Release|x64.Build.0 = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|ARM64.Build.0 = Debug|ARM64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
@@ -2992,14 +3000,6 @@ Global
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.Build.0 = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.ActiveCfg = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.Build.0 = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.ActiveCfg = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.Build.0 = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.ActiveCfg = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.Build.0 = Release|x64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
@@ -3361,12 +3361,12 @@ Global
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{45354F4F-1414-45CE-B600-51CD1209FD19} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -48,7 +48,7 @@ Before you begin, make sure your device meets the system requirements:
Choose one of the installation methods below:
<details open>
<details>
<summary>Download .exe from GitHub</summary>
Go to the [PowerToys GitHub releases][github-release-link], click Assets to reveal the downloads, and choose the installer that matches your architecture and install scope. For most devices, that's the x64 per-user installer.
@@ -56,17 +56,17 @@ Go to the [PowerToys GitHub releases][github-release-link], click Assets to reve
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.96%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.1/PowerToysUserSetup-0.95.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.1/PowerToysUserSetup-0.95.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.1/PowerToysSetup-0.95.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.1/PowerToysSetup-0.95.1-arm64.exe
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.0/PowerToysUserSetup-0.95.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.0/PowerToysUserSetup-0.95.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.0/PowerToysSetup-0.95.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.95.0/PowerToysSetup-0.95.0-arm64.exe
| Description | Filename |
|----------------|----------|
| Per user - x64 | [PowerToysUserSetup-0.95.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.95.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.95.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.95.1-arm64.exe][ptMachineArm64] |
| Per user - x64 | [PowerToysUserSetup-0.95.0-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.95.0-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.95.0-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.95.0-arm64.exe][ptMachineArm64] |
</details>
@@ -281,4 +281,4 @@ The application logs basic diagnostic data (telemetry). For more privacy informa
[roadmap]: https://github.com/microsoft/PowerToys/wiki/Roadmap
[privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839
[loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title=
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs

View File

@@ -0,0 +1,87 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -1493,11 +1493,12 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
}
processes.resize(bytes / sizeof(processes[0]));
std::array<std::wstring_view, 42> processesToTerminate = {
std::array<std::wstring_view, 43> processesToTerminate = {
L"PowerToys.PowerLauncher.exe",
L"PowerToys.Settings.exe",
L"PowerToys.AdvancedPaste.exe",
L"PowerToys.Awake.exe",
L"PowerToys.McpServer.exe",
L"PowerToys.FancyZones.exe",
L"PowerToys.FancyZonesEditor.exe",
L"PowerToys.FileLocksmithUI.exe",

View File

@@ -34,8 +34,13 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(Platform)\$(Configuration)\SetupShared\</OutDir>
<IntDir>$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\SetupShared\obj\</IntDir>
<OutDir Condition=" '$(PerUser)' != 'true' ">$(Platform)\$(Configuration)\MachineSetup\</OutDir>
<OutDir Condition=" '$(PerUser)' == 'true' ">$(Platform)\$(Configuration)\UserSetup\</OutDir>
<IntDir Condition=" '$(PerUser)' != 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\MachineSetup\obj\</IntDir>
<IntDir Condition=" '$(PerUser)' == 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\UserSetup\obj\</IntDir>
<!-- The CMD script below checks this value, and it is **CASE SENSITIVE** -->
<NormalizedPerUserValue>false</NormalizedPerUserValue>
<NormalizedPerUserValue Condition=" '$(PerUser)' == 'true' ">true</NormalizedPerUserValue>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
@@ -54,7 +59,6 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs.bk""""
@@ -76,7 +80,8 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs.bk""""
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if not "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform) -installscopeperuser $(NormalizedPerUserValue)
</Command>
<Message>Backing up original files and populating .NET and WPF Runtime dependencies for WiX3 based installer</Message>
</PreBuildEvent>
@@ -110,6 +115,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -122,6 +128,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
</ClCompile>
<Link>
@@ -174,4 +181,4 @@
<Error Condition="!Exists('..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props'))" />
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props'))" />
</Target>
</Project>
</Project>

View File

@@ -4,13 +4,6 @@
<Fragment>
<DirectoryRef Id="WinUI3AppsInstallFolder">
<Directory Id="CmdPalInstallFolder" Name="CmdPal">
<Directory Id="CmdPalDepsInstallFolder" Name="Dependencies">
<?if $(sys.BUILDARCH) = x64 ?>
<Directory Id="CmdPalDepsX64InstallFolder" Name="x64" />
<?else?>
<Directory Id="CmdPalDepsArm64InstallFolder" Name="arm64" />
<?endif?>
</Directory>
</Directory>
</DirectoryRef>
<DirectoryRef Id="CmdPalInstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test">
@@ -25,40 +18,14 @@
<?endif?>
</Component>
</DirectoryRef>
<?if $(sys.BUILDARCH) = x64 ?>
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.x64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
</Component>
</DirectoryRef>
<?else?>
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.ARM64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
</Component>
</DirectoryRef>
<?endif?>
<ComponentGroup Id="CmdPalComponentGroup">
<Component Id="RemoveCmdPalFolder" Guid="2DF90C08-CC75-4245-A14E-B82904636C53" Directory="INSTALLFOLDER">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCmdPalFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveCmdPalInstallDirFolder" Directory="CmdPalInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveCmdPalDepsInstallDirFolder" Directory="CmdPalDepsInstallFolder" On="uninstall" />
<?if $(sys.BUILDARCH) = x64 ?>
<RemoveFolder Id="RemoveCmdPalDepsX64InstallDirFolder" Directory="CmdPalDepsX64InstallFolder" On="uninstall" />
<?else?>
<RemoveFolder Id="RemoveCmdPalDepsArm64InstallDirFolder" Directory="CmdPalDepsArm64InstallFolder" On="uninstall" />
<?endif?>
</Component>
<ComponentRef Id="Module_CmdPal" />
<ComponentRef Id="Module_CmdPal_Deps" />
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -15,8 +15,8 @@
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_user" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append DSCModules folder to current user's PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[DSCModulesReferenceFolder]" />
<!-- Append install folder to current user's PATH -->
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[INSTALLFOLDER]" />
</Component>
<?else?>
<Component Id="powertoys_env_path_machine" Bitness="always64">
@@ -24,8 +24,8 @@
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_machine" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append DSCModules folder to machine PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[DSCModulesReferenceFolder]" />
<!-- Append install folder to machine PATH -->
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[INSTALLFOLDER]" />
</Component>
<?endif?>
<Component Id="powertoys_toast_clsid" Bitness="always64">
@@ -63,6 +63,16 @@
</Component>
</DirectoryRef>
<DirectoryRef Id="DSCModulesReferenceFolder">
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
</DirectoryRef>
<?if $(var.PerUser) = "true" ?>
<!-- DSC module files for PerUser handled in InstallDSCModule custom action. -->
<?else?>
@@ -110,6 +120,7 @@
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall" />
@@ -117,15 +128,16 @@
<ComponentRef Id="powertoys_exe" />
<ComponentRef Id="PowerToysStartMenuShortcut" />
<ComponentRef Id="powertoys_per_machine_comp" />
<?if $(var.PerUser) = "true" ?>
<ComponentRef Id="powertoys_env_path_user" />
<?else?>
<ComponentRef Id="powertoys_env_path_machine" />
<?endif?>
<ComponentRef Id="powertoys_toast_clsid" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />
<ComponentRef Id="DesktopShortcut" />
<?if $(var.PerUser) = "true" ?>
<ComponentRef Id="powertoys_env_path_user" />
<?else?>
<ComponentRef Id="powertoys_env_path_machine" />
<?endif?>
<ComponentRef Id="PowerToysDSCReference" />
<?if $(var.PerUser) = "false" ?>
<ComponentRef Id="PowerToysDSC" />
<?endif?>

View File

@@ -1,5 +1,4 @@
<Project>
<Import Project="..\..\Directory.Build.props" Condition="Exists('..\..\Directory.Build.props')" />
<Import Project="..\..\src\Version.props" Condition="Exists('..\..\src\Version.props')" />
<PropertyGroup>
<!-- Set BaseIntermediateOutputPath for each project to avoid conflicts -->
@@ -9,4 +8,4 @@
<!-- Set MSBuildProjectExtensionsPath to use the BaseIntermediateOutputPath -->
<MSBuildProjectExtensionsPath Condition="'$(BaseIntermediateOutputPath)' != ''">$(BaseIntermediateOutputPath)</MSBuildProjectExtensionsPath>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,33 +0,0 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define DscJsonFiles=?>
<?define DscJsonFilesPath=$(var.BinDir)\DSCModules?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder" FileSource="$(var.DscJsonFilesPath)">
<!-- DSC v2 PowerShell module files -->
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
<!-- DSC v3 JSON manifest files - Generated by generateAllFileComponents.ps1 -->
<!--DscJsonFiles_Component_Def-->
</DirectoryRef>
<ComponentGroup Id="DscResourcesComponentGroup">
<ComponentRef Id="PowerToysDSCReference" />
<Component Id="RemoveDSCModulesFolder" Guid="A3C77D92-4E97-4C1A-9F2E-8B3C5D6E7F80" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveDSCModulesFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -14,6 +14,7 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" x64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' != 'x64'">
@@ -24,6 +25,7 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" arm64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
@@ -35,7 +37,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\CmdPal.wxs.bk ..\..\..\CmdPal.wxs
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
call move /Y ..\..\..\DscResources.wxs.bk ..\..\..\DscResources.wxs
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
@@ -59,12 +60,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(RunBuildEvents)'=='false'">
<PostBuildEvent></PostBuildEvent>
<RunPostBuildEvent></RunPostBuildEvent>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
<PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' == 'true' ">
<DefineConstants>$(DefineConstants);PerUser=true</DefineConstants>
</PropertyGroup>

View File

@@ -14,16 +14,11 @@
<?define SettingsV2OOBEAssetsFluentIconsFiles=?>
<?define SettingsV2OOBEAssetsFluentIconsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\?>
<?define SettingsV2IconsModelsFiles=?>
<?define SettingsV2IconsModelsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\Models\?>
<Fragment>
<DirectoryRef Id="WinUI3AppsAssetsFolder">
<Directory Id="SettingsV2AssetsInstallFolder" Name="Settings">
<Directory Id="SettingsAppAssetsScriptsFolder" Name="Scripts" />
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons">
<Directory Id="SettingsV2IconsModelsInstallFolder" Name="Models" />
</Directory>
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons" />
<Directory Id="SettingsV2AssetsModulesInstallFolder" Name="Modules">
<Directory Id="SettingsV2OOBEAssetsModulesInstallFolder" Name="OOBE" />
</Directory>
@@ -50,11 +45,6 @@
<!--SettingsV2OOBEAssetsFluentIconsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsV2IconsModelsInstallFolder" FileSource="$(var.SettingsV2IconsModelsFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--SettingsV2IconsModelsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsAppAssetsScriptsFolder" FileSource="$(var.SettingsV2AssetsFilesPath)\Scripts\">
<Component Id="CommandNotFound_Scripts" Guid="898EFA1E-EDD3-4F4B-8C7F-4A14B0D05B02" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
@@ -77,7 +67,6 @@
</RegistryKey>
<RemoveFolder Id="RemoveFolderSettingsV2AssetsInstallFolder" Directory="SettingsV2AssetsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsFluentIconsInstallFolder" Directory="SettingsV2OOBEAssetsFluentIconsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2IconsModelsInstallFolder" Directory="SettingsV2IconsModelsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2AssetsModulesInstallFolder" Directory="SettingsV2AssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsModulesInstallFolder" Directory="SettingsV2OOBEAssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsAppAssetsScriptsFolder" Directory="SettingsAppAssetsScriptsFolder" On="uninstall" />

View File

@@ -1,7 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}</ProjectGuid>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<TargetName>SilentFilesInUseBAFunction</TargetName>
<ProjectName>PowerToysSetupCustomActionsVNext</ProjectName>
<ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
@@ -10,6 +33,7 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- Configuration-specific property groups -->
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
@@ -41,10 +65,7 @@
</PropertyGroup>
<ItemGroup>
<ClCompile Include="SilentFilesInUseBAFunctions.cpp">
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="SilentFilesInUseBAFunctions.cpp" />
<ClCompile Include="bafunctions.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -71,5 +92,31 @@
</Link>
</ItemDefinitionGroup>
<!-- C++ source compile-specific things for Debug/Release configurations -->
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -18,6 +18,7 @@ public: // IBootstrapperApplication
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION SYSTEM ACTIVE *** Running detect begin BA function. fCached=%d, registrationType=%d, cPackages=%u, fCancel=%d", fCached, registrationType, cPackages, *pfCancel);
LExit:
return hr;
}
@@ -31,6 +32,12 @@ public: // IBAFunctions
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION SYSTEM ACTIVE *** Running plan begin BA function. cPackages=%u, fCancel=%d", cPackages, *pfCancel);
//-------------------------------------------------------------------------------------------------
// YOUR CODE GOES HERE
// BalExitOnFailure(hr, "Change this message to represent real error handling.");
//-------------------------------------------------------------------------------------------------
LExit:
return hr;
}
@@ -56,7 +63,6 @@ public: // IBAFunctions
)
{
HRESULT hr = S_OK;
UNREFERENCED_PARAMETER(source);
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION CALLED *** Running OnExecuteFilesInUse BA function. packageId=%ls, cFiles=%u, recommendation=%d", wzPackageId, cFiles, nRecommendation);

View File

@@ -1,7 +1,9 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, Position = 1)]
[string]$platform
[string]$platform,
[Parameter(Mandatory = $False, Position = 2)]
[string]$installscopeperuser = "false"
)
Function Generate-FileList() {
@@ -75,7 +77,9 @@ Function Generate-FileComponents() {
[Parameter(Mandatory = $True, Position = 1)]
[string]$fileListName,
[Parameter(Mandatory = $True, Position = 2)]
[string]$wxsFilePath
[string]$wxsFilePath,
[Parameter(Mandatory = $True, Position = 3)]
[string]$regroot
)
$wxsFile = Get-Content $wxsFilePath;
@@ -96,7 +100,7 @@ Function Generate-FileComponents() {
$componentDefs +=
@"
<Component Id="$($componentId)" Guid="$((New-Guid).ToString().ToUpper())">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryKey Root="$($regroot)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$($componentId)" Value="" KeyPath="yes"/>
</RegistryKey>`r`n
"@
@@ -130,194 +134,194 @@ if ($platform -ceq "arm64") {
$platform = "ARM64"
}
if ($installscopeperuser -eq "true") {
$registryroot = "HKCU"
} else {
$registryroot = "HKLM"
}
#BaseApplications
Generate-FileList -fileDepsJson "" -fileListName BaseApplicationsFiles -wxsFilePath $PSScriptRoot\BaseApplications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release"
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs -regroot $registryroot
#WinUI3Applications
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -regroot $registryroot
#AdvancedPaste
Generate-FileList -fileDepsJson "" -fileListName AdvancedPasteAssetsFiles -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\AdvancedPaste"
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -regroot $registryroot
#AwakeFiles
Generate-FileList -fileDepsJson "" -fileListName AwakeImagesFiles -wxsFilePath $PSScriptRoot\Awake.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Awake"
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs -regroot $registryroot
#ColorPicker
Generate-FileList -fileDepsJson "" -fileListName ColorPickerAssetsFiles -wxsFilePath $PSScriptRoot\ColorPicker.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ColorPicker"
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs -regroot $registryroot
#Environment Variables
Generate-FileList -fileDepsJson "" -fileListName EnvironmentVariablesAssetsFiles -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\EnvironmentVariables"
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -regroot $registryroot
#FileExplorerAdd-ons
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerMonacoAssetsFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco"
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerCustomLanguagesFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco\customLanguages"
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
#FileLocksmith
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\FileLocksmith"
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -regroot $registryroot
#Hosts
Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $PSScriptRoot\Hosts.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Hosts"
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs -regroot $registryroot
#ImageResizer
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\ImageResizer"
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs -regroot $registryroot
# Light Switch Service
Generate-FileList -fileDepsJson "" -fileListName LightSwitchFiles -wxsFilePath $PSScriptRoot\LightSwitch.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\LightSwitchService"
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs -regroot $registryroot
#New+
Generate-FileList -fileDepsJson "" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\NewPlus"
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs -regroot $registryroot
#Peek
Generate-FileList -fileDepsJson "" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Peek\"
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs -regroot $registryroot
#PowerRename
Generate-FileList -fileDepsJson "" -fileListName PowerRenameAssetsFiles -wxsFilePath $PSScriptRoot\PowerRename.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\PowerRename\"
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs -regroot $registryroot
#RegistryPreview
Generate-FileList -fileDepsJson "" -fileListName RegistryPreviewAssetsFiles -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\RegistryPreview\"
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -regroot $registryroot
#Run
Generate-FileList -fileDepsJson "" -fileListName launcherImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\PowerLauncher"
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
## Plugins
###Calculator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.deps.json" -fileListName calcComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName calcImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Images"
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Folder
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Microsoft.Plugin.Folder.deps.json" -fileListName FolderComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName FolderImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Images"
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Program
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Microsoft.Plugin.Program.deps.json" -fileListName ProgramComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ProgramImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Images"
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Shell
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Microsoft.Plugin.Shell.deps.json" -fileListName ShellComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ShellImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Images"
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Indexer
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Microsoft.Plugin.Indexer.deps.json" -fileListName IndexerComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName IndexerImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Images"
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###UnitConverter
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.deps.json" -fileListName UnitConvCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UnitConvImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Images"
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WebSearch
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Community.PowerToys.Run.Plugin.WebSearch.deps.json" -fileListName WebSrchCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WebSrchImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Images"
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###History
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Microsoft.PowerToys.Run.Plugin.History.deps.json" -fileListName HistoryPluginComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName HistoryPluginImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Images"
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Uri
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Microsoft.Plugin.Uri.deps.json" -fileListName UriComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UriImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Images"
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###VSCodeWorkspaces
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.deps.json" -fileListName VSCWrkCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName VSCWrkImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Images"
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowWalker
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Microsoft.Plugin.WindowWalker.deps.json" -fileListName WindowWlkrCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WindowWlkrImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Images"
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###OneNote
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Microsoft.PowerToys.Run.Plugin.OneNote.deps.json" -fileListName OneNoteComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName OneNoteImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Images"
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Registry
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Microsoft.PowerToys.Run.Plugin.Registry.deps.json" -fileListName RegistryComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName RegistryImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Images"
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Service
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Microsoft.PowerToys.Run.Plugin.Service.deps.json" -fileListName ServiceComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ServiceImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Images"
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###System
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Microsoft.PowerToys.Run.Plugin.System.deps.json" -fileListName SystemComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName SystemImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Images"
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###TimeDate
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Microsoft.PowerToys.Run.Plugin.TimeDate.deps.json" -fileListName TimeDateComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName TimeDateImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Images"
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowsSettings
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.deps.json" -fileListName WinSetCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinSetImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Images"
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowsTerminal
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.deps.json" -fileListName WinTermCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinTermImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Images"
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###PowerToys
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Microsoft.PowerToys.Run.Plugin.PowerToys.deps.json" -fileListName PowerToysCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName PowerToysImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Images"
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###ValueGenerator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Community.PowerToys.Run.Plugin.ValueGenerator.deps.json" -fileListName ValueGeneratorCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ValueGeneratorImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Images"
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
## Plugins
#ShortcutGuide
Generate-FileList -fileDepsJson "" -fileListName ShortcutGuideSvgFiles -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ShortcutGuide\"
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -regroot $registryroot
#Settings
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\OOBE\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsFluentIconsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2IconsModelsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\Models\"
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2IconsModelsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
#Workspaces
Generate-FileList -fileDepsJson "" -fileListName WorkspacesImagesComponentFiles -wxsFilePath $PSScriptRoot\Workspaces.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Workspaces\"
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs
#DSC Resources - JSON manifest files in DSCModules subfolder
Generate-FileList -fileDepsJson "" -fileListName DscJsonFiles -wxsFilePath $PSScriptRoot\DscResources.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\DSCModules\"
Generate-FileComponents -fileListName "DscJsonFiles" -wxsFilePath $PSScriptRoot\DscResources.wxs
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs -regroot $registryroot

View File

@@ -0,0 +1,102 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Find build output directory
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
# Find all DSC manifest JSON files
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
# Create empty component group
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
# Generate WiX fragment
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
# Write the WiX file
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -2,9 +2,17 @@
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="Microsoft.SemanticKernel*" />
<package pattern="Microsoft.Extensions.*" />
<package pattern="System.*" />
<package pattern="OpenAI" />
<package pattern="Azure.*" />
</packageSource>
<packageSource key="PowerToysPublicDependencies">
<package pattern="*" />
</packageSource>

View File

@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>PowerToys.McpServer</RootNamespace>
<AssemblyName>PowerToys.McpServer</AssemblyName>
<Nullable>enable</Nullable>
<OutputPath>..\..\$(Platform)\$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>PowerToys.McpServer.dev.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(CIBuild)'=='true'">
<ApplicationManifest>PowerToys.McpServer.prod.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\common\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="PowerToys.McpServer.app" />
<msix xmlns="urn:schemas-microsoft-com:msix.v1"
publisher="CN=PowerToys Dev, O=PowerToys, L=Redmond, S=Washington, C=US"
packageName="Microsoft.PowerToys.SparseApp"
applicationId="PowerToys.McpServer" />
</assembly>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="PowerToys.McpServer.app" />
<msix xmlns="urn:schemas-microsoft-com:msix.v1"
publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
packageName="Microsoft.PowerToys.SparseApp"
applicationId="PowerToys.McpServer" />
</assembly>

57
src/McpServer/Program.cs Normal file
View File

@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using PowerToys.McpServer.Tools;
namespace PowerToys.McpServer
{
internal sealed class Program
{
private static async Task<int> Main(string[] args)
{
// Initialize PowerToys logger
// Logger.InitializeLogger expects path relative to Constants.AppDataPath()
// which already points to LocalAppData\Microsoft\PowerToys
string logPath = Path.Combine("\\McpServer", "Logs");
Logger.InitializeLogger(logPath);
Logger.LogInfo("Starting PowerToys MCP Server with official SDK");
try
{
var builder = Host.CreateApplicationBuilder(args);
// Configure all logs to go to stderr (required for MCP protocol)
builder.Logging.AddConsole(consoleLogOptions =>
{
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
// Register MCP server with stdio transport and tools
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();
Logger.LogInfo("Building and running MCP host...");
await builder.Build().RunAsync();
Logger.LogInfo("MCP server shutdown complete");
return 0;
}
catch (Exception ex)
{
Logger.LogError("Fatal error in MCP server", ex);
return 1;
}
}
}
}

102
src/McpServer/README.md Normal file
View File

@@ -0,0 +1,102 @@
# PowerToys Model Context Protocol Server
This module hosts a standalone Model Context Protocol (MCP) server that exposes PowerToys functionality to MCP-compliant AI agents. The server is built as a .NET 9 console application that implements the MCP specification using the official ModelContextProtocol SDK.
## Project Structure
- **Program.cs**: Main entry point that configures the MCP server with stdio transport
- **Tools/AwakeTools.cs**: Implementation of Awake-related MCP tools
- **PowerToys.McpServer.csproj**: .NET 9 project configuration with MCP dependencies
## Dependencies
- **Microsoft.Extensions.Hosting**: For hosting infrastructure and dependency injection
- **ModelContextProtocol**: Official MCP SDK for .NET
- **PowerToys Settings Library**: Integration with PowerToys settings system
- **ManagedCommon**: PowerToys logging and utilities
## Available Tools
| Tool Name | Description | Parameters | Module |
|-----------|-------------|------------|--------|
| `GetAwakeStatus` | Returns the current Awake configuration (mode, timers, display policy) | None | Awake |
| `SetAwakePassive` | Set Awake to passive mode (allow system to sleep normally) | None | Awake |
| `SetAwakeIndefinite` | Set Awake to indefinite mode (keep system awake until manually changed) | `keepDisplayOn` (bool), `force` (bool) | Awake |
| `SetAwakeTimed` | Set Awake to timed mode (keep system awake for a specific duration) | `durationSeconds` (int), `keepDisplayOn` (bool), `force` (bool) | Awake |
## Building and Running
### Prerequisites
- .NET 9 SDK
- Visual Studio 2022 (recommended) or VS Code with C# extension
### Build
```bash
# From PowerToys root directory
msbuild src/McpServer/PowerToys.McpServer.csproj /p:Platform=x64 /p:Configuration=Debug
# Or using dotnet CLI
cd src/McpServer
dotnet build -c Debug
```
### Run the Server
The executable is built to `x64\Debug\PowerToys.McpServer.exe`. The server communicates over standard input/output using MCP framing (`Content-Length` header followed by JSON).
**Example MCP Client Session:**
1. Client sends `initialize` request with MCP version and capabilities
2. Client calls `tools/list` to discover available PowerToys tools
3. Client invokes `tools/call` with the desired tool name and arguments
4. Server responds with tool execution results or errors
The server will remain active until the process is terminated or a `shutdown` request is received.
### Logging
- Application logs are written to `%LOCALAPPDATA%\Microsoft\PowerToys\McpServer\Logs\`
- MCP protocol logs are sent to stderr (required by MCP specification)
## Architecture
The server uses the official ModelContextProtocol .NET SDK and follows these patterns:
- **Tool Discovery**: Tools are automatically discovered using `WithToolsFromAssembly()`
- **Tool Attributes**: Methods marked with `[McpServerTool]` and `[Description]` are exposed as MCP tools
- **Parameter Binding**: Method parameters are automatically bound from MCP tool call arguments
- **Error Handling**: Exceptions are caught and returned as MCP error responses
- **Settings Integration**: Uses PowerToys settings system for configuration persistence
## Adding New Module Tools
1. Create a new static class in the `Tools/` directory (e.g., `FancyZonesTools.cs`)
2. Mark the class with `[McpServerToolType]` attribute
3. Implement static methods with `[McpServerTool]` and `[Description]` attributes:
```csharp
[McpServerToolType]
public static class MyModuleTools
{
[McpServerTool]
[Description("Description of what this tool does")]
public static JsonObject MyTool(
[Description("Parameter description")] string parameter)
{
// Implementation here
return new JsonObject();
}
}
```
4. Follow existing patterns in `AwakeTools.cs` for:
- Settings integration using `SettingsUtils`
- Logging using `Logger.LogInfo/LogError`
- Error handling and response formatting
- PowerToys process detection and module status checks
## Integration with PowerToys
The MCP server integrates with PowerToys through:
- **Settings System**: Uses the same settings files as the main PowerToys application
- **Process Management**: Detects and interacts with running PowerToys processes
- **Module Status**: Checks if specific PowerToys modules are enabled
- **Logging**: Uses PowerToys logging infrastructure for troubleshooting
Refer to the PowerToys developer documentation for build and packaging instructions.

View File

@@ -0,0 +1,694 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text.Json.Nodes;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using ModelContextProtocol.Server;
using Lock = System.Threading.Lock;
namespace PowerToys.McpServer.Tools
{
/// <summary>
/// MCP tools for PowerToys Awake module.
/// </summary>
[McpServerToolType]
public static class AwakeTools
{
private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
private const string PowerToysProcessName = "PowerToys";
private const string AwakeExecutableName = "PowerToys.Awake.exe";
private static readonly string[] AwakeRelativeSearchPaths =
[
AwakeExecutableName,
Path.Combine("modules", "Awake", AwakeExecutableName),
];
/// <summary>
/// Gets the current Awake mode and configuration.
/// </summary>
/// <returns>JSON object with current Awake status.</returns>
[McpServerTool]
[Description("Get the current Awake mode and configuration from the PowerToys settings store.")]
public static JsonObject GetAwakeStatus()
{
try
{
(bool powerToysRunning, bool awakeModuleEnabled) = CheckPowerToysAndAwakeStatus();
if (!powerToysRunning || !awakeModuleEnabled)
{
if (IsAwakeProcessRunning())
{
// Awake is running via CLI, but we cannot determine its actual configuration
Logger.LogInfo("[MCP] Detected Awake CLI process running while PowerToys is not active or Awake module is disabled.");
return AwakeStatusPayload.CreateUnknownActive().ToJsonObject();
}
return AwakeStatusPayload.CreateInactive().ToJsonObject();
}
// PowerToys is running and Awake module is enabled
bool awakeProcessRunning = IsAwakeProcessRunning();
AwakeSettings settings = SettingsUtils.GetSettingsOrDefault<AwakeSettings>(AwakeSettings.ModuleName);
string summary = FormatAwakeDescription(settings);
if (awakeProcessRunning)
{
summary = $"{summary} An Awake process is already running with the current configuration. To override the active session and apply new settings, use force=true.";
}
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(settings, summary);
Logger.LogInfo("[MCP] Retrieved Awake status via SDK tool.");
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to read Awake status.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
/// <summary>
/// Sets the Awake mode to passive (allow system sleep).
/// </summary>
/// <returns>JSON object with updated Awake status.</returns>
[McpServerTool]
[Description("Set Awake to passive mode (allow system to sleep normally).")]
public static JsonObject SetAwakePassive()
{
try
{
(bool powerToysRunning, bool awakeModuleEnabled) = CheckPowerToysAndAwakeStatus();
if (!powerToysRunning || !awakeModuleEnabled)
{
StopAwakeProcesses();
Logger.LogInfo("[MCP] Stopped all Awake processes because PowerToys is not running.");
return AwakeStatusPayload.CreateInactive().ToJsonObject();
}
AwakeSettings settings = SettingsUtils.GetSettingsOrDefault<AwakeSettings>(AwakeSettings.ModuleName);
settings.Properties.Mode = AwakeMode.PASSIVE;
settings.Properties.KeepDisplayOn = false;
settings.Properties.IntervalHours = 0;
settings.Properties.IntervalMinutes = 0;
SettingsUtils.SaveSettings(settings.ToJsonString(), AwakeSettings.ModuleName);
string confirmation = FormatAwakeDescription(settings);
Logger.LogInfo($"[MCP] {confirmation}");
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(settings, confirmation);
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to set Awake to passive.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
/// <summary>
/// Sets the Awake mode to indefinite (keep system awake forever).
/// </summary>
/// <param name="keepDisplayOn">Whether to keep the display on. Default is true.</param>
/// <returns>JSON object with updated Awake status.</returns>
[McpServerTool]
[Description("Set Awake to indefinite mode (keep system awake until manually changed).")]
public static JsonObject SetAwakeIndefinite(
[Description("Whether to keep the display on")] bool keepDisplayOn = true,
[Description("Force the change even if Awake is already running (default: false)")] bool force = false)
{
try
{
(bool powerToysRunning, bool awakeModuleEnabled) = CheckPowerToysAndAwakeStatus();
if (!powerToysRunning || !awakeModuleEnabled)
{
return AwakeStatusPayload.CreateError(
"Indefinite mode requires PowerToys to be running with Awake module enabled. CLI mode does not support indefinite operation.").ToJsonObject();
}
AwakeSettings settings = SettingsUtils.GetSettingsOrDefault<AwakeSettings>(AwakeSettings.ModuleName);
if (!force && IsAwakeActive(settings))
{
return BuildActiveProcessResponse(settings, true, false);
}
settings.Properties.Mode = AwakeMode.INDEFINITE;
settings.Properties.KeepDisplayOn = keepDisplayOn;
settings.Properties.IntervalHours = 0;
settings.Properties.IntervalMinutes = 0;
SettingsUtils.SaveSettings(settings.ToJsonString(), AwakeSettings.ModuleName);
string confirmation = FormatAwakeDescription(settings);
Logger.LogInfo($"[MCP] {confirmation}");
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(settings, confirmation);
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to set Awake to indefinite.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
/// <summary>
/// Sets the Awake mode to expire at a specific date and time.
/// </summary>
/// <param name="expireAt">ISO 8601 date/time when Awake should expire (e.g., "2025-10-22T15:30:00").</param>
/// <param name="keepDisplayOn">Whether to keep the display on. Default is true.</param>
/// <returns>JSON object with updated Awake status.</returns>
[McpServerTool]
[Description("Set Awake to expire at a specific date and time (ISO 8601 format).")]
public static JsonObject SetAwakeExpireAt(
[Description("ISO 8601 date/time when Awake should expire (e.g., \"2025-10-22T15:30:00\")")] string expireAt,
[Description("Whether to keep the display on")] bool keepDisplayOn = true,
[Description("Force the change even if Awake is already running (default: false)")] bool force = false)
{
try
{
if (!DateTimeOffset.TryParse(expireAt, out DateTimeOffset expirationDateTime))
{
return AwakeStatusPayload.CreateError($"Invalid date format: '{expireAt}'. Please use ISO 8601 format (e.g., '2025-10-22T15:30:00').").ToJsonObject();
}
if (expirationDateTime <= DateTimeOffset.Now)
{
return AwakeStatusPayload.CreateError("Expiration time must be in the future.").ToJsonObject();
}
(bool powerToysRunning, bool awakeModuleEnabled) = CheckPowerToysAndAwakeStatus();
if (!powerToysRunning || !awakeModuleEnabled)
{
TimeSpan duration = expirationDateTime - DateTimeOffset.Now;
uint durationSeconds = (uint)Math.Max(60, duration.TotalSeconds);
return HandleCliScenario(AwakeMode.EXPIRABLE, keepDisplayOn, durationSeconds, force);
}
AwakeSettings settings = SettingsUtils.GetSettingsOrDefault<AwakeSettings>(AwakeSettings.ModuleName);
if (!force && IsAwakeActive(settings))
{
return BuildActiveProcessResponse(settings, true, false);
}
TimeSpan timeSpan = expirationDateTime - DateTimeOffset.Now;
uint hours = (uint)timeSpan.TotalHours;
uint minutes = (uint)Math.Ceiling(timeSpan.TotalMinutes % 60);
if (hours == 0 && minutes == 0)
{
minutes = 1;
}
settings.Properties.Mode = AwakeMode.EXPIRABLE;
settings.Properties.KeepDisplayOn = keepDisplayOn;
settings.Properties.IntervalHours = hours;
settings.Properties.IntervalMinutes = minutes;
settings.Properties.ExpirationDateTime = expirationDateTime;
SettingsUtils.SaveSettings(settings.ToJsonString(), AwakeSettings.ModuleName);
string confirmation = FormatAwakeDescription(settings);
Logger.LogInfo($"[MCP] {confirmation}");
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(settings, confirmation);
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to set Awake expire-at mode.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
/// <summary>
/// Sets the Awake mode to timed (keep system awake for a specific duration).
/// </summary>
/// <param name="durationSeconds">Duration in seconds (minimum 60).</param>
/// <param name="keepDisplayOn">Whether to keep the display on. Default is true.</param>
/// <returns>JSON object with updated Awake status.</returns>
[McpServerTool]
[Description("Set Awake to timed mode (keep system awake for a specific duration).")]
public static JsonObject SetAwakeTimed(
[Description("Duration in seconds (minimum 60)")] int durationSeconds,
[Description("Whether to keep the display on")] bool keepDisplayOn = true,
[Description("Force the change even if Awake is already running (default: false)")] bool force = false)
{
try
{
if (durationSeconds < 60)
{
durationSeconds = 60;
}
(bool powerToysRunning, bool awakeModuleEnabled) = CheckPowerToysAndAwakeStatus();
if (!powerToysRunning || !awakeModuleEnabled)
{
return HandleCliScenario(AwakeMode.TIMED, keepDisplayOn, (uint)durationSeconds, force);
}
TimeSpan timeSpan = TimeSpan.FromSeconds(durationSeconds);
uint hours = (uint)timeSpan.TotalHours;
uint minutes = (uint)Math.Ceiling(timeSpan.TotalMinutes % 60);
if (hours == 0 && minutes == 0)
{
minutes = 1;
}
AwakeSettings settings = SettingsUtils.GetSettingsOrDefault<AwakeSettings>(AwakeSettings.ModuleName);
if (!force && IsAwakeActive(settings))
{
return BuildActiveProcessResponse(settings, true, false);
}
settings.Properties.Mode = AwakeMode.TIMED;
settings.Properties.KeepDisplayOn = keepDisplayOn;
settings.Properties.IntervalHours = hours;
settings.Properties.IntervalMinutes = minutes;
settings.Properties.ExpirationDateTime = DateTimeOffset.Now.Add(timeSpan);
SettingsUtils.SaveSettings(settings.ToJsonString(), AwakeSettings.ModuleName);
string confirmation = FormatAwakeDescription(settings);
Logger.LogInfo($"[MCP] {confirmation}");
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(settings, confirmation);
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to set Awake to timed mode.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
private static string FormatAwakeDescription(AwakeSettings settings)
{
var mode = settings.Properties.Mode.ToString().ToLowerInvariant();
var display = settings.Properties.KeepDisplayOn ? "display on" : "display off";
return settings.Properties.Mode switch
{
AwakeMode.PASSIVE => "Awake mode: passive (system sleep allowed)",
AwakeMode.INDEFINITE => $"Awake mode: indefinite, {display}",
AwakeMode.TIMED => $"Awake mode: timed ({settings.Properties.IntervalHours}h {settings.Properties.IntervalMinutes}m), {display}",
AwakeMode.EXPIRABLE => $"Awake mode: expirable (until {settings.Properties.ExpirationDateTime:yyyy-MM-dd HH:mm}), {display}",
_ => $"Awake mode: {mode}",
};
}
private static JsonObject BuildActiveProcessResponse(AwakeSettings settings, bool powerToysRunning, bool launchedViaCli)
{
return AwakeStatusPayload.CreateError(
"Awake is already running. Use force=true to override.",
settings).ToJsonObject();
}
private static bool IsPowerToysRunning()
{
try
{
return Process.GetProcessesByName(PowerToysProcessName).Length > 0;
}
catch (Exception ex)
{
Logger.LogWarning($"[MCP] Unable to determine PowerToys runner status: {ex.Message}");
return true;
}
}
/// <summary>
/// Gets whether the Awake module is enabled in PowerToys settings.
/// </summary>
/// <returns>True if Awake module is enabled, false otherwise</returns>
private static bool IsAwakeModuleEnabled()
{
try
{
var generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
return generalSettings?.Enabled?.Awake == true;
}
catch
{
// If we can't read settings, assume disabled
return false;
}
}
/// <summary>
/// Checks PowerToys and Awake module status.
/// </summary>
/// <returns>Tuple containing (powerToysRunning, awakeModuleEnabled)</returns>
private static (bool PowerToysRunning, bool AwakeModuleEnabled) CheckPowerToysAndAwakeStatus()
{
bool powerToysRunning = IsPowerToysRunning();
bool awakeModuleEnabled = powerToysRunning && IsAwakeModuleEnabled();
return (powerToysRunning, awakeModuleEnabled);
}
/// <summary>
/// Handles CLI scenario when PowerToys is not running or Awake module is disabled.
/// </summary>
/// <param name="mode">The Awake mode to set</param>
/// <param name="keepDisplayOn">Whether to keep display on</param>
/// <param name="durationSeconds">Duration in seconds (0 for indefinite)</param>
/// <param name="force">Whether to force override existing process</param>
/// <returns>JSON response for CLI scenario</returns>
private static JsonObject HandleCliScenario(AwakeMode mode, bool keepDisplayOn, uint durationSeconds, bool force)
{
if (!force && IsAwakeProcessRunning())
{
return AwakeStatusPayload.CreateError(
"Awake is already running and PowerToys is not active. Use force=true to override.").ToJsonObject();
}
if (IsAwakeProcessRunning())
{
StopAwakeProcesses();
}
JsonObject cliPayload = StartAwakeCliProcess(mode, keepDisplayOn, durationSeconds);
return cliPayload;
}
private static JsonObject StartAwakeCliProcess(AwakeMode mode, bool keepDisplayOn, uint durationSeconds)
{
try
{
if (!TryResolveAwakeExecutable(out string executablePath))
{
throw new FileNotFoundException("PowerToys.Awake.exe was not found near the MCP server executable.");
}
ProcessStartInfo startInfo = CreateSimpleStartInfo(executablePath, mode, keepDisplayOn, durationSeconds);
Process? launchedProcess = Process.Start(startInfo);
if (launchedProcess is null)
{
throw new InvalidOperationException("Failed to start PowerToys.Awake.exe.");
}
// No tracking, just launch and forget
launchedProcess.Dispose();
AwakeSettings snapshot = BuildAwakeSnapshot(mode, keepDisplayOn, durationSeconds);
string confirmation = FormatAwakeDescription(snapshot);
Logger.LogInfo($"[MCP] Launched Awake CLI for mode {mode} (PowerToys not running).");
AwakeStatusPayload payload = AwakeStatusPayload.FromSettings(snapshot, confirmation);
return payload.ToJsonObject();
}
catch (Exception ex)
{
Logger.LogError("[MCP] Failed to start Awake CLI.", ex);
return AwakeStatusPayload.CreateError(ex.Message).ToJsonObject();
}
}
private static ProcessStartInfo CreateSimpleStartInfo(string executablePath, AwakeMode mode, bool keepDisplayOn, uint durationSeconds)
{
string workingDirectory = Path.GetDirectoryName(executablePath) ?? AppDomain.CurrentDomain.BaseDirectory;
var startInfo = new ProcessStartInfo(executablePath)
{
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = string.IsNullOrEmpty(workingDirectory) ? AppDomain.CurrentDomain.BaseDirectory : workingDirectory,
};
startInfo.ArgumentList.Add("--display-on");
startInfo.ArgumentList.Add(keepDisplayOn ? "true" : "false");
if (mode == AwakeMode.TIMED && durationSeconds > 0)
{
startInfo.ArgumentList.Add("--time-limit");
startInfo.ArgumentList.Add(durationSeconds.ToString(CultureInfo.InvariantCulture));
}
else if (mode == AwakeMode.EXPIRABLE && durationSeconds > 0)
{
// For EXPIRABLE mode, convert duration to expiration datetime
DateTimeOffset expirationDateTime = DateTimeOffset.Now.AddSeconds(durationSeconds);
startInfo.ArgumentList.Add("--expire-at");
startInfo.ArgumentList.Add(expirationDateTime.ToString("O")); // ISO 8601 format
}
return startInfo;
}
private static void StopAwakeProcesses()
{
string processName = Path.GetFileNameWithoutExtension(AwakeExecutableName);
try
{
Process[] awakeProcesses = Process.GetProcessesByName(processName);
foreach (Process process in awakeProcesses)
{
try
{
if (!process.HasExited)
{
process.Kill(true);
process.WaitForExit(TimeSpan.FromSeconds(5));
}
}
catch (Exception ex)
{
Logger.LogWarning($"[MCP] Failed to terminate Awake process {process.Id}: {ex.Message}");
}
finally
{
process.Dispose();
}
}
}
catch (Exception ex)
{
Logger.LogWarning($"[MCP] Failed to enumerate Awake processes: {ex.Message}");
}
}
private static AwakeSettings BuildAwakeSnapshot(AwakeMode mode, bool keepDisplayOn, uint durationSeconds)
{
var snapshot = new AwakeSettings();
snapshot.Properties.Mode = mode;
snapshot.Properties.KeepDisplayOn = keepDisplayOn;
if (mode == AwakeMode.TIMED && durationSeconds > 0)
{
TimeSpan timeSpan = TimeSpan.FromSeconds(durationSeconds);
snapshot.Properties.IntervalHours = (uint)timeSpan.TotalHours;
snapshot.Properties.IntervalMinutes = (uint)Math.Ceiling(timeSpan.TotalMinutes % 60);
snapshot.Properties.ExpirationDateTime = DateTimeOffset.Now.Add(timeSpan);
}
else if (mode == AwakeMode.EXPIRABLE && durationSeconds > 0)
{
snapshot.Properties.IntervalHours = 0;
snapshot.Properties.IntervalMinutes = 0;
snapshot.Properties.ExpirationDateTime = DateTimeOffset.Now.AddSeconds(durationSeconds);
}
else
{
snapshot.Properties.IntervalHours = 0;
snapshot.Properties.IntervalMinutes = 0;
snapshot.Properties.ExpirationDateTime = DateTimeOffset.Now;
}
return snapshot;
}
private static bool TryResolveAwakeExecutable(out string executablePath)
{
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (TryResolveAwakeExecutableFrom(baseDirectory, out executablePath))
{
return true;
}
string? parentDirectory = Directory.GetParent(baseDirectory)?.FullName;
if (!string.IsNullOrEmpty(parentDirectory) && TryResolveAwakeExecutableFrom(parentDirectory, out executablePath))
{
return true;
}
executablePath = string.Empty;
return false;
}
private static bool TryResolveAwakeExecutableFrom(string rootDirectory, out string executablePath)
{
foreach (string relativePath in AwakeRelativeSearchPaths)
{
string candidate = Path.Combine(rootDirectory, relativePath);
if (File.Exists(candidate))
{
executablePath = candidate;
return true;
}
}
executablePath = string.Empty;
return false;
}
private static bool IsAwakeProcessRunning()
{
try
{
string processName = Path.GetFileNameWithoutExtension(AwakeExecutableName);
return Process.GetProcessesByName(processName).Length > 0;
}
catch (Exception ex)
{
Logger.LogWarning($"[MCP] Unable to determine Awake process status: {ex.Message}");
return false;
}
}
private static bool IsAwakeActive(AwakeSettings settings)
{
// Only check if Awake module is enabled
return IsAwakeModuleEnabled();
}
private sealed class AwakeStatusPayload
{
internal string Mode { get; set; } = "unknown";
internal bool? KeepDisplayOn { get; set; }
internal uint? IntervalHours { get; set; }
internal uint? IntervalMinutes { get; set; }
internal string? ExpirationDateTime { get; set; }
internal string Summary { get; set; } = string.Empty;
internal bool Success { get; set; } = true;
internal string? ErrorMessage { get; set; }
internal JsonObject ToJsonObject()
{
var result = new JsonObject
{
["mode"] = Mode,
["summary"] = Summary,
};
// Add properties only if they have values
if (KeepDisplayOn.HasValue)
{
result["keepDisplayOn"] = KeepDisplayOn.Value;
}
if (IntervalHours.HasValue)
{
result["intervalHours"] = IntervalHours.Value;
}
if (IntervalMinutes.HasValue)
{
result["intervalMinutes"] = IntervalMinutes.Value;
}
if (!string.IsNullOrEmpty(ExpirationDateTime))
{
result["expirationDateTime"] = ExpirationDateTime;
}
// Add error handling properties
if (!Success)
{
result["success"] = false;
if (!string.IsNullOrEmpty(ErrorMessage))
{
result["error"] = ErrorMessage;
}
}
return result;
}
internal static AwakeStatusPayload FromSettings(AwakeSettings settings, string summary)
{
var payload = new AwakeStatusPayload
{
Mode = settings.Properties.Mode.ToString().ToLowerInvariant(),
Summary = summary,
};
// Only include properties relevant to the current mode
if (settings.Properties.Mode != AwakeMode.PASSIVE)
{
payload.KeepDisplayOn = settings.Properties.KeepDisplayOn;
}
if (settings.Properties.Mode == AwakeMode.TIMED || settings.Properties.Mode == AwakeMode.EXPIRABLE)
{
payload.IntervalHours = settings.Properties.IntervalHours;
payload.IntervalMinutes = settings.Properties.IntervalMinutes;
payload.ExpirationDateTime = settings.Properties.ExpirationDateTime.ToString("O");
}
return payload;
}
internal static AwakeStatusPayload CreateInactive()
{
return new AwakeStatusPayload
{
Mode = "inactive",
Summary = "PowerToys Awake is not running because PowerToys is not active.",
};
}
internal static AwakeStatusPayload CreateUnknownActive()
{
return new AwakeStatusPayload
{
Mode = "unknown",
Summary = "An Awake process is currently running, but its configuration cannot be determined. To terminate the existing process and start with new settings, use force=true.",
};
}
internal static AwakeStatusPayload CreateError(string errorMessage, AwakeSettings? settings = null)
{
var payload = new AwakeStatusPayload
{
Success = false,
ErrorMessage = errorMessage,
};
if (settings != null)
{
payload.Mode = settings.Properties.Mode.ToString().ToLowerInvariant();
// Only include properties relevant to the current mode
if (settings.Properties.Mode != AwakeMode.PASSIVE)
{
payload.KeepDisplayOn = settings.Properties.KeepDisplayOn;
}
if (settings.Properties.Mode == AwakeMode.TIMED || settings.Properties.Mode == AwakeMode.EXPIRABLE)
{
payload.IntervalHours = settings.Properties.IntervalHours;
payload.IntervalMinutes = settings.Properties.IntervalMinutes;
payload.ExpirationDateTime = settings.Properties.ExpirationDateTime.ToString("O");
}
payload.Summary = "An Awake session is already active with the current settings. To override and change the configuration, use force=true.";
}
else
{
payload.Mode = "unknown";
payload.Summary = "An Awake process is currently running. To terminate the existing process and start with new settings, use force=true.";
}
return payload;
}
}
}
}

View File

@@ -36,7 +36,7 @@
</Capabilities>
<Applications>
<Application Id="PowerToys.OCR" Executable="PowerToys.PowerOCR.exe" EntryPoint="Windows.FullTrustApplication">
<Application Id="PowerToys.OCR" Executable="PowerToys.PowerOCR.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements
DisplayName="PowerToys.OCR"
Description="PowerToys OCR Module"
@@ -45,7 +45,7 @@
Square44x44Logo="Images\Square44x44Logo.png">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.SettingsUI" Executable="WinUI3Apps\PowerToys.Settings.exe" EntryPoint="Windows.FullTrustApplication">
<Application Id="PowerToys.SettingsUI" Executable="PowerToys.Settings.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements
DisplayName="PowerToys.SettingsUI"
Description="PowerToys Settings UI"
@@ -54,7 +54,7 @@
Square44x44Logo="Images\Square44x44Logo.png">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.ImageResizerUI" Executable="WinUI3Apps\PowerToys.ImageResizer.exe" EntryPoint="Windows.FullTrustApplication">
<Application Id="PowerToys.ImageResizerUI" Executable="WinUI3Apps\PowerToys.ImageResizer.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements
DisplayName="PowerToys.ImageResizer"
Description="PowerToys Image Resizer UI"
@@ -63,5 +63,28 @@
Square44x44Logo="Images\Square44x44Logo.png">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.McpServer" Executable="PowerToys.McpServer.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements
AppListEntry="none"
DisplayName="PowerToys.McpServer"
Description="PowerToys MCP Server"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
</uap:VisualElements>
<Extensions>
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension
Name="com.microsoft.windows.ai.mcpServer"
Id="PowerToys.McpServer"
DisplayName="PowerToys MCP Server"
PublicFolder="Assets">
<uap3:Properties>
<Registration>mcpServerConfig.json</Registration>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
</Extensions>
</Application>
</Applications>
</Package>

View File

@@ -0,0 +1,18 @@
{
"manifest_version": "0.1",
"name": "PowerToys-McpServer",
"version": "1.0.0",
"description": "PowerToys McpServer",
"author": {
"name": "Microsoft"
},
"server": {
"type": "binary",
"entry_point": "PowerToys.McpServer.exe",
"mcp_config": {
"command": "PowerToys.McpServer.exe",
"args": [
]
}
}
}

View File

@@ -12,8 +12,7 @@ Param(
[switch]$Clean,
[switch]$ForceCert,
[switch]$NoSign,
[switch]$CIBuild
[switch]$NoSign
)
# PowerToys sparse packaging helper.
@@ -23,7 +22,7 @@ Param(
$ErrorActionPreference = 'Stop'
$isCIBuild = $false
if ($CIBuild.IsPresent) {
if ($NoSign.IsPresent) {
$isCIBuild = $true
} elseif ($env:CIBuild) {
$isCIBuild = $env:CIBuild -ieq 'true'
@@ -292,6 +291,7 @@ try {
$essentialFiles = @(
"AppxManifest.xml"
"Images\*"
"Assets\*"
)
foreach ($filePattern in $essentialFiles) {
@@ -310,7 +310,11 @@ try {
$sourceDir = $sourcePath.TrimEnd('\*')
$targetDir = Join-Path $stagingDir (Split-Path $relativePath.TrimEnd('\*') -Parent)
if (Test-Path $sourceDir) {
Copy-Item -Path "$sourceDir\*" -Destination $targetDir -Force -ErrorAction SilentlyContinue
$targetSubDir = Join-Path $stagingDir ($relativePath.TrimEnd('\*'))
if (-not (Test-Path $targetSubDir)) {
New-Item -ItemType Directory -Path $targetSubDir -Force | Out-Null
}
Copy-Item -Path "$sourceDir\*" -Destination $targetSubDir -Force -ErrorAction SilentlyContinue
}
} else {
# Copy single file

View File

@@ -2,22 +2,20 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- CI Build Configuration -->
<PropertyGroup Condition="'$(CIBuild)'=='true'">
<PropertyGroup Condition="'$(CIBuild)'=='true' and '$(ForceSign)' != 'true'">
<ForceCIPackaging>true</ForceCIPackaging>
<NoSignCI>true</NoSignCI>
<EffectiveCIBuild>true</EffectiveCIBuild>
</PropertyGroup>
<!-- Target to generate sparse MSIX package -->
<Target Name="GenerateSparsePackage" BeforeTargets="PrepareForBuild">
<!-- Use NoSign only for CI builds to avoid certificate issues on hosted agents -->
<PropertyGroup>
<NoSignParam Condition="'$(NoSignCI)' == 'true'">-NoSign</NoSignParam>
<NoSignParam Condition="'$(NoSignCI)' != 'true'"></NoSignParam>
<CIBuildParam Condition="'$(CIBuild)' == 'true'">-CIBuild</CIBuildParam>
<CIBuildParam Condition="'$(CIBuild)' != 'true'"></CIBuildParam>
<NoSignParam Condition="'$(EffectiveCIBuild)' == 'true'">-NoSign</NoSignParam>
<NoSignParam Condition="'$(EffectiveCIBuild)' != 'true'"></NoSignParam>
</PropertyGroup>
<Exec Command="pwsh -NonInteractive -ExecutionPolicy Bypass -File &quot;$(MSBuildThisFileDirectory)BuildSparsePackage.ps1&quot; -Platform $(Platform) -Configuration $(Configuration) $(NoSignParam) $(CIBuildParam)"
<Exec Command="pwsh -NonInteractive -ExecutionPolicy Bypass -File &quot;$(MSBuildThisFileDirectory)BuildSparsePackage.ps1&quot; -Platform $(Platform) -Configuration $(Configuration) $(NoSignParam)"
ContinueOnError="false"
WorkingDirectory="$(MSBuildThisFileDirectory)" />
</Target>
@@ -112,6 +110,12 @@
</Image>
</ItemGroup>
<ItemGroup>
<None Include="Assets\mcpServerConfig.json">
<Filter>Assets</Filter>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -5,11 +5,18 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>png;jpg;jpeg;gif;bmp;ico</Extensions>
</Filter>
<Filter Include="Assets">
<UniqueIdentifier>{B3E94A82-1F2C-4D3E-A5F6-789ABC012DEF}</UniqueIdentifier>
<Extensions>json;xml;txt</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="AppxManifest.xml" />
<None Include="BuildSparsePackage.ps1" />
<None Include="BuildSparsePackage.cmd" />
<None Include="Assets\mcpServerConfig.json">
<Filter>Assets</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Image Include="Images\Square150x150Logo.png">

View File

@@ -9,6 +9,12 @@
<RootNamespace>CalculatorEngineCommon</RootNamespace>
<AppxPackage>false</AppxPackage>
</PropertyGroup>
<!-- BEGIN common.build.pre.props -->
<PropertyGroup Label="Configuration">
<EnableHybridCRT>true</EnableHybridCRT>
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
</PropertyGroup>
<!-- END common.build.pre.props -->
<!-- BEGIN cppwinrt.build.pre.props -->
<PropertyGroup Label="Globals">
<CppWinRTEnabled>true</CppWinRTEnabled>
@@ -19,9 +25,11 @@
</PropertyGroup>
<PropertyGroup>
<MinimalCoreWin>true</MinimalCoreWin>
<AppContainerApplication>false</AppContainerApplication>
<AppContainerApplication>true</AppContainerApplication>
<WindowsStoreApp>true</WindowsStoreApp>
<ApplicationType>Windows Store</ApplicationType>
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference>
<!-- The SDK reference breaks the Hybrid CRT -->
</PropertyGroup>
<PropertyGroup>
<!-- We have to use the Desktop platform for Hybrid CRT to work. -->
@@ -140,5 +148,43 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target> <!-- END common.build.post.props -->
</Target>
<!-- BEGIN common.build.post.props -->
<!--
The Hybrid CRT model statically links the runtime and STL and dynamically
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
WinAppSDK asserts that this is "supported according to the CRT maintainer."
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
-->
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- END common.build.post.props -->
</Project>

View File

@@ -112,10 +112,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredCursorWrapEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCursorWrapEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
@@ -196,38 +192,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOnlineAIModelsValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureAIInferenceValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureAIInferenceValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteMistralValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteMistralValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteGoogleValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteGoogleValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAnthropicValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAnthropicValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOllamaValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOllamaValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteFoundryLocalValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteFoundryLocalValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredNewPlusEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusEnabledValue());

View File

@@ -35,7 +35,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
@@ -55,14 +54,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAnthropicValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -38,7 +38,6 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
@@ -59,14 +58,6 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAnthropicValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -66,5 +66,11 @@ namespace PowerToys.GPOWrapperProjection
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredWorkspacesEnabledValue();
}
public static GpoRuleConfigured GetConfiguredMcpEnabledValue()
{
// MCP doesn't have GPO support yet, always return NotConfigured
return GpoRuleConfigured.NotConfigured;
}
}
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace LanguageModelProvider;
internal static class AppUtils
{
public static string GetThemeAssetSuffix()
{
// Default suffix for assets that are theme-agnostic today.
return string.Empty;
}
}

View File

@@ -2,8 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.AI.Foundry.Local;
using System.Globalization;
using System.Text;
using System.Text.Json;
namespace LanguageModelProvider.FoundryLocal;
@@ -11,68 +12,53 @@ internal sealed class FoundryClient
{
public static async Task<FoundryClient?> CreateAsync()
{
try
var serviceManager = FoundryServiceManager.TryCreate();
if (serviceManager is null)
{
Logger.LogInfo("[FoundryClient] Creating Foundry Local client");
var manager = new FoundryLocalManager();
// Check if service is already running
if (manager.IsServiceRunning)
{
Logger.LogInfo("[FoundryClient] Foundry service is already running");
return new FoundryClient(manager);
}
// Start the service using SDK's method
Logger.LogInfo("[FoundryClient] Starting Foundry service using manager.StartServiceAsync()");
await manager.StartServiceAsync().ConfigureAwait(false);
Logger.LogInfo("[FoundryClient] Foundry service started successfully");
return new FoundryClient(manager);
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error creating client: {ex.Message}");
if (ex.InnerException != null)
{
Logger.LogError($"[FoundryClient] Inner exception: {ex.InnerException.Message}");
}
return null;
}
if (!await serviceManager.IsRunning().ConfigureAwait(false))
{
if (!await serviceManager.StartService().ConfigureAwait(false))
{
return null;
}
}
var serviceUrl = await serviceManager.GetServiceUrl().ConfigureAwait(false);
if (string.IsNullOrEmpty(serviceUrl))
{
return null;
}
var serviceUri = new Uri(serviceUrl, UriKind.Absolute);
var baseAddress = serviceUri.AbsoluteUri.EndsWith('/')
? serviceUri
: new Uri(serviceUri, "/");
var httpClient = new HttpClient
{
BaseAddress = baseAddress,
Timeout = TimeSpan.FromHours(2),
};
var assemblyVersion = typeof(FoundryClient).Assembly.GetName().Version?.ToString() ?? "unknown";
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd($"foundry-local-cs-sdk/{assemblyVersion}");
return new FoundryClient(serviceManager, httpClient);
}
private readonly FoundryLocalManager _foundryManager;
public FoundryServiceManager ServiceManager { get; }
private readonly HttpClient _httpClient;
private readonly List<FoundryCatalogModel> _catalogModels = [];
private FoundryClient(FoundryLocalManager foundryManager)
private FoundryClient(FoundryServiceManager serviceManager, HttpClient httpClient)
{
_foundryManager = foundryManager;
}
public Task<string?> GetServiceUrl()
{
try
{
return Task.FromResult(_foundryManager.Endpoint?.ToString());
}
catch
{
return Task.FromResult<string?>(null);
}
}
public Uri? GetServiceUri()
{
try
{
return _foundryManager.ServiceUri;
}
catch
{
return null;
}
ServiceManager = serviceManager;
_httpClient = httpClient;
}
public async Task<List<FoundryCatalogModel>> ListCatalogModels()
@@ -84,39 +70,20 @@ internal sealed class FoundryClient
try
{
Logger.LogInfo("[FoundryClient] Listing catalog models");
var models = await _foundryManager.ListCatalogModelsAsync().ConfigureAwait(false);
var response = await _httpClient.GetAsync("/foundry/list").ConfigureAwait(false);
response.EnsureSuccessStatusCode();
if (models != null)
var models = await JsonSerializer.DeserializeAsync(
response.Content.ReadAsStream(),
FoundryJsonContext.Default.ListFoundryCatalogModel).ConfigureAwait(false);
if (models is { Count: > 0 })
{
foreach (var model in models)
{
_catalogModels.Add(new FoundryCatalogModel
{
Name = model.ModelId ?? string.Empty,
DisplayName = model.DisplayName ?? string.Empty,
ProviderType = model.ProviderType ?? string.Empty,
Uri = model.Uri ?? string.Empty,
Version = model.Version ?? string.Empty,
ModelType = model.ModelType ?? string.Empty,
Publisher = model.Publisher ?? string.Empty,
Task = model.Task ?? string.Empty,
FileSizeMb = model.FileSizeMb,
Alias = model.Alias ?? string.Empty,
License = model.License ?? string.Empty,
LicenseDescription = model.LicenseDescription ?? string.Empty,
ParentModelUri = model.ParentModelUri ?? string.Empty,
SupportsToolCalling = model.SupportsToolCalling,
});
}
Logger.LogInfo($"[FoundryClient] Found {_catalogModels.Count} catalog models");
models.ForEach(_catalogModels.Add);
}
}
catch (Exception ex)
catch
{
Logger.LogError($"[FoundryClient] Error listing catalog models: {ex.Message}");
// Surfacing errors here prevents listing other providers; swallow and return cached list instead.
}
@@ -125,84 +92,138 @@ internal sealed class FoundryClient
public async Task<List<FoundryCachedModel>> ListCachedModels()
{
try
var response = await _httpClient.GetAsync("/openai/models").ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var catalogModels = await ListCatalogModels().ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var modelIds = content
.Trim('[', ']')
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Select(id => id.Trim('"'));
List<FoundryCachedModel> models = [];
foreach (var id in modelIds)
{
Logger.LogInfo("[FoundryClient] Listing cached models");
var cachedModels = await _foundryManager.ListCachedModelsAsync().ConfigureAwait(false);
var catalogModels = await ListCatalogModels().ConfigureAwait(false);
List<FoundryCachedModel> models = [];
foreach (var model in cachedModels)
{
var catalogModel = catalogModels.FirstOrDefault(m => m.Name == model.ModelId);
var alias = catalogModel?.Alias ?? model.Alias;
models.Add(new FoundryCachedModel(model.ModelId ?? string.Empty, alias));
}
Logger.LogInfo($"[FoundryClient] Found {models.Count} cached models");
return models;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error listing cached models: {ex.Message}");
return [];
var model = catalogModels.FirstOrDefault(m => m.Name == id);
models.Add(model != null ? new FoundryCachedModel(id, model.Alias) : new FoundryCachedModel(id, null));
}
return models;
}
public async Task<bool> IsModelLoaded(string modelId)
public async Task<FoundryDownloadResult> DownloadModel(FoundryCatalogModel model, IProgress<float>? progress, CancellationToken cancellationToken = default)
{
try
{
var loadedModels = await _foundryManager.ListLoadedModelsAsync().ConfigureAwait(false);
var isLoaded = loadedModels.Any(m => m.ModelId == modelId);
Logger.LogInfo($"[FoundryClient] IsModelLoaded({modelId}): {isLoaded}");
Logger.LogInfo($"[FoundryClient] Loaded models: {string.Join(", ", loadedModels.Select(m => m.ModelId))}");
return isLoaded;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] IsModelLoaded exception: {ex.Message}");
return false;
}
}
var models = await ListCachedModels().ConfigureAwait(false);
public async Task<bool> EnsureModelLoaded(string modelId)
{
try
if (models.Any(m => m.Name == model.Name))
{
Logger.LogInfo($"[FoundryClient] EnsureModelLoaded called with: {modelId}");
return new(true, "Model already downloaded");
}
// Check if already loaded
if (await IsModelLoaded(modelId).ConfigureAwait(false))
return await Task.Run(
async () =>
{
Logger.LogInfo($"[FoundryClient] Model already loaded: {modelId}");
return true;
}
try
{
var providerType = model.ProviderType.EndsWith("Local", StringComparison.OrdinalIgnoreCase)
? model.ProviderType
: $"{model.ProviderType}Local";
// Check if model exists in cache
var cachedModels = await ListCachedModels().ConfigureAwait(false);
Logger.LogInfo($"[FoundryClient] Cached models: {string.Join(", ", cachedModels.Select(m => m.Name))}");
var downloadRequest = new FoundryDownloadBody
{
Model = new FoundryModelDownload
{
Name = model.Name,
Uri = model.Uri,
Publisher = model.Publisher,
ProviderType = providerType,
PromptTemplate = model.PromptTemplate,
},
Token = string.Empty,
IgnorePipeReport = true,
};
if (!cachedModels.Any(m => m.Name == modelId))
{
Logger.LogWarning($"[FoundryClient] Model not found in cache: {modelId}");
return false;
}
var downloadBodyContext = FoundryJsonContext.Default.FoundryDownloadBody;
string body = JsonSerializer.Serialize(downloadRequest, downloadBodyContext);
// Load the model
Logger.LogInfo($"[FoundryClient] Loading model: {modelId}");
await _foundryManager.LoadModelAsync(modelId).ConfigureAwait(false);
using var request = new HttpRequestMessage(HttpMethod.Post, "/openai/download")
{
Content = new StringContent(body, Encoding.UTF8, "application/json"),
};
// Verify it's loaded
var loaded = await IsModelLoaded(modelId).ConfigureAwait(false);
Logger.LogInfo($"[FoundryClient] Model load result: {loaded}");
return loaded;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] EnsureModelLoaded exception: {ex.Message}");
return false;
}
using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
using var reader = new StreamReader(stream);
StringBuilder jsonBuilder = new();
var collectingJson = false;
var completed = false;
while (!completed && (await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false)) is string line)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
if (line.StartsWith("Total", StringComparison.CurrentCultureIgnoreCase) &&
line.Contains("Downloading", StringComparison.OrdinalIgnoreCase) &&
line.Contains('%'))
{
var percentStr = line.Split('%')[0].Split(' ').Last();
if (double.TryParse(percentStr, NumberStyles.Float, CultureInfo.CurrentCulture, out var percentage))
{
progress?.Report((float)(percentage / 100));
}
}
else if (line.Contains("[DONE]", StringComparison.OrdinalIgnoreCase) ||
line.Contains("All Completed", StringComparison.OrdinalIgnoreCase))
{
collectingJson = true;
}
else if (collectingJson && line.TrimStart().StartsWith('{'))
{
jsonBuilder.AppendLine(line);
}
else if (collectingJson && jsonBuilder.Length > 0)
{
jsonBuilder.AppendLine(line);
if (line.Trim() == "}")
{
completed = true;
}
}
}
var downloadResultContext = FoundryJsonContext.Default.FoundryDownloadResult;
var jsonPayload = jsonBuilder.Length > 0 ? jsonBuilder.ToString() : null;
if (jsonPayload is null)
{
return new FoundryDownloadResult(false, "No completion response received from server.");
}
try
{
return JsonSerializer.Deserialize(jsonPayload, downloadResultContext)
?? new FoundryDownloadResult(false, "Failed to parse completion response.");
}
catch (JsonException ex)
{
return new FoundryDownloadResult(false, $"Failed to parse completion response: {ex.Message}");
}
}
catch (Exception e)
{
return new FoundryDownloadResult(false, e.Message);
}
},
cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed class FoundryDownloadBody
{
[JsonPropertyName("Model")]
public required FoundryModelDownload Model { get; init; }
[JsonPropertyName("token")]
public required string Token { get; init; }
[JsonPropertyName("IgnorePipeReport")]
public required bool IgnorePipeReport { get; init; }
}

View File

@@ -2,6 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
namespace LanguageModelProvider.FoundryLocal;
public record ReloadFinishedMessage();
internal sealed record FoundryDownloadResult(bool Success, string? ErrorMessage);

View File

@@ -12,6 +12,9 @@ namespace LanguageModelProvider.FoundryLocal;
WriteIndented = false)]
[JsonSerializable(typeof(FoundryCatalogModel))]
[JsonSerializable(typeof(List<FoundryCatalogModel>))]
[JsonSerializable(typeof(FoundryDownloadResult))]
[JsonSerializable(typeof(FoundryModelDownload))]
[JsonSerializable(typeof(FoundryDownloadBody))]
internal sealed partial class FoundryJsonContext : JsonSerializerContext
{
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed class FoundryModelDownload
{
[JsonPropertyName("Name")]
public required string Name { get; init; }
[JsonPropertyName("Uri")]
public required string Uri { get; init; }
[JsonPropertyName("Publisher")]
public required string Publisher { get; init; }
[JsonPropertyName("ProviderType")]
public required string ProviderType { get; init; }
[JsonPropertyName("PromptTemplate")]
public required PromptTemplate? PromptTemplate { get; init; }
}

View File

@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace LanguageModelProvider.FoundryLocal;
internal sealed class FoundryServiceManager
{
public static FoundryServiceManager? TryCreate()
{
return IsAvailable() ? new FoundryServiceManager() : null;
}
private static bool IsAvailable()
{
using var process = new Process();
process.StartInfo.FileName = "where";
process.StartInfo.Arguments = "foundry";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
return process.ExitCode == 0;
}
private static string? GetUrl(string output)
{
var match = Regex.Match(output, @"https?:\/\/[^\/]+:\d+");
return match.Success ? match.Value : null;
}
public async Task<string?> GetServiceUrl()
{
var status = await Utils.RunFoundryWithArguments("service status").ConfigureAwait(false);
if (status.ExitCode != 0 || string.IsNullOrWhiteSpace(status.Output))
{
return null;
}
return GetUrl(status.Output);
}
public async Task<bool> IsRunning()
{
var url = await GetServiceUrl().ConfigureAwait(false);
return url is not null;
}
public async Task<bool> StartService(int maxWaitSeconds = 30)
{
if (await IsRunning().ConfigureAwait(false))
{
return true;
}
// Start foundry service (fire-and-forget, don't wait for the process to exit)
_ = Task.Run(() => Utils.RunFoundryWithArguments("service start"));
// Poll to check if service is running
int elapsedSeconds = 0;
while (elapsedSeconds < maxWaitSeconds)
{
await Task.Delay(1000).ConfigureAwait(false);
elapsedSeconds++;
if (await IsRunning().ConfigureAwait(false))
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace LanguageModelProvider.FoundryLocal;
internal static class Utils
{
public static async Task<(string? Output, string? Error, int ExitCode)> RunFoundryWithArguments(string arguments)
{
try
{
using var process = new Process();
process.StartInfo.FileName = "foundry";
process.StartInfo.Arguments = arguments;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
string? output = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
string? error = await process.StandardError.ReadToEndAsync().ConfigureAwait(false);
await process.WaitForExitAsync().ConfigureAwait(false);
return (output, error, process.ExitCode);
}
catch
{
return (null, null, -1);
}
}
}

View File

@@ -2,9 +2,13 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LanguageModelProvider.FoundryLocal;
using ManagedCommon;
using Microsoft.Extensions.AI;
using OpenAI;
@@ -13,6 +17,7 @@ namespace LanguageModelProvider;
public sealed class FoundryLocalModelProvider : ILanguageModelProvider
{
private IEnumerable<ModelDetails>? _downloadedModels;
private IEnumerable<ModelDetails>? _catalogModels;
private FoundryClient? _foundryManager;
private string? _serviceUrl;
@@ -20,72 +25,46 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
public string Name => "FoundryLocal";
public HardwareAccelerator ModelHardwareAccelerator => HardwareAccelerator.FOUNDRYLOCAL;
public string ProviderDescription => "The model will run locally via Foundry Local";
public string UrlPrefix => "fl://";
public string Icon => $"fl{AppUtils.GetThemeAssetSuffix()}.svg";
public string Url => _serviceUrl ?? string.Empty;
public string GetDetailsUrl(ModelDetails details)
{
throw new NotImplementedException();
}
public IChatClient? GetIChatClient(string url)
{
try
{
Logger.LogInfo($"[FoundryLocal] GetIChatClient called with url: {url}");
InitializeAsync().GetAwaiter().GetResult();
}
catch (Exception ex)
catch
{
Logger.LogError($"[FoundryLocal] Failed to initialize: {ex.Message}");
return null;
}
if (string.IsNullOrWhiteSpace(_serviceUrl) || _foundryManager == null)
if (string.IsNullOrWhiteSpace(_serviceUrl))
{
Logger.LogError("[FoundryLocal] Service URL or manager is null");
return null;
}
// Extract model ID from URL (format: fl://modelname)
var modelId = url.Replace(UrlPrefix, string.Empty).Trim('/');
var modelId = url.Split('/').LastOrDefault();
if (string.IsNullOrWhiteSpace(modelId))
{
Logger.LogError("[FoundryLocal] Model ID is empty after extraction");
return null;
}
Logger.LogInfo($"[FoundryLocal] Extracted model ID: {modelId}");
// Ensure the model is loaded before returning chat client
try
{
var isLoaded = _foundryManager.EnsureModelLoaded(modelId).GetAwaiter().GetResult();
if (!isLoaded)
{
Logger.LogError($"[FoundryLocal] Failed to load model: {modelId}");
return null;
}
Logger.LogInfo($"[FoundryLocal] Model is loaded: {modelId}");
}
catch (Exception ex)
{
Logger.LogError($"[FoundryLocal] Exception ensuring model loaded: {ex.Message}");
return null;
}
// Use ServiceUri instead of Endpoint since Endpoint already includes /v1
var baseUri = _foundryManager.GetServiceUri();
if (baseUri == null)
{
Logger.LogError("[FoundryLocal] Service URI is null");
return null;
}
var endpointUri = new Uri($"{baseUri.ToString().TrimEnd('/')}/v1");
Logger.LogInfo($"[FoundryLocal] Creating OpenAI client with endpoint: {endpointUri}");
Logger.LogInfo($"[FoundryLocal] Model ID for chat client: {modelId}");
return new OpenAIClient(
new ApiKeyCredential("none"),
new OpenAIClientOptions { Endpoint = endpointUri })
new OpenAIClientOptions { Endpoint = new Uri($"{_serviceUrl}/v1") })
.GetChatClient(modelId)
.AsIChatClient();
}
@@ -115,16 +94,34 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
{
if (ignoreCached)
{
Logger.LogInfo("[FoundryLocal] Ignoring cached models, resetting");
Reset();
}
await InitializeAsync(cancelationToken);
Logger.LogInfo($"[FoundryLocal] Returning {_downloadedModels?.Count() ?? 0} downloaded models");
return _downloadedModels ?? [];
}
public IEnumerable<ModelDetails> GetAllModelsInCatalog()
{
return _catalogModels ?? [];
}
public async Task<bool> DownloadModel(ModelDetails modelDetails, IProgress<float>? progress, CancellationToken cancellationToken = default)
{
if (_foundryManager == null)
{
return false;
}
if (modelDetails.ProviderModelDetails is not FoundryCatalogModel model)
{
return false;
}
return (await _foundryManager.DownloadModel(model, progress, cancellationToken)).Success;
}
private void Reset()
{
_downloadedModels = null;
@@ -138,26 +135,38 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
return;
}
Logger.LogInfo("[FoundryLocal] Initializing provider");
_foundryManager ??= await FoundryClient.CreateAsync();
if (_foundryManager == null)
{
Logger.LogError("[FoundryLocal] Failed to create Foundry client");
return;
}
_serviceUrl ??= await _foundryManager.GetServiceUrl();
Logger.LogInfo($"[FoundryLocal] Service URL: {_serviceUrl}");
_serviceUrl ??= await _foundryManager.ServiceManager.GetServiceUrl();
if (_catalogModels == null || !_catalogModels.Any())
{
_catalogModels = (await _foundryManager.ListCatalogModels()).Select(ToModelDetails).ToArray();
}
var cachedModels = await _foundryManager.ListCachedModels();
Logger.LogInfo($"[FoundryLocal] Found {cachedModels.Count} cached models");
List<ModelDetails> downloadedModels = [];
foreach (var model in _catalogModels)
{
var cachedModel = cachedModels.FirstOrDefault(m => m.Name == model.Name);
if (cachedModel != default)
{
model.Id = $"{UrlPrefix}{cachedModel.Id}";
downloadedModels.Add(model);
cachedModels.Remove(cachedModel);
}
}
foreach (var model in cachedModels)
{
Logger.LogInfo($"[FoundryLocal] Adding unmatched cached model: {model.Name}");
downloadedModels.Add(new ModelDetails
{
Id = $"fl-{model.Name}",
@@ -171,15 +180,27 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
}
_downloadedModels = downloadedModels;
Logger.LogInfo($"[FoundryLocal] Initialization complete. Total downloaded models: {downloadedModels.Count}");
}
private ModelDetails ToModelDetails(FoundryCatalogModel model)
{
return new ModelDetails
{
Id = $"fl-{model.Name}",
Name = model.Name,
Url = $"{UrlPrefix}{model.Name}",
Description = $"{model.Alias} running locally with Foundry Local",
HardwareAccelerators = [HardwareAccelerator.FOUNDRYLOCAL],
Size = model.FileSizeMb * 1024 * 1024,
SupportedOnQualcomm = true,
License = model.License?.ToLowerInvariant() ?? string.Empty,
ProviderModelDetails = model,
};
}
public async Task<bool> IsAvailable()
{
Logger.LogInfo("[FoundryLocal] Checking availability");
await InitializeAsync();
var available = _foundryManager != null;
Logger.LogInfo($"[FoundryLocal] Available: {available}");
return available;
return _foundryManager != null;
}
}

View File

@@ -12,6 +12,10 @@ public interface ILanguageModelProvider
string UrlPrefix { get; }
string Icon { get; }
HardwareAccelerator ModelHardwareAccelerator { get; }
string ProviderDescription { get; }
Task<IEnumerable<ModelDetails>> GetModelsAsync(bool ignoreCached = false, CancellationToken cancelationToken = default);
@@ -19,4 +23,8 @@ public interface ILanguageModelProvider
IChatClient? GetIChatClient(string url);
string GetIChatClientString(string url);
string GetDetailsUrl(ModelDetails details);
string Url { get; }
}

View File

@@ -10,11 +10,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
<PackageReference Include="Microsoft.AI.Foundry.Local" />
<PackageReference Include="OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
</Project>

View File

@@ -26,16 +26,6 @@ namespace ManagedCommon
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
/// <summary>
/// Gets the path to the log directory for the current version of the app.
/// </summary>
public static string CurrentVersionLogDirectoryPath { get; private set; }
/// <summary>
/// Gets the path to the log directory for the app.
/// </summary>
public static string AppLogDirectoryPath { get; private set; }
/// <summary>
/// Initializes the logger and sets the path for logging.
/// </summary>
@@ -52,9 +42,6 @@ namespace ManagedCommon
Directory.CreateDirectory(versionedPath);
}
AppLogDirectoryPath = basePath;
CurrentVersionLogDirectoryPath = versionedPath;
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
@@ -143,7 +130,7 @@ namespace ManagedCommon
{
exMessage +=
"Inner exception: " + Environment.NewLine +
ex.InnerException.GetType() + " (" + ex.InnerException.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
ex.InnerException.GetType() + " (" + ex.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
}
exMessage +=

View File

@@ -12,7 +12,6 @@ namespace ManagedCommon
ColorPicker,
CmdPal,
CropAndLock,
CursorWrap,
EnvironmentVariables,
FancyZones,
FileLocksmith,

View File

@@ -63,12 +63,14 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>

View File

@@ -59,7 +59,6 @@ struct LogSettings
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
inline const static std::string mouseJumpLoggerName = "mouse-jump";
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
inline const static std::string cursorWrapLoggerName = "cursor-wrap";
inline const static std::string imageResizerLoggerName = "imageresizer";
inline const static std::string powerRenameLoggerName = "powerrename";
inline const static std::string alwaysOnTopLoggerName = "always-on-top";

View File

@@ -46,6 +46,16 @@
<PropertyGroup>
<TargetName>notifications</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>

View File

@@ -3,7 +3,6 @@
#include <Windows.h>
#include <optional>
#include <vector>
#include <string>
namespace powertoys_gpo
{
@@ -52,7 +51,6 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
const std::wstring POLICY_CONFIGURE_ENABLED_CURSOR_WRAP = L"ConfigureEnabledUtilityCursorWrap";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
@@ -84,14 +82,6 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_RUN_AT_STARTUP = L"ConfigureRunAtStartup";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS = L"PowerLauncherAllPluginsEnabledState";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS = L"AllowPowerToysAdvancedPasteOnlineAIModels";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OPENAI = L"AllowAdvancedPasteOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI = L"AllowAdvancedPasteAzureOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE = L"AllowAdvancedPasteAzureAIInference";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_MISTRAL = L"AllowAdvancedPasteMistral";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_GOOGLE = L"AllowAdvancedPasteGoogle";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_ANTHROPIC = L"AllowAdvancedPasteAnthropic";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OLLAMA = L"AllowAdvancedPasteOllama";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL = L"AllowAdvancedPasteFoundryLocal";
const std::wstring POLICY_MWB_CLIPBOARD_SHARING_ENABLED = L"MwbClipboardSharingEnabled";
const std::wstring POLICY_MWB_FILE_TRANSFER_ENABLED = L"MwbFileTransferEnabled";
const std::wstring POLICY_MWB_USE_ORIGINAL_USER_INTERFACE = L"MwbUseOriginalUserInterface";
@@ -411,11 +401,6 @@ namespace powertoys_gpo
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
}
inline gpo_rule_configured_t getConfiguredCursorWrapEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CURSOR_WRAP);
}
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
@@ -590,46 +575,6 @@ namespace powertoys_gpo
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureAIInferenceValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteMistralValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_MISTRAL);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteGoogleValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_GOOGLE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAnthropicValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_ANTHROPIC);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOllamaValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OLLAMA);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteFoundryLocalValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL);
}
inline gpo_rule_configured_t getConfiguredMwbClipboardSharingEnabledValue()
{
return getConfiguredValue(POLICY_MWB_CLIPBOARD_SHARING_ENABLED);

View File

@@ -33,4 +33,9 @@
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
<Exec Command="&quot;$(OutDir)$(AssemblyName).exe&quot; &quot;..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll&quot; $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
</Target>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
<Exec Command="&quot;$(MSBuildToolsPath)\msbuild.exe&quot; PowerToys.sln -p:Configuration=&quot;$(Configuration)&quot; -p:Platform=&quot;x64&quot; -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="..\..\..\" />
</Target>
</Project>

View File

@@ -13,7 +13,7 @@ namespace PowerToys.DSC.Models;
public sealed class DscManifest
{
private const string Schema = "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json";
private const string Executable = @"..\PowerToys.DSC.exe";
private const string Executable = @"PowerToys.DSC.exe";
private readonly string _type;
private readonly string _version;

View File

@@ -40,11 +40,9 @@
</EmbeddedResource>
</ItemGroup>
<!-- Generate the DSC resource JSON files to DSCModules subfolder -->
<!-- Skip generation in CI/CD builds (CIBuild=true) to avoid unnecessary work during pipeline -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(CIBuild)' != 'true'">
<Message Text="Generating DSC resource JSON files to DSCModules subfolder..." Importance="high" />
<MakeDir Directories="$(TargetDir)DSCModules" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)DSCModules&quot;" />
<!-- In debug mode, generate the DSC resource JSON files -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Message Text="Generating DSC resource JSON files inside ..." Importance="high" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)\&quot;" />
</Target>
</Project>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces>
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
</policyNamespaces>
<resources minRequiredRevision="1.18"/><!-- Last changed with PowerToys v0.96.0 -->
<resources minRequiredRevision="1.17"/><!-- Last changed with PowerToys v0.90.0 -->
<supportedOn>
<definitions>
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
@@ -26,7 +26,6 @@
<definition name="SUPPORTED_POWERTOYS_0_88_0" displayName="$(string.SUPPORTED_POWERTOYS_0_88_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_89_0" displayName="$(string.SUPPORTED_POWERTOYS_0_89_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_90_0" displayName="$(string.SUPPORTED_POWERTOYS_0_90_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_96_0" displayName="$(string.SUPPORTED_POWERTOYS_0_96_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1)"/>
</definitions>
</supportedOn>
@@ -615,86 +614,6 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteOpenAI)" explainText="$(string.AllowAdvancedPasteOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteAzureOpenAI)" explainText="$(string.AllowAdvancedPasteAzureOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureAIInference" class="Both" displayName="$(string.AllowAdvancedPasteAzureAIInference)" explainText="$(string.AllowAdvancedPasteAzureAIInferenceDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureAIInference">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteMistral" class="Both" displayName="$(string.AllowAdvancedPasteMistral)" explainText="$(string.AllowAdvancedPasteMistralDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteMistral">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteGoogle" class="Both" displayName="$(string.AllowAdvancedPasteGoogle)" explainText="$(string.AllowAdvancedPasteGoogleDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteGoogle">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAnthropic" class="Both" displayName="$(string.AllowAdvancedPasteAnthropic)" explainText="$(string.AllowAdvancedPasteAnthropicDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAnthropic">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOllama" class="Both" displayName="$(string.AllowAdvancedPasteOllama)" explainText="$(string.AllowAdvancedPasteOllamaDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOllama">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteFoundryLocal" class="Both" displayName="$(string.AllowAdvancedPasteFoundryLocal)" explainText="$(string.AllowAdvancedPasteFoundryLocalDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteFoundryLocal">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="MwbClipboardSharingEnabled" class="Both" displayName="$(string.MwbClipboardSharingEnabled)" explainText="$(string.MwbClipboardSharingEnabledDescription)" key="Software\Policies\PowerToys" valueName="MwbClipboardSharingEnabled">
<parentCategory ref="MouseWithoutBorders" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_83_0" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>PowerToys</displayName>
<description>PowerToys</description>
<resources>
@@ -33,7 +33,6 @@
<string id="SUPPORTED_POWERTOYS_0_88_0">PowerToys version 0.88.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_89_0">PowerToys version 0.89.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_90_0">PowerToys version 0.90.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_96_0">PowerToys version 0.96.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1">From PowerToys version 0.64.0 until PowerToys version 0.87.1</string>
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.
@@ -292,54 +291,6 @@ If you don't configure this policy, the user will be able to control the setting
<string id="ConfigureEnabledUtilityFileExplorerQOIPreview">QOI file preview: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFileExplorerQOIThumbnails">QOI file thumbnail: Configure enabled state</string>
<string id="AllowPowerToysAdvancedPasteOnlineAIModels">Allow using online AI models</string>
<string id="AllowAdvancedPasteOpenAI">Advanced Paste: Allow OpenAI endpoint</string>
<string id="AllowAdvancedPasteOpenAIDescription">This policy controls whether users can use the OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureOpenAI">Advanced Paste: Allow Azure OpenAI endpoint</string>
<string id="AllowAdvancedPasteAzureOpenAIDescription">This policy controls whether users can use the Azure OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use Azure OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureAIInference">Advanced Paste: Allow Azure AI Inference endpoint</string>
<string id="AllowAdvancedPasteAzureAIInferenceDescription">This policy controls whether users can use the Azure AI Inference endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure AI Inference as their AI provider.
If you disable this policy, users will not be able to select or use Azure AI Inference endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteMistral">Advanced Paste: Allow Mistral endpoint</string>
<string id="AllowAdvancedPasteMistralDescription">This policy controls whether users can use the Mistral AI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Mistral as their AI provider.
If you disable this policy, users will not be able to select or use Mistral endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteGoogle">Advanced Paste: Allow Google endpoint</string>
<string id="AllowAdvancedPasteGoogleDescription">This policy controls whether users can use the Google (Gemini) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Google as their AI provider.
If you disable this policy, users will not be able to select or use Google endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAnthropic">Advanced Paste: Allow Anthropic endpoint</string>
<string id="AllowAdvancedPasteAnthropicDescription">This policy controls whether users can use the Anthropic (Claude) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Anthropic as their AI provider.
If you disable this policy, users will not be able to select or use Anthropic endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteOllama">Advanced Paste: Allow Ollama endpoint</string>
<string id="AllowAdvancedPasteOllamaDescription">This policy controls whether users can use the Ollama local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Ollama as their AI provider.
If you disable this policy, users will not be able to select or use Ollama endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteFoundryLocal">Advanced Paste: Allow Foundry Local endpoint</string>
<string id="AllowAdvancedPasteFoundryLocalDescription">This policy controls whether users can use the Foundry Local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Foundry Local as their AI provider.
If you disable this policy, users will not be able to select or use Foundry Local endpoint in Advanced Paste settings.</string>
<string id="MwbClipboardSharingEnabled">Clipboard sharing enabled</string>
<string id="MwbFileTransferEnabled">File transfer enabled</string>
<string id="MwbUseOriginalUserInterface">Original user interface is available</string>

View File

@@ -1,66 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using AdvancedPaste.Settings;
using Microsoft.PowerToys.Settings.UI.Library;
namespace AdvancedPaste.UnitTests.Mocks;
/// <summary>
/// Minimal <see cref="IUserSettings"/> implementation used by integration tests that
/// need to construct the runtime Advanced Paste services.
/// </summary>
internal sealed class IntegrationTestUserSettings : IUserSettings
{
private readonly PasteAIConfiguration _configuration;
private readonly IReadOnlyList<AdvancedPasteCustomAction> _customActions;
private readonly IReadOnlyList<PasteFormats> _additionalActions;
public IntegrationTestUserSettings()
{
var provider = new PasteAIProviderDefinition
{
Id = "integration-openai",
EnableAdvancedAI = true,
ServiceTypeKind = AIServiceType.OpenAI,
ModelName = "gpt-4o",
ModerationEnabled = true,
};
_configuration = new PasteAIConfiguration
{
ActiveProviderId = provider.Id,
Providers = new ObservableCollection<PasteAIProviderDefinition> { provider },
};
_customActions = Array.Empty<AdvancedPasteCustomAction>();
_additionalActions = Array.Empty<PasteFormats>();
}
public bool IsAIEnabled => true;
public bool ShowCustomPreview => false;
public bool CloseAfterLosingFocus => false;
public IReadOnlyList<AdvancedPasteCustomAction> CustomActions => _customActions;
public IReadOnlyList<PasteFormats> AdditionalActions => _additionalActions;
public PasteAIConfiguration PasteAIConfiguration => _configuration;
public event EventHandler Changed;
public Task SetActiveAIProviderAsync(string providerId)
{
_configuration.ActiveProviderId = providerId ?? string.Empty;
Changed?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
}

View File

@@ -13,8 +13,6 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.UnitTests.Mocks;
using ManagedCommon;
@@ -81,9 +79,7 @@ public sealed class AIServiceBatchIntegrationTests
Assert.IsTrue(results.Count <= inputs.Count);
CollectionAssert.AreEqual(results.Select(result => result.ToInput()).ToList(), inputs.Take(results.Count).ToList());
#pragma warning disable IL2026, IL3050 // The tests rely on runtime JSON serialization for ad-hoc data files.
async Task WriteResultsAsync() => await File.WriteAllTextAsync(resultsFile, JsonSerializer.Serialize(results, SerializerOptions));
#pragma warning restore IL2026, IL3050
Logger.LogInfo($"Starting {nameof(TestGenerateBatchResults)}; Count={inputs.Count}, InCache={results.Count}");
@@ -105,12 +101,8 @@ public sealed class AIServiceBatchIntegrationTests
await WriteResultsAsync();
}
private static async Task<List<T>> GetDataListAsync<T>(string filePath)
{
#pragma warning disable IL2026, IL3050 // Tests only run locally and can depend on runtime JSON serialization.
return File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
#pragma warning restore IL2026, IL3050
}
private static async Task<List<T>> GetDataListAsync<T>(string filePath) =>
File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
private static async Task<string> GetTextOutputAsync(BatchTestInput input, PasteFormats format)
{
@@ -138,35 +130,23 @@ public sealed class AIServiceBatchIntegrationTests
private static async Task<DataPackage> GetOutputDataPackageAsync(BatchTestInput batchTestInput, PasteFormats format)
{
var services = CreateServices();
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
NoOpProgress progress = new();
CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService);
switch (format)
{
case PasteFormats.CustomTextTransformation:
var transformResult = await services.CustomActionTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress);
return DataPackageHelpers.CreateFromText(transformResult.Content ?? string.Empty);
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress));
case PasteFormats.KernelQuery:
var clipboardData = DataPackageHelpers.CreateFromText(batchTestInput.Clipboard).GetView();
return await services.KernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
KernelService kernelService = new(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, customTextTransformService);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
default:
throw new InvalidOperationException($"Unexpected format {format}");
}
}
private static IntegrationTestServices CreateServices()
{
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
ICustomActionTransformService customActionTransformService = new CustomActionTransformService(promptModerationService, providerFactory, credentialsProvider, userSettings);
IKernelService kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
return new IntegrationTestServices(customActionTransformService, kernelService);
}
private readonly record struct IntegrationTestServices(ICustomActionTransformService CustomActionTransformService, IKernelService KernelService);
}

View File

@@ -11,8 +11,6 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.Telemetry;
using AdvancedPaste.UnitTests.Mocks;
@@ -29,19 +27,16 @@ namespace AdvancedPaste.UnitTests.ServicesTests;
public sealed class KernelServiceIntegrationTests : IDisposable
{
private const string StandardImageFile = "image_with_text_example.png";
private IKernelService _kernelService;
private KernelService _kernelService;
private AdvancedPasteEventListener _eventListener;
[TestInitialize]
public void TestInitialize()
{
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
CustomActionTransformService customActionTransformService = new(promptModerationService, providerFactory, credentialsProvider, userSettings);
_kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
_kernelService = new KernelService(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, new CustomTextTransformService(credentialsProvider, promptModerationService));
_eventListener = new();
}

View File

@@ -37,10 +37,22 @@
<None Remove="AdvancedPasteXAML\Controls\PromptBox.xaml" />
<None Remove="AdvancedPasteXAML\Styles\Button.xaml" />
<None Remove="Assets\AdvancedPaste\AIIcon.png" />
<None Remove="Assets\AdvancedPaste\Anthropic.svg" />
<None Remove="Assets\AdvancedPaste\Azure.svg" />
<None Remove="Assets\AdvancedPaste\AzureAI.svg" />
<None Remove="Assets\AdvancedPaste\Bedrock.svg" />
<None Remove="Assets\AdvancedPaste\FoundryLocal.svg" />
<None Remove="Assets\AdvancedPaste\Gemini.svg" />
<None Remove="Assets\AdvancedPaste\Gradient.png" />
<None Remove="AdvancedPasteXAML\Controls\AnimatedContentControl\AnimatedBorderBrush.xaml" />
<None Remove="AdvancedPasteXAML\Views\MainPage.xaml" />
<None Remove="Assets\AdvancedPaste\SemanticKernel.svg" />
<None Remove="Assets\AdvancedPaste\HuggingFace.svg" />
<None Remove="Assets\AdvancedPaste\Mistral.svg" />
<None Remove="Assets\AdvancedPaste\Ollama.svg" />
<None Remove="Assets\AdvancedPaste\Onnx.svg" />
<None Remove="Assets\AdvancedPaste\OpenAI.dark.svg" />
<None Remove="Assets\AdvancedPaste\OpenAI.light.svg" />
<None Remove="Assets\AdvancedPaste\WindowsML.svg" />
</ItemGroup>
<ItemGroup>
@@ -59,17 +71,17 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageReference Include="MessagePack" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Amazon" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.HuggingFace" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.MistralAI" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Amazon" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.HuggingFace" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.MistralAI" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.SemanticKernel" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="System.ClientModel" />
<PackageReference Include="System.ClientModel" />
<PackageReference Include="Microsoft.Windows.Compatibility" />
<PackageReference Include="Microsoft.Windows.CsWin32" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
@@ -139,23 +151,4 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<!-- Share AI Model Provider Icons from Settings.UI to avoid duplication -->
<!-- These icons are included from Settings.UI project -->
<Content Include="..\..\..\settings-ui\Settings.UI\Assets\Settings\Icons\Models\*.svg">
<Link>Assets\Settings\Icons\Models\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- AdvancedPaste specific assets -->
<Content Include="Assets\AdvancedPaste\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\AdvancedPaste\*.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- Keep SemanticKernel.svg as it's specific to AdvancedPaste -->
<Content Include="Assets\AdvancedPaste\SemanticKernel.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -13,7 +13,7 @@
<converters:DateTimeToFriendlyStringConverter x:Key="DateTimeToFriendlyStringConverter" />
<tkconverters:BoolToVisibilityConverter x:Name="BoolToVisibilityConverter" />
</UserControl.Resources>
<Grid ColumnSpacing="12">
<Grid Height="64" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />

View File

@@ -14,13 +14,28 @@
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<LinearGradientBrush x:Name="IntelligentUnderlineGradient" StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Offset="0.0" Color="#FF0078D4" />
<GradientStop Offset="0.42" Color="#FF464FEB" />
<GradientStop Offset="0.87" Color="#FFD660FF" />
<GradientStop Offset="1.0" Color="#FFFEA874" />
</LinearGradientBrush>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<Color x:Key="AccentGradientColor">#65C8F2</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#98EFFE" />
<GradientStop Offset="0.25" Color="#48B1E9" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Color x:Key="AccentGradientColor">#005FB8</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#4992C7" />
<GradientStop Offset="0.25" Color="#1353A0" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Color x:Key="AccentGradientColor">#48B1E9</Color>
<SolidColorBrush x:Key="AccentGradientBrush" Color="{StaticResource AccentGradientColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<x:Double x:Key="ModelSelectorButtonWidth">44</x:Double>
<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
@@ -156,19 +171,6 @@
BorderThickness="{TemplateBinding BorderThickness}"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}" />
<Rectangle
x:Name="FocusHighlighter"
Grid.Row="1"
Grid.RowSpan="1"
Grid.ColumnSpan="4"
Height="2"
Margin="12,0,12,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Fill="{StaticResource IntelligentUnderlineGradient}"
RadiusX="1"
RadiusY="1"
Visibility="Collapsed" />
<Grid Grid.Row="1" Width="{StaticResource ModelSelectorButtonWidth}">
<ProgressRing
Width="20"
@@ -280,10 +282,7 @@
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusHighlighter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,2">
@@ -300,7 +299,7 @@
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderThemeThicknessFocused}" />
</ObjectAnimationUsingKeyFrames>-->
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}" />
</ObjectAnimationUsingKeyFrames>
@@ -542,10 +541,7 @@
Source="{x:Bind ViewModel.ActiveAIProvider?.ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
</DropDownButton.Content>
<DropDownButton.Flyout>
<Flyout
Opened="AIProviderFlyout_Opened"
Placement="Bottom"
ShouldConstrainToRootBounds="False">
<Flyout Placement="Bottom" ShouldConstrainToRootBounds="False">
<Grid
Width="386"
Margin="-4"
@@ -744,8 +740,8 @@
x:Name="LoadingText"
x:Uid="LoadingText"
Grid.Row="1"
Margin="4,4,0,0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
FontWeight="SemiBold"
Foreground="{ThemeResource AccentGradientBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Visibility="Collapsed">
<animations:Implicit.ShowAnimations>

View File

@@ -22,8 +22,6 @@ namespace AdvancedPaste.Controls
{
public OptionsViewModel ViewModel { get; private set; }
private bool _syncingProviderSelection;
public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register(
nameof(PlaceholderText),
typeof(string),
@@ -76,11 +74,6 @@ namespace AdvancedPaste.Controls
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
VisualStateManager.GoToState(this, state, true);
}
if (e.PropertyName is nameof(ViewModel.ActiveAIProvider) or nameof(ViewModel.AIProviders))
{
SyncProviderSelection();
}
}
private void ViewModel_PreviewRequested(object sender, EventArgs e)
@@ -94,7 +87,6 @@ namespace AdvancedPaste.Controls
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
InputTxtBox.Focus(FocusState.Programmatic);
SyncProviderSelection();
}
[RelayCommand]
@@ -134,56 +126,18 @@ namespace AdvancedPaste.Controls
Loader.IsLoading = loading;
}
private void SyncProviderSelection()
{
if (AIProviderListView is null)
{
return;
}
try
{
_syncingProviderSelection = true;
AIProviderListView.SelectedItem = ViewModel.ActiveAIProvider;
}
finally
{
_syncingProviderSelection = false;
}
}
private void AIProviderFlyout_Opened(object sender, object e)
{
SyncProviderSelection();
}
private async void AIProviderListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_syncingProviderSelection)
if (AIProviderListView.SelectedItem is PasteAIProviderDefinition provider)
{
return;
}
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
{
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
}
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
if (AIProviderListView.SelectedItem is not PasteAIProviderDefinition provider)
{
return;
}
if (string.Equals(ViewModel.ActiveAIProvider?.Id, provider.Id, StringComparison.OrdinalIgnoreCase))
{
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
flyout?.Hide();
return;
}
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
{
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
SyncProviderSelection();
}
flyout?.Hide();
}
}
}

View File

@@ -150,7 +150,7 @@
</Grid.RowDefinitions>
<Grid
Margin="8,0,8,16"
Margin="8,8,8,4"
Padding="4"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
@@ -161,7 +161,7 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ClipboardHistoryItemPreviewControl Height="48" ClipboardItem="{x:Bind ViewModel.CurrentClipboardItem, Mode=OneWay}" />
<controls:ClipboardHistoryItemPreviewControl Height="64" ClipboardItem="{x:Bind ViewModel.CurrentClipboardItem, Mode=OneWay}" />
<Button
x:Uid="ClipboardHistoryButton"
Grid.Column="1"
@@ -210,10 +210,7 @@
<ColumnDefinition Width="*" MaxWidth="240" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ClipboardHistoryItemPreviewControl
Height="64"
x:Phase="0"
ClipboardItem="{x:Bind}" />
<controls:ClipboardHistoryItemPreviewControl x:Phase="0" ClipboardItem="{x:Bind}" />
<Button
x:Name="ClipboardHistoryItemMoreOptionsButton"
x:Uid="ClipboardHistoryItemMoreOptionsButton"
@@ -247,57 +244,62 @@
x:Name="CustomFormatTextBox"
x:Uid="CustomFormatTextBox"
Grid.Row="1"
Margin="20,0,20,0"
Margin="20,4,20,0"
x:FieldModifier="public"
IsEnabled="{x:Bind ViewModel.IsCustomAIServiceEnabled, Mode=OneWay}"
TabIndex="0">
<controls:PromptBox.Footer>
<StackPanel Orientation="Horizontal">
<TextBlock
x:Uid="AIMistakeNote"
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<Button
Padding="0"
Style="{StaticResource CaptionTextBlockStyle}">
<Run x:Uid="AIMistakeNote" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</TextBlock>
<TextBlock
Margin="4,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource SubtleButtonStyle}">
<FontIcon FontSize="12" Glyph="&#xE946;" />
<Button.Flyout>
<Flyout>
<StackPanel Spacing="8">
<TextBlock TextWrapping="Wrap">
<Run x:Uid="AIMistakeNote" /><LineBreak /><Run
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="You are using a custom endpoint. Verify all answers." />
</TextBlock>
<StackPanel Orientation="Horizontal" Spacing="8">
<HyperlinkButton
x:Name="TermsHyperlink"
x:Uid="TermsLink"
Padding="0"
FontSize="12"
NavigateUri="{x:Bind ViewModel.TermsLinkUri, Mode=OneWay}"
Visibility="{x:Bind ViewModel.HasTermsLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<HyperlinkButton
x:Name="PrivacyHyperLink"
x:Uid="PrivacyLink"
Padding="0"
FontSize="12"
NavigateUri="{x:Bind ViewModel.PrivacyLinkUri, Mode=OneWay}"
Visibility="{x:Bind ViewModel.HasPrivacyLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
Style="{StaticResource CaptionTextBlockStyle}">
<Hyperlink
x:Name="TermsHyperlink"
NavigateUri="https://openai.com/policies/terms-of-use"
TabIndex="3">
<Run x:Uid="TermsLink" />
</Hyperlink>
<ToolTipService.ToolTip>
<TextBlock Text="https://openai.com/policies/terms-of-use" />
</ToolTipService.ToolTip>
</TextBlock>
<TextBlock
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
ToolTipService.ToolTip="">
<Run x:Uid="AIFooterSeparator" Foreground="{ThemeResource TextFillColorSecondaryBrush}">|</Run>
</TextBlock>
<TextBlock
Margin="0,0,2,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}">
<Hyperlink NavigateUri="https://openai.com/policies/privacy-policy" TabIndex="3">
<Run x:Uid="PrivacyLink" />
</Hyperlink>
<ToolTipService.ToolTip>
<TextBlock Text="https://openai.com/policies/privacy-policy" />
</ToolTipService.ToolTip>
</TextBlock>
</StackPanel>
</controls:PromptBox.Footer>
</controls:PromptBox>
<Grid Grid.Row="2" RowSpacing="4">
<Grid
Grid.Row="2"
Background="{ThemeResource LayerOnAcrylicFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="0,1,0,0"
RowSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="{x:Bind ViewModel.StandardPasteFormats.Count, Mode=OneWay, Converter={StaticResource standardPasteFormatsToHeightConverter}}" />
<RowDefinition Height="Auto" />
@@ -318,6 +320,7 @@
ScrollViewer.VerticalScrollMode="Auto"
SelectionMode="None"
TabIndex="1" />
<Rectangle
Grid.Row="1"
Height="1"

View File

@@ -0,0 +1,10 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1822)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.718 2.34668H12.12L16.5 13.3333H14.098L9.718 2.34668ZM4.87933 2.34668H7.39067L11.7707 13.3333H9.32133L8.426 11.026H3.84467L2.94867 13.3327H0.5L4.88 2.34801L4.87933 2.34668ZM7.634 8.98601L6.13533 5.12468L4.63667 8.98668H7.63333L7.634 8.98601Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2092_1822">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 585 B

View File

@@ -0,0 +1,23 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.05607 1.09062H10.3957L5.89074 14.4385C5.84444 14.5756 5.75629 14.6948 5.6387 14.7792C5.52111 14.8637 5.38 14.9091 5.23524 14.9091H1.85791C1.74822 14.9091 1.64011 14.883 1.54252 14.833C1.44493 14.7829 1.36066 14.7103 1.29669 14.6212C1.23271 14.5322 1.19087 14.4291 1.17462 14.3206C1.15837 14.2122 1.16818 14.1014 1.20324 13.9975L5.40041 1.56129C5.44669 1.42407 5.53485 1.30483 5.65248 1.22037C5.7701 1.1359 5.91126 1.09063 6.05607 1.09062Z" fill="url(#paint0_linear_2092_1811)"/>
<path d="M12.3626 10.0435H5.48096C5.41698 10.0434 5.35447 10.0626 5.30156 10.0986C5.24864 10.1345 5.20779 10.1856 5.18432 10.2451C5.16085 10.3046 5.15584 10.3698 5.16996 10.4322C5.18408 10.4946 5.21666 10.5513 5.26346 10.595L9.68546 14.7223C9.81421 14.8424 9.98373 14.9092 10.1598 14.9091H14.0565L12.3626 10.0435Z" fill="#0078D4"/>
<path d="M6.05617 1.0907C5.90978 1.09014 5.76704 1.1364 5.64881 1.22273C5.53058 1.30906 5.44305 1.43093 5.399 1.57054L1.2085 13.9862C1.17108 14.0905 1.15933 14.2023 1.17425 14.3121C1.18917 14.4219 1.23031 14.5265 1.2942 14.617C1.3581 14.7076 1.44285 14.7814 1.54131 14.8323C1.63976 14.8831 1.74902 14.9095 1.85983 14.9092H5.32433C5.45337 14.8861 5.57397 14.8293 5.67382 14.7443C5.77367 14.6594 5.84919 14.5495 5.89267 14.4259L6.72833 11.963L9.71333 14.7472C9.83842 14.8507 9.99534 14.9079 10.1577 14.9092H14.0398L12.3372 10.0435L7.37367 10.0447L10.4115 1.0907H6.05617Z" fill="url(#paint1_linear_2092_1811)"/>
<path d="M11.5996 1.5607C11.5533 1.4237 11.4653 1.30466 11.3479 1.22034C11.2304 1.13603 11.0895 1.09068 10.9449 1.0907H6.1084C6.25297 1.09071 6.3939 1.13606 6.51135 1.22038C6.62879 1.30469 6.71683 1.42372 6.76307 1.5607L10.9604 13.9974C10.9955 14.1013 11.0053 14.2121 10.9891 14.3206C10.9729 14.4291 10.931 14.5322 10.867 14.6213C10.8031 14.7104 10.7188 14.7831 10.6212 14.8331C10.5236 14.8832 10.4154 14.9094 10.3057 14.9094H15.1424C15.2521 14.9093 15.3602 14.8832 15.4578 14.8331C15.5554 14.783 15.6396 14.7104 15.7036 14.6213C15.7675 14.5321 15.8094 14.4291 15.8256 14.3206C15.8418 14.2121 15.832 14.1013 15.7969 13.9974L11.5996 1.5607Z" fill="url(#paint2_linear_2092_1811)"/>
<defs>
<linearGradient id="paint0_linear_2092_1811" x1="7.63774" y1="2.11462" x2="3.1309" y2="15.429" gradientUnits="userSpaceOnUse">
<stop stop-color="#114A8B"/>
<stop offset="1" stop-color="#0669BC"/>
</linearGradient>
<linearGradient id="paint1_linear_2092_1811" x1="9.04567" y1="8.31954" x2="8.00317" y2="8.67204" gradientUnits="userSpaceOnUse">
<stop stop-opacity="0.3"/>
<stop offset="0.071" stop-opacity="0.2"/>
<stop offset="0.321" stop-opacity="0.1"/>
<stop offset="0.623" stop-opacity="0.05"/>
<stop offset="1" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_2092_1811" x1="8.4729" y1="1.72636" x2="13.4201" y2="14.9065" gradientUnits="userSpaceOnUse">
<stop stop-color="#3CCBF4"/>
<stop offset="1" stop-color="#2892DF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,49 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1818)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3222 0C11.7976 0 12.2189 0.367333 12.3702 0.886C12.5216 1.40467 13.4069 4.61267 13.4069 4.61267V10.9873H10.1982L10.2636 0H11.3222Z" fill="url(#paint0_linear_2092_1818)"/>
<path d="M16.0323 4.97996C16.0323 4.75329 15.849 4.57996 15.6323 4.57996H13.7423C13.1034 4.58049 12.4908 4.83459 12.039 5.28645C11.5873 5.73832 11.3334 6.35101 11.333 6.98996V10.9873H13.6237C14.2624 10.9866 14.8747 10.7325 15.3263 10.2808C15.7779 9.82909 16.0318 9.21667 16.0323 8.57796V4.97996Z" fill="url(#paint1_linear_2092_1818)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3216 1.6754e-05C11.2349 -0.00060392 11.1489 0.0160265 11.0686 0.0489413C10.9883 0.0818561 10.9154 0.130399 10.854 0.191747C10.7927 0.253096 10.7442 0.326027 10.7112 0.406302C10.6783 0.486576 10.6617 0.572592 10.6623 0.65935L10.5976 12.7914C10.5975 13.6423 10.2594 14.4583 9.65765 15.06C9.05595 15.6617 8.23992 15.9998 7.38898 16H1.56631C1.50256 16.0004 1.43966 15.9854 1.3829 15.9564C1.32613 15.9274 1.27717 15.8852 1.24012 15.8333C1.20308 15.7814 1.17903 15.7214 1.17002 15.6583C1.161 15.5952 1.16727 15.5309 1.18831 15.4707L5.85498 2.15002C6.07482 1.5228 6.48378 0.979202 7.02549 0.594138C7.56721 0.209074 8.21502 0.00149836 8.87964 1.6754e-05H11.3323H11.3216Z" fill="url(#paint2_linear_2092_1818)"/>
</g>
<defs>
<linearGradient id="paint0_linear_2092_1818" x1="12.6616" y1="11.2247" x2="9.96091" y2="0.410667" gradientUnits="userSpaceOnUse">
<stop stop-color="#712575"/>
<stop offset="0.09" stop-color="#9A2884"/>
<stop offset="0.18" stop-color="#BF2C92"/>
<stop offset="0.27" stop-color="#DA2E9C"/>
<stop offset="0.34" stop-color="#EB30A2"/>
<stop offset="0.4" stop-color="#F131A5"/>
<stop offset="0.5" stop-color="#EC30A3"/>
<stop offset="0.61" stop-color="#DF2F9E"/>
<stop offset="0.72" stop-color="#C92D96"/>
<stop offset="0.83" stop-color="#AA2A8A"/>
<stop offset="0.95" stop-color="#83267C"/>
<stop offset="1" stop-color="#712575"/>
</linearGradient>
<linearGradient id="paint1_linear_2092_1818" x1="13.6883" y1="0.226623" x2="13.6883" y2="15.4813" gradientUnits="userSpaceOnUse">
<stop stop-color="#DA7ED0"/>
<stop offset="0.08" stop-color="#B17BD5"/>
<stop offset="0.19" stop-color="#8778DB"/>
<stop offset="0.3" stop-color="#6276E1"/>
<stop offset="0.41" stop-color="#4574E5"/>
<stop offset="0.54" stop-color="#2E72E8"/>
<stop offset="0.67" stop-color="#1D71EB"/>
<stop offset="0.81" stop-color="#1471EC"/>
<stop offset="1" stop-color="#1171ED"/>
</linearGradient>
<linearGradient id="paint2_linear_2092_1818" x1="12.769" y1="0.572683" x2="2.65698" y2="16.7887" gradientUnits="userSpaceOnUse">
<stop stop-color="#DA7ED0"/>
<stop offset="0.05" stop-color="#B77BD4"/>
<stop offset="0.11" stop-color="#9079DA"/>
<stop offset="0.18" stop-color="#6E77DF"/>
<stop offset="0.25" stop-color="#5175E3"/>
<stop offset="0.33" stop-color="#3973E7"/>
<stop offset="0.42" stop-color="#2772E9"/>
<stop offset="0.54" stop-color="#1A71EB"/>
<stop offset="0.68" stop-color="#1371EC"/>
<stop offset="1" stop-color="#1171ED"/>
</linearGradient>
<clipPath id="clip0_2092_1818">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,59 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1741)">
<mask id="mask0_2092_1741" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="17" height="16">
<path d="M16.5 0H0.5V16H16.5V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_2092_1741)">
<mask id="mask1_2092_1741" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="-1" y="-2" width="19" height="20">
<path d="M17.8337 -1.33337H-0.833008V17.3333H17.8337V-1.33337Z" fill="white"/>
</mask>
<g mask="url(#mask1_2092_1741)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.1137 0.315668C11.57 0.315668 11.9744 0.657891 12.1196 1.15567C12.2648 1.65345 13.1152 4.73345 13.1152 4.73345V10.852H10.0352L10.0974 0.305298H11.1137V0.315668Z" fill="url(#paint0_linear_2092_1741)"/>
<path d="M15.6352 5.09586C15.6352 4.87808 15.4589 4.71216 15.2515 4.71216H13.4366C12.1611 4.71216 11.124 5.7492 11.124 7.02472V10.8618H13.3226C14.5982 10.8618 15.6352 9.82472 15.6352 8.54919V5.09586Z" fill="url(#paint1_linear_2092_1741)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.1133 0.315674C10.7607 0.315674 10.4807 0.595674 10.4807 0.948265L10.4185 12.5942C10.4185 14.2949 9.0392 15.6742 7.33847 15.6742H1.74885C1.47921 15.6742 1.30292 15.4149 1.38589 15.1661L5.86589 2.37938C6.30144 1.14531 7.46293 0.315674 8.7696 0.315674H11.1237H11.1133Z" fill="url(#paint2_linear_2092_1741)"/>
</g>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_2092_1741" x1="12.3996" y1="11.0801" x2="9.80702" y2="0.699373" gradientUnits="userSpaceOnUse">
<stop stop-color="#712575"/>
<stop offset="0.09" stop-color="#9A2884"/>
<stop offset="0.18" stop-color="#BF2C92"/>
<stop offset="0.27" stop-color="#DA2E9C"/>
<stop offset="0.34" stop-color="#EB30A2"/>
<stop offset="0.4" stop-color="#F131A5"/>
<stop offset="0.5" stop-color="#EC30A3"/>
<stop offset="0.61" stop-color="#DF2F9E"/>
<stop offset="0.72" stop-color="#C92D96"/>
<stop offset="0.83" stop-color="#AA2A8A"/>
<stop offset="0.95" stop-color="#83267C"/>
<stop offset="1" stop-color="#712575"/>
</linearGradient>
<linearGradient id="paint1_linear_2092_1741" x1="13.3848" y1="0.532897" x2="13.3848" y2="15.1759" gradientUnits="userSpaceOnUse">
<stop stop-color="#DA7ED0"/>
<stop offset="0.08" stop-color="#B17BD5"/>
<stop offset="0.19" stop-color="#8778DB"/>
<stop offset="0.3" stop-color="#6276E1"/>
<stop offset="0.41" stop-color="#4574E5"/>
<stop offset="0.54" stop-color="#2E72E8"/>
<stop offset="0.67" stop-color="#1D71EB"/>
<stop offset="0.81" stop-color="#1471EC"/>
<stop offset="1" stop-color="#1171ED"/>
</linearGradient>
<linearGradient id="paint2_linear_2092_1741" x1="12.5029" y1="0.865306" x2="2.79625" y2="16.4313" gradientUnits="userSpaceOnUse">
<stop stop-color="#DA7ED0"/>
<stop offset="0.05" stop-color="#B77BD4"/>
<stop offset="0.11" stop-color="#9079DA"/>
<stop offset="0.18" stop-color="#6E77DF"/>
<stop offset="0.25" stop-color="#5175E3"/>
<stop offset="0.33" stop-color="#3973E7"/>
<stop offset="0.42" stop-color="#2772E9"/>
<stop offset="0.54" stop-color="#1A71EB"/>
<stop offset="0.68" stop-color="#1371EC"/>
<stop offset="1" stop-color="#1171ED"/>
</linearGradient>
<clipPath id="clip0_2092_1741">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,20 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.2445 7.22331C13.137 6.75184 12.13 6.07273 11.2778 5.22264C10.0911 4.03353 9.2444 2.54831 8.8258 0.921308C8.80744 0.849046 8.76551 0.784967 8.70665 0.739197C8.6478 0.693428 8.57536 0.668579 8.5008 0.668579C8.42624 0.668579 8.35381 0.693428 8.29495 0.739197C8.2361 0.784967 8.19417 0.849046 8.1758 0.921308C7.75632 2.5481 6.90952 4.03315 5.72314 5.22264C4.87089 6.07263 3.8639 6.75172 2.75647 7.22331C2.32314 7.40998 1.8778 7.55998 1.4218 7.67531C1.3491 7.69317 1.28448 7.7349 1.23829 7.79382C1.1921 7.85274 1.16699 7.92544 1.16699 8.00031C1.16699 8.07518 1.1921 8.14788 1.23829 8.2068C1.28448 8.26572 1.3491 8.30744 1.4218 8.32531C1.8778 8.43998 2.3218 8.58998 2.75647 8.77664C3.86397 9.24811 4.87098 9.92722 5.72314 10.7773C6.9102 11.9666 7.75709 13.452 8.1758 15.0793C8.19367 15.152 8.2354 15.2166 8.29431 15.2628C8.35323 15.309 8.42594 15.3341 8.5008 15.3341C8.57567 15.3341 8.64838 15.309 8.7073 15.2628C8.76621 15.2166 8.80794 15.152 8.8258 15.0793C8.94047 14.6226 9.09047 14.1786 9.27714 13.744C9.74858 12.6365 10.4277 11.6294 11.2778 10.7773C12.4671 9.59052 13.9526 8.74386 15.5798 8.32531C15.6521 8.30694 15.7161 8.26502 15.7619 8.20616C15.8077 8.1473 15.8325 8.07487 15.8325 8.00031C15.8325 7.92575 15.8077 7.85332 15.7619 7.79446C15.7161 7.7356 15.6521 7.69367 15.5798 7.67531C15.1234 7.56047 14.6768 7.40932 14.2445 7.22331Z" fill="#3186FF"/>
<path d="M14.2445 7.22331C13.137 6.75184 12.13 6.07273 11.2778 5.22264C10.0911 4.03353 9.2444 2.54831 8.8258 0.921308C8.80744 0.849046 8.76551 0.784967 8.70665 0.739197C8.6478 0.693428 8.57536 0.668579 8.5008 0.668579C8.42624 0.668579 8.35381 0.693428 8.29495 0.739197C8.2361 0.784967 8.19417 0.849046 8.1758 0.921308C7.75632 2.5481 6.90952 4.03315 5.72314 5.22264C4.87089 6.07263 3.8639 6.75172 2.75647 7.22331C2.32314 7.40998 1.8778 7.55998 1.4218 7.67531C1.3491 7.69317 1.28448 7.7349 1.23829 7.79382C1.1921 7.85274 1.16699 7.92544 1.16699 8.00031C1.16699 8.07518 1.1921 8.14788 1.23829 8.2068C1.28448 8.26572 1.3491 8.30744 1.4218 8.32531C1.8778 8.43998 2.3218 8.58998 2.75647 8.77664C3.86397 9.24811 4.87098 9.92722 5.72314 10.7773C6.9102 11.9666 7.75709 13.452 8.1758 15.0793C8.19367 15.152 8.2354 15.2166 8.29431 15.2628C8.35323 15.309 8.42594 15.3341 8.5008 15.3341C8.57567 15.3341 8.64838 15.309 8.7073 15.2628C8.76621 15.2166 8.80794 15.152 8.8258 15.0793C8.94047 14.6226 9.09047 14.1786 9.27714 13.744C9.74858 12.6365 10.4277 11.6294 11.2778 10.7773C12.4671 9.59052 13.9526 8.74386 15.5798 8.32531C15.6521 8.30694 15.7161 8.26502 15.7619 8.20616C15.8077 8.1473 15.8325 8.07487 15.8325 8.00031C15.8325 7.92575 15.8077 7.85332 15.7619 7.79446C15.7161 7.7356 15.6521 7.69367 15.5798 7.67531C15.1234 7.56047 14.6768 7.40932 14.2445 7.22331Z" fill="url(#paint0_linear_2092_1806)"/>
<path d="M14.2445 7.22331C13.137 6.75184 12.13 6.07273 11.2778 5.22264C10.0911 4.03353 9.2444 2.54831 8.8258 0.921308C8.80744 0.849046 8.76551 0.784967 8.70665 0.739197C8.6478 0.693428 8.57536 0.668579 8.5008 0.668579C8.42624 0.668579 8.35381 0.693428 8.29495 0.739197C8.2361 0.784967 8.19417 0.849046 8.1758 0.921308C7.75632 2.5481 6.90952 4.03315 5.72314 5.22264C4.87089 6.07263 3.8639 6.75172 2.75647 7.22331C2.32314 7.40998 1.8778 7.55998 1.4218 7.67531C1.3491 7.69317 1.28448 7.7349 1.23829 7.79382C1.1921 7.85274 1.16699 7.92544 1.16699 8.00031C1.16699 8.07518 1.1921 8.14788 1.23829 8.2068C1.28448 8.26572 1.3491 8.30744 1.4218 8.32531C1.8778 8.43998 2.3218 8.58998 2.75647 8.77664C3.86397 9.24811 4.87098 9.92722 5.72314 10.7773C6.9102 11.9666 7.75709 13.452 8.1758 15.0793C8.19367 15.152 8.2354 15.2166 8.29431 15.2628C8.35323 15.309 8.42594 15.3341 8.5008 15.3341C8.57567 15.3341 8.64838 15.309 8.7073 15.2628C8.76621 15.2166 8.80794 15.152 8.8258 15.0793C8.94047 14.6226 9.09047 14.1786 9.27714 13.744C9.74858 12.6365 10.4277 11.6294 11.2778 10.7773C12.4671 9.59052 13.9526 8.74386 15.5798 8.32531C15.6521 8.30694 15.7161 8.26502 15.7619 8.20616C15.8077 8.1473 15.8325 8.07487 15.8325 8.00031C15.8325 7.92575 15.8077 7.85332 15.7619 7.79446C15.7161 7.7356 15.6521 7.69367 15.5798 7.67531C15.1234 7.56047 14.6768 7.40932 14.2445 7.22331Z" fill="url(#paint1_linear_2092_1806)"/>
<path d="M14.2445 7.22331C13.137 6.75184 12.13 6.07273 11.2778 5.22264C10.0911 4.03353 9.2444 2.54831 8.8258 0.921308C8.80744 0.849046 8.76551 0.784967 8.70665 0.739197C8.6478 0.693428 8.57536 0.668579 8.5008 0.668579C8.42624 0.668579 8.35381 0.693428 8.29495 0.739197C8.2361 0.784967 8.19417 0.849046 8.1758 0.921308C7.75632 2.5481 6.90952 4.03315 5.72314 5.22264C4.87089 6.07263 3.8639 6.75172 2.75647 7.22331C2.32314 7.40998 1.8778 7.55998 1.4218 7.67531C1.3491 7.69317 1.28448 7.7349 1.23829 7.79382C1.1921 7.85274 1.16699 7.92544 1.16699 8.00031C1.16699 8.07518 1.1921 8.14788 1.23829 8.2068C1.28448 8.26572 1.3491 8.30744 1.4218 8.32531C1.8778 8.43998 2.3218 8.58998 2.75647 8.77664C3.86397 9.24811 4.87098 9.92722 5.72314 10.7773C6.9102 11.9666 7.75709 13.452 8.1758 15.0793C8.19367 15.152 8.2354 15.2166 8.29431 15.2628C8.35323 15.309 8.42594 15.3341 8.5008 15.3341C8.57567 15.3341 8.64838 15.309 8.7073 15.2628C8.76621 15.2166 8.80794 15.152 8.8258 15.0793C8.94047 14.6226 9.09047 14.1786 9.27714 13.744C9.74858 12.6365 10.4277 11.6294 11.2778 10.7773C12.4671 9.59052 13.9526 8.74386 15.5798 8.32531C15.6521 8.30694 15.7161 8.26502 15.7619 8.20616C15.8077 8.1473 15.8325 8.07487 15.8325 8.00031C15.8325 7.92575 15.8077 7.85332 15.7619 7.79446C15.7161 7.7356 15.6521 7.69367 15.5798 7.67531C15.1234 7.56047 14.6768 7.40932 14.2445 7.22331Z" fill="url(#paint2_linear_2092_1806)"/>
<defs>
<linearGradient id="paint0_linear_2092_1806" x1="5.16714" y1="10.3333" x2="7.8338" y2="7.99997" gradientUnits="userSpaceOnUse">
<stop stop-color="#08B962"/>
<stop offset="1" stop-color="#08B962" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_2092_1806" x1="5.8338" y1="3.66664" x2="8.16714" y2="7.33331" gradientUnits="userSpaceOnUse">
<stop stop-color="#F94543"/>
<stop offset="1" stop-color="#F94543" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_2092_1806" x1="2.8338" y1="8.99998" x2="12.1671" y2="7.99998" gradientUnits="userSpaceOnUse">
<stop stop-color="#FABC12"/>
<stop offset="0.46" stop-color="#FABC12" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,24 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1755)">
<mask id="mask0_2092_1755" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="17" height="16">
<path d="M16.428 0H0.5V16H16.428V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_2092_1755)">
<path d="M5.05035 0H2.77441V3.21057H5.05035V0Z" fill="#FFD800"/>
<path d="M14.1529 0H11.877V3.21057H14.1529V0Z" fill="#FFD800"/>
<path d="M7.32555 3.21082H2.77441V6.42139H7.32555V3.21082Z" fill="#FFAF00"/>
<path d="M14.1537 3.21082H9.60254V6.42139H14.1537V3.21082Z" fill="#FFAF00"/>
<path d="M14.1519 6.41992H2.77441V9.63049H14.1519V6.41992Z" fill="#FF8205"/>
<path d="M5.05035 9.63074H2.77441V12.8414H5.05035V9.63074Z" fill="#FA500F"/>
<path d="M9.60213 9.63074H7.32617V12.8414H9.60213V9.63074Z" fill="#FA500F"/>
<path d="M14.1529 9.63074H11.877V12.8414H14.1529V9.63074Z" fill="#FA500F"/>
<path d="M7.32633 12.8402H0.5V16.0509H7.32633V12.8402Z" fill="#E10500"/>
<path d="M16.4296 12.8402H9.60254V16.0509H16.4296V12.8402Z" fill="#E10500"/>
</g>
</g>
<defs>
<clipPath id="clip0_2092_1755">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,18 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1790)">
<path d="M15.85 7.50005H15.75L13.08 2.54505C13.1287 2.45432 13.1544 2.35303 13.155 2.25005C13.155 2.16427 13.138 2.07933 13.105 2.00014C13.072 1.92095 13.0237 1.84907 12.9628 1.78865C12.9019 1.72823 12.8297 1.68045 12.7502 1.64808C12.6708 1.61571 12.5857 1.59939 12.5 1.60005C12.4129 1.59972 12.3267 1.6173 12.2467 1.65171C12.1667 1.68612 12.0946 1.73661 12.035 1.80005L6.71496 0.740047C6.70184 0.64745 6.66874 0.558814 6.61795 0.480283C6.56716 0.401752 6.4999 0.335204 6.42084 0.285253C6.34177 0.235302 6.25279 0.203143 6.16006 0.191003C6.06733 0.178864 5.97307 0.187036 5.88381 0.214952C5.79455 0.242869 5.71243 0.289862 5.64314 0.352674C5.57385 0.415486 5.51905 0.492615 5.48253 0.578715C5.44602 0.664814 5.42867 0.757825 5.43167 0.851299C5.43468 0.944773 5.45798 1.03647 5.49996 1.12005L1.34996 7.06505C1.29477 7.04867 1.23753 7.04025 1.17996 7.04005C1.01805 7.05429 0.867358 7.12867 0.757581 7.24853C0.647805 7.36838 0.586914 7.52502 0.586914 7.68755C0.586914 7.85008 0.647805 8.00671 0.757581 8.12657C0.867358 8.24643 1.01805 8.32081 1.17996 8.33505L3.42996 13.87C3.39194 13.9551 3.37153 14.0469 3.36996 14.14C3.37128 14.3116 3.44034 14.4756 3.5621 14.5964C3.68386 14.7173 3.84843 14.7851 4.01996 14.785C4.10788 14.7861 4.19505 14.7688 4.27596 14.7344C4.35686 14.7 4.42973 14.6491 4.48996 14.585L11.21 15.24C11.2312 15.4111 11.3195 15.5667 11.4554 15.6727C11.5914 15.7787 11.7639 15.8263 11.935 15.805C12.106 15.7838 12.2617 15.6955 12.3676 15.5596C12.4736 15.4236 12.5212 15.2511 12.5 15.08C12.498 14.9264 12.4433 14.7781 12.345 14.66L15.73 8.76005H15.84C15.9253 8.76137 16.0101 8.74587 16.0895 8.71442C16.1688 8.68297 16.2412 8.63619 16.3025 8.57676C16.3638 8.51733 16.4128 8.44641 16.4467 8.36804C16.4805 8.28968 16.4987 8.20541 16.5 8.12005C16.4947 7.95205 16.4236 7.79286 16.302 7.67686C16.1804 7.56085 16.018 7.49734 15.85 7.50005ZM12 2.64505C12.0769 2.74772 12.1833 2.82448 12.305 2.86505L11.305 10.55C11.2418 10.5642 11.1811 10.5878 11.125 10.62L5.49996 5.76005C5.51878 5.70543 5.52726 5.64778 5.52496 5.59005C5.52496 5.55005 5.52496 5.50505 5.52496 5.46505L12 2.64505ZM15.235 8.30505L11.79 10.66C11.763 10.6412 11.7345 10.6245 11.705 10.61L12.725 2.84505L15.355 7.69505C15.2499 7.81343 15.1928 7.96678 15.195 8.12505L15.235 8.30505ZM4.78496 4.95005C4.63217 4.97297 4.49283 5.0504 4.39266 5.16803C4.29249 5.28566 4.23825 5.43555 4.23996 5.59005V5.63505L1.92996 7.00005L5.49996 1.87005L4.78496 4.95005ZM4.99996 6.22505C5.08363 6.20348 5.16307 6.16798 5.23496 6.12005L10.79 10.955C10.7638 11.0306 10.7502 11.11 10.75 11.19V11.225L4.54996 13.775C4.46194 13.6393 4.32644 13.5412 4.16996 13.5L4.99996 6.22505ZM10.935 11.62C11.0198 11.7179 11.1337 11.7862 11.26 11.815L11.565 14.5C11.4362 14.5671 11.3327 14.6741 11.27 14.805L4.76996 14.165L10.935 11.62ZM11.7 11.765C11.8068 11.7099 11.8967 11.6269 11.9601 11.5248C12.0235 11.4226 12.058 11.3052 12.06 11.185C12.0622 11.1306 12.0537 11.0762 12.035 11.025L15.185 8.86005L12 14.4L11.7 11.765ZM11.86 2.22505L5.28996 5.08505L5.21496 5.03505L6.04996 1.45505H6.07496C6.18268 1.45615 6.28889 1.42961 6.38342 1.37796C6.47796 1.32631 6.55768 1.25129 6.61496 1.16005L11.86 2.20505V2.22505ZM1.82996 7.69005C1.82996 7.64505 1.82996 7.60505 1.82996 7.57005L4.42496 6.04005C4.47735 6.09439 4.53812 6.13997 4.60496 6.17505L3.74996 13.43L1.60996 8.17005C1.67867 8.11029 1.73383 8.03657 1.77177 7.95379C1.80971 7.87102 1.82955 7.7811 1.82996 7.69005Z" fill="#333333"/>
<path d="M12.7446 2.84497L15.3696 7.69497C15.2665 7.81456 15.2098 7.96712 15.2096 8.12497C15.2023 8.18475 15.2023 8.24519 15.2096 8.30497L11.7696 10.66L11.6846 10.61L12.6846 2.84497H12.7446Z" fill="#DEDEDD"/>
<path d="M11.7002 11.765C11.807 11.7099 11.8969 11.6268 11.9603 11.5247C12.0237 11.4226 12.0582 11.3052 12.0602 11.185C12.0625 11.1305 12.054 11.0762 12.0352 11.025L15.1852 8.85999L12.0002 14.4L11.7002 11.765Z" fill="#B2B2B2"/>
<path d="M10.9345 11.62C11.0194 11.7179 11.1332 11.7862 11.2595 11.815L11.5645 14.5C11.4358 14.567 11.3322 14.6741 11.2695 14.805L4.76953 14.165L10.9345 11.62Z" fill="#D1D1D1"/>
<path d="M4.99992 6.225C5.08359 6.20343 5.16303 6.16793 5.23492 6.12L10.7899 10.955C10.7637 11.0306 10.7502 11.11 10.7499 11.19V11.225L4.54992 13.775C4.4619 13.6392 4.3264 13.5412 4.16992 13.5L4.99992 6.225Z" fill="#F2F2F2"/>
<path d="M1.83035 7.69004C1.83035 7.64504 1.83035 7.60504 1.83035 7.57004L4.42535 6.04004C4.47774 6.09439 4.53851 6.13997 4.60535 6.17504L3.75035 13.43L1.61035 8.17004C1.67906 8.11029 1.73422 8.03656 1.77216 7.95378C1.8101 7.87101 1.82994 7.78109 1.83035 7.69004Z" fill="#D8D8D7"/>
<path d="M4.78469 4.95C4.6319 4.97292 4.49255 5.05034 4.39238 5.16797C4.29221 5.28561 4.23798 5.4355 4.23969 5.59V5.635L1.92969 7L5.49969 1.87L4.78469 4.95Z" fill="#B2B2B2"/>
<path d="M11.8598 2.22503L5.28984 5.08503L5.21484 5.03503L6.04984 1.45503H6.07484C6.18256 1.45613 6.28877 1.42959 6.38331 1.37795C6.47785 1.3263 6.55757 1.25127 6.61484 1.16003L11.8598 2.20503V2.22503Z" fill="#D1D1D1"/>
<path d="M12 2.64502C12.0769 2.74769 12.1833 2.82445 12.305 2.86502L11.305 10.55C11.2418 10.5642 11.1811 10.5878 11.125 10.62L5.5 5.76002C5.51882 5.7054 5.5273 5.64775 5.525 5.59002C5.525 5.55002 5.525 5.50502 5.525 5.46502L12 2.64502Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_2092_1790">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,15 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1800)">
<mask id="mask0_2092_1800" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="17" height="16">
<path d="M16.5 0H0.5V16H16.5V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_2092_1800)">
<path d="M6.63673 5.772V4.26557C6.63673 4.13867 6.68433 4.0435 6.79527 3.98013L9.8241 2.23585C10.2364 1.998 10.728 1.88706 11.2353 1.88706C13.1382 1.88706 14.3434 3.3618 14.3434 4.9316C14.3434 5.0426 14.3434 5.16947 14.3275 5.29633L11.1877 3.45687C10.9975 3.3459 10.8071 3.3459 10.6169 3.45687L6.63673 5.772ZM13.709 11.6392V8.03953C13.709 7.8175 13.6138 7.65893 13.4236 7.54793L9.44343 5.2328L10.7437 4.48747C10.8547 4.42413 10.9499 4.42413 11.0609 4.48747L14.0897 6.23177C14.9619 6.73927 15.5485 7.8175 15.5485 8.864C15.5485 10.0691 14.835 11.1793 13.709 11.6392ZM5.70117 8.46777L4.40087 7.70667C4.28993 7.64333 4.2423 7.5481 4.2423 7.42123V3.9327C4.2423 2.23602 5.5426 0.951497 7.30277 0.951497C7.96887 0.951497 8.58717 1.17355 9.1106 1.56996L5.98673 3.37773C5.7965 3.4887 5.7013 3.64723 5.7013 3.86933L5.70117 8.46777ZM8.5 10.0852L6.63673 9.03863V6.8187L8.5 5.77217L10.3631 6.8187V9.03863L8.5 10.0852ZM9.6972 14.9058C9.03113 14.9058 8.41283 14.6838 7.8894 14.2874L11.0132 12.4796C11.2035 12.3686 11.2987 12.2101 11.2987 11.988V7.3894L12.6149 8.15053C12.7258 8.21387 12.7735 8.30907 12.7735 8.43597V11.9245C12.7735 13.6212 11.4572 14.9058 9.6972 14.9058ZM5.939 11.3697L2.91018 9.62543C2.03797 9.1179 1.45133 8.0397 1.45133 6.99317C1.45133 5.77217 2.18077 4.67803 3.30657 4.21813V7.83357C3.30657 8.0556 3.40178 8.21417 3.592 8.32513L7.5564 10.6244L6.2561 11.3697C6.14517 11.433 6.04993 11.433 5.939 11.3697ZM5.76467 13.9703C3.9728 13.9703 2.6566 12.6224 2.6566 10.9574C2.6566 10.8305 2.6725 10.7036 2.68826 10.5768L5.81213 12.3845C6.00237 12.4955 6.19273 12.4955 6.38297 12.3845L10.3631 10.0853V11.5918C10.3631 11.7186 10.3155 11.8138 10.2046 11.8772L7.17577 13.6215C6.76347 13.8593 6.27203 13.9703 5.76467 13.9703ZM9.6972 15.8572C11.6159 15.8572 13.2174 14.4935 13.5823 12.6857C15.3583 12.2258 16.5 10.5608 16.5 8.86417C16.5 7.7541 16.0243 6.6759 15.168 5.89887C15.2473 5.56583 15.2949 5.2328 15.2949 4.89993C15.2949 2.6324 13.4554 0.935567 11.3305 0.935567C10.9025 0.935567 10.4902 0.99892 10.0778 1.14172C9.36417 0.443973 8.381 0 7.30277 0C5.38407 0 3.78256 1.36364 3.41771 3.17142C1.64172 3.63133 0.5 5.29633 0.5 6.993C0.5 8.10307 0.975663 9.18127 1.83198 9.9583C1.7527 10.2913 1.70511 10.6244 1.70511 10.9572C1.70511 13.2248 3.54458 14.9216 5.66947 14.9216C6.09753 14.9216 6.50983 14.8582 6.92217 14.7154C7.63567 15.4132 8.61883 15.8572 9.6972 15.8572Z" fill="white"/>
</g>
</g>
<defs>
<clipPath id="clip0_2092_1800">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,10 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1732)">
<path d="M6.63673 5.772V4.26557C6.63673 4.13867 6.68433 4.0435 6.79527 3.98013L9.8241 2.23585C10.2364 1.998 10.728 1.88706 11.2353 1.88706C13.1382 1.88706 14.3434 3.3618 14.3434 4.9316C14.3434 5.0426 14.3434 5.16947 14.3275 5.29633L11.1877 3.45687C10.9975 3.3459 10.8071 3.3459 10.6169 3.45687L6.63673 5.772ZM13.709 11.6392V8.03953C13.709 7.8175 13.6138 7.65893 13.4236 7.54793L9.44343 5.2328L10.7437 4.48747C10.8547 4.42413 10.9499 4.42413 11.0609 4.48747L14.0897 6.23177C14.9619 6.73927 15.5485 7.8175 15.5485 8.864C15.5485 10.0691 14.835 11.1793 13.709 11.6392ZM5.70117 8.46777L4.40087 7.70667C4.28993 7.64333 4.2423 7.5481 4.2423 7.42123V3.9327C4.2423 2.23602 5.5426 0.951497 7.30277 0.951497C7.96887 0.951497 8.58717 1.17355 9.1106 1.56996L5.98673 3.37773C5.7965 3.4887 5.7013 3.64723 5.7013 3.86933L5.70117 8.46777ZM8.5 10.0852L6.63673 9.03863V6.8187L8.5 5.77217L10.3631 6.8187V9.03863L8.5 10.0852ZM9.6972 14.9058C9.03113 14.9058 8.41283 14.6838 7.8894 14.2874L11.0132 12.4796C11.2035 12.3686 11.2987 12.2101 11.2987 11.988V7.3894L12.6149 8.15053C12.7258 8.21387 12.7735 8.30907 12.7735 8.43597V11.9245C12.7735 13.6212 11.4572 14.9058 9.6972 14.9058ZM5.939 11.3697L2.91018 9.62543C2.03797 9.1179 1.45133 8.0397 1.45133 6.99317C1.45133 5.77217 2.18077 4.67803 3.30657 4.21813V7.83357C3.30657 8.0556 3.40178 8.21417 3.592 8.32513L7.5564 10.6244L6.2561 11.3697C6.14517 11.433 6.04993 11.433 5.939 11.3697ZM5.76467 13.9703C3.9728 13.9703 2.6566 12.6224 2.6566 10.9574C2.6566 10.8305 2.6725 10.7036 2.68826 10.5768L5.81213 12.3845C6.00237 12.4955 6.19273 12.4955 6.38297 12.3845L10.3631 10.0853V11.5918C10.3631 11.7186 10.3155 11.8138 10.2046 11.8772L7.17577 13.6215C6.76347 13.8593 6.27203 13.9703 5.76467 13.9703ZM9.6972 15.8572C11.6159 15.8572 13.2174 14.4935 13.5823 12.6857C15.3583 12.2258 16.5 10.5608 16.5 8.86417C16.5 7.7541 16.0243 6.6759 15.168 5.89887C15.2473 5.56583 15.2949 5.2328 15.2949 4.89993C15.2949 2.6324 13.4554 0.935567 11.3305 0.935567C10.9025 0.935567 10.4902 0.99892 10.0778 1.14172C9.36417 0.443973 8.381 0 7.30277 0C5.38407 0 3.78256 1.36364 3.41771 3.17142C1.64172 3.63133 0.5 5.29633 0.5 6.993C0.5 8.10307 0.975663 9.18127 1.83198 9.9583C1.7527 10.2913 1.70511 10.6244 1.70511 10.9572C1.70511 13.2248 3.54458 14.9216 5.66947 14.9216C6.09753 14.9216 6.50983 14.8582 6.92217 14.7154C7.63567 15.4132 8.61883 15.8572 9.6972 15.8572Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2092_1732">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,74 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2092_1770)">
<mask id="mask0_2092_1770" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="17" height="16">
<path d="M16.5 0H0.5V16H16.5V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_2092_1770)">
<mask id="mask1_2092_1770" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="17" height="16">
<path d="M16.5 0H0.5V16H16.5V0Z" fill="white"/>
</mask>
<g mask="url(#mask1_2092_1770)">
<path d="M16.131 10.9838L9.24712 15.124C9.02152 15.2597 8.76328 15.3313 8.5 15.3313C8.23675 15.3313 7.97846 15.2597 7.75286 15.124L0.869003 10.9838C0.640038 10.8461 0.5 10.5985 0.5 10.3313C0.5 10.0641 0.640038 9.81645 0.869003 9.67877L7.75286 5.53867C7.97846 5.40299 8.23675 5.3313 8.5 5.3313C8.76328 5.3313 9.02152 5.40299 9.24712 5.53867L16.131 9.67877C16.36 9.81645 16.5 10.0641 16.5 10.3313C16.5 10.5985 16.36 10.8461 16.131 10.9838Z" fill="url(#paint0_linear_2092_1770)"/>
<path d="M16.131 8.65256L9.24712 12.7926C9.02152 12.9283 8.76328 13 8.5 13C8.23675 13 7.97846 12.9283 7.75286 12.7926L0.869003 8.65256C0.640038 8.5148 0.5 8.2672 0.5 8C0.5 7.73282 0.640038 7.48518 0.869003 7.34746L7.75286 3.20737C7.97846 3.07168 8.23675 3 8.5 3C8.76328 3 9.02152 3.07168 9.24712 3.20737L16.131 7.34746C16.36 7.48518 16.5 7.73282 16.5 8C16.5 8.2672 16.36 8.5148 16.131 8.65256Z" fill="url(#paint1_linear_2092_1770)"/>
<path d="M16.131 6.31818L9.24712 10.4583C9.02152 10.5939 8.76328 10.6656 8.5 10.6656C8.23675 10.6656 7.97846 10.5939 7.75286 10.4583L0.869003 6.31818C0.640038 6.18046 0.5 5.93283 0.5 5.66565C0.5 5.39846 0.640038 5.15083 0.869003 5.01311L7.75286 0.873017C7.97846 0.737337 8.23675 0.665649 8.5 0.665649C8.76328 0.665649 9.02152 0.737337 9.24712 0.873017L16.131 5.01311C16.36 5.15083 16.5 5.39846 16.5 5.66565C16.5 5.93283 16.36 6.18046 16.131 6.31818Z" fill="url(#paint2_linear_2092_1770)"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint3_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint4_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint5_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint6_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint7_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M11.8334 7.55765C11.8334 8.29403 11.2364 8.89099 10.5 8.89099H5.83334C5.09695 8.89099 4.5 8.29403 4.5 7.55765V2.66565H11.8334V7.55765Z" fill="url(#paint8_radial_2092_1770)" fill-opacity="0.4"/>
<path d="M8.01858 3.31028L7.76982 2.80011C7.749 2.7608 7.7104 2.72675 7.65934 2.70267C7.60826 2.67859 7.54725 2.66565 7.48468 2.66565C7.42214 2.66565 7.36112 2.67859 7.31005 2.70267C7.25898 2.72675 7.22038 2.7608 7.19957 2.80011L6.9508 3.31028C6.87498 3.46428 6.74675 3.60454 6.57612 3.72002C6.40548 3.83551 6.19708 3.92314 5.9672 3.97603L5.20177 4.14185C5.14277 4.15571 5.09168 4.18143 5.05555 4.21548C5.0194 4.24951 5 4.29019 5 4.33188C5 4.37357 5.0194 4.41423 5.05555 4.44828C5.09168 4.48231 5.14277 4.50803 5.20177 4.52191L5.9672 4.68771C6.16372 4.73139 6.34502 4.80035 6.501 4.89045C6.53005 4.90723 6.55823 4.92475 6.58548 4.94297C6.72874 5.03882 6.84258 5.152 6.92118 5.27615C6.93774 5.30231 6.95274 5.32895 6.9661 5.35602L7.21486 5.86619C7.23363 5.90162 7.26685 5.93279 7.31062 5.95622C7.3154 5.95879 7.32032 5.96127 7.32535 5.96363C7.37642 5.98771 7.43743 6.00065 7.5 6.00065C7.56257 6.00065 7.62358 5.98771 7.67465 5.96363C7.72572 5.93955 7.76432 5.9055 7.78514 5.86619L8.0339 5.35602C8.11125 5.20091 8.24182 5.05999 8.41522 4.94442C8.58864 4.82885 8.80008 4.74182 9.0328 4.69027L9.79824 4.52447C9.8572 4.51059 9.90832 4.48487 9.94448 4.45083C9.98056 4.41679 10 4.37611 10 4.33443C10 4.29274 9.98056 4.25207 9.94448 4.21803C9.90832 4.18399 9.8572 4.15827 9.79824 4.1444L9.78296 4.14185L9.01752 3.97603C8.7848 3.92448 8.57328 3.83747 8.39992 3.72188C8.22652 3.60631 8.09595 3.46539 8.01858 3.31028Z" fill="url(#paint9_linear_2092_1770)"/>
<path d="M11.0775 6.78623L11.5368 6.88572L11.546 6.88725C11.5813 6.89557 11.612 6.911 11.6336 6.93143C11.6553 6.95185 11.667 6.97625 11.667 7.00126C11.667 7.02628 11.6553 7.05068 11.6336 7.0711C11.612 7.09154 11.5813 7.10697 11.546 7.11528L11.0867 7.21477C10.947 7.2457 10.8202 7.29792 10.7161 7.36726C10.6121 7.4366 10.5337 7.52117 10.4873 7.61422L10.338 7.92032C10.3256 7.94392 10.3024 7.96434 10.2718 7.97878C10.2412 7.99323 10.2045 8.00104 10.167 8.00104C10.1295 8.00104 10.0928 7.99323 10.0622 7.97878C10.0316 7.96434 10.0084 7.94392 9.99587 7.92032L9.99539 7.91937L9.84667 7.61422C9.80051 7.52088 9.72235 7.43602 9.61827 7.3664C9.51419 7.29677 9.38715 7.24434 9.24731 7.21323L8.78803 7.11375C8.75267 7.10543 8.72195 7.09 8.70035 7.06958C8.67859 7.04915 8.66699 7.02475 8.66699 6.99974C8.66699 6.97472 8.67859 6.95032 8.70035 6.9299C8.72195 6.90946 8.75267 6.89403 8.78803 6.88572L9.24731 6.78623C9.38523 6.7545 9.51027 6.70192 9.61267 6.63262C9.71499 6.56334 9.79195 6.47918 9.83747 6.38678L9.98675 6.08068C9.99923 6.05708 10.0224 6.03666 10.053 6.02222C10.0836 6.00777 10.1203 6 10.1578 6C10.1953 6 10.232 6.00777 10.2626 6.02222C10.2932 6.03666 10.3164 6.05708 10.3288 6.08068L10.4781 6.38678C10.5245 6.47983 10.6029 6.5644 10.7069 6.63375C10.811 6.70308 10.9379 6.7553 11.0775 6.78623Z" fill="url(#paint10_linear_2092_1770)"/>
</g>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_2092_1770" x1="0.5" y1="5.3313" x2="9.4888" y2="19.7133" gradientUnits="userSpaceOnUse">
<stop stop-color="#004695"/>
<stop offset="1" stop-color="#0078D4"/>
</linearGradient>
<linearGradient id="paint1_linear_2092_1770" x1="0.5" y1="3" x2="9.4888" y2="17.382" gradientUnits="userSpaceOnUse">
<stop stop-color="#0078D4"/>
<stop offset="1" stop-color="#0FAFFF"/>
</linearGradient>
<linearGradient id="paint2_linear_2092_1770" x1="0.9" y1="0.66565" x2="9.8888" y2="15.0477" gradientUnits="userSpaceOnUse">
<stop stop-color="#3BD5FF"/>
<stop offset="1" stop-color="#0FAFFF"/>
</linearGradient>
<radialGradient id="paint3_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(7.5 5.33231) rotate(90) scale(1 0.97124)">
<stop stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint4_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(8.5 4.99899) rotate(-14.0362) scale(1.37437 0.380635)">
<stop stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint5_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(6.5 4.99899) rotate(-165.964) scale(1.37437 0.384775)">
<stop stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint6_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.5 7.33231) rotate(-153.435) scale(0.745357 0.359002)">
<stop stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint7_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10.8334 7.33231) rotate(-26.565) scale(0.745357 0.290223)">
<stop stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint8_radial_2092_1770" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10.1666 7.66565) rotate(90) scale(0.666666 0.627526)">
<stop offset="0.0638343" stop-color="#00204D"/>
<stop offset="1" stop-color="#00204D" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint9_linear_2092_1770" x1="6.43217" y1="3.09882" x2="8.32475" y2="8.55931" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#DFFAFF"/>
</linearGradient>
<linearGradient id="paint10_linear_2092_1770" x1="6.43248" y1="3.09983" x2="8.32506" y2="8.56032" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#DFFAFF"/>
</linearGradient>
<clipPath id="clip0_2092_1770">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -23,16 +23,16 @@ namespace AdvancedPaste.Services;
public sealed class AdvancedAIKernelService : KernelServiceBase
{
private sealed record RuntimeConfiguration(
private readonly IAICredentialsProvider credentialsProvider;
private readonly record struct RuntimeConfig(
AIServiceType ServiceType,
string ModelName,
string Endpoint,
string DeploymentName,
string ModelPath,
string SystemPrompt,
bool ModerationEnabled) : IKernelRuntimeConfiguration;
private readonly IAICredentialsProvider credentialsProvider;
bool UsePasteScope,
bool ModerationEnabled);
public AdvancedAIKernelService(
IAICredentialsProvider credentialsProvider,
@@ -47,7 +47,7 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
this.credentialsProvider = credentialsProvider;
}
protected override string AdvancedAIModelName => GetRuntimeConfiguration().ModelName;
protected override string AdvancedAIModelName => GetRuntimeConfig().ModelName;
protected override PromptExecutionSettings PromptExecutionSettings => CreatePromptExecutionSettings();
@@ -55,15 +55,16 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
{
ArgumentNullException.ThrowIfNull(kernelBuilder);
var runtimeConfig = GetRuntimeConfiguration();
var runtimeConfig = GetRuntimeConfig();
var serviceType = runtimeConfig.ServiceType;
var modelName = runtimeConfig.ModelName;
var requiresApiKey = RequiresApiKey(serviceType);
var apiKey = string.Empty;
if (requiresApiKey)
{
this.credentialsProvider.Refresh();
apiKey = (this.credentialsProvider.GetKey() ?? string.Empty).Trim();
var scope = runtimeConfig.UsePasteScope ? AICredentialScope.PasteAI : AICredentialScope.AdvancedAI;
this.credentialsProvider.Refresh(scope);
apiKey = (this.credentialsProvider.GetKey(scope) ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(apiKey))
{
throw new InvalidOperationException($"An API key is required for {serviceType} but none was found in the credential vault.");
@@ -93,7 +94,7 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
protected override bool ShouldModerateAdvancedAI()
{
if (!TryGetRuntimeConfiguration(out var runtimeConfig))
if (!TryGetRuntimeConfig(out var runtimeConfig))
{
return false;
}
@@ -111,9 +112,9 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
return "gpt-4o";
}
protected override IKernelRuntimeConfiguration GetRuntimeConfiguration()
private RuntimeConfig GetRuntimeConfig()
{
if (TryGetRuntimeConfiguration(out var runtimeConfig))
if (TryGetRuntimeConfig(out var runtimeConfig))
{
return runtimeConfig;
}
@@ -121,11 +122,11 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
throw new InvalidOperationException("No Advanced AI provider is configured.");
}
private bool TryGetRuntimeConfiguration(out IKernelRuntimeConfiguration runtimeConfig)
private bool TryGetRuntimeConfig(out RuntimeConfig runtimeConfig)
{
runtimeConfig = null;
runtimeConfig = default;
if (!TryResolveAdvancedProvider(out var provider))
if (!TryResolveAdvancedProvider(out var provider, out var usePasteScope))
{
return false;
}
@@ -136,20 +137,21 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
return false;
}
runtimeConfig = new RuntimeConfiguration(
runtimeConfig = new RuntimeConfig(
serviceType,
GetModelName(provider),
provider.EndpointUrl,
provider.DeploymentName,
provider.ModelPath,
provider.SystemPrompt,
usePasteScope,
provider.ModerationEnabled);
return true;
}
private bool TryResolveAdvancedProvider(out PasteAIProviderDefinition provider)
private bool TryResolveAdvancedProvider(out PasteAIProviderDefinition provider, out bool usePasteScope)
{
provider = null;
usePasteScope = false;
var configuration = this.UserSettings?.PasteAIConfiguration;
if (configuration is null)
@@ -161,18 +163,15 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
if (IsAdvancedProvider(activeProvider))
{
provider = activeProvider;
usePasteScope = true;
return true;
}
if (activeProvider is not null)
{
return false;
}
var fallback = configuration.Providers?.FirstOrDefault(IsAdvancedProvider);
if (fallback is not null)
{
provider = fallback;
usePasteScope = configuration.UseSharedCredentials;
return true;
}
@@ -217,10 +216,10 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
private PromptExecutionSettings CreatePromptExecutionSettings()
{
var serviceType = GetRuntimeConfiguration().ServiceType;
var serviceType = GetRuntimeConfig().ServiceType;
return new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Required(),
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
Temperature = 0.01,
};
}

View File

@@ -4,17 +4,13 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Settings;
using AdvancedPaste.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
@@ -91,10 +87,6 @@ namespace AdvancedPaste.Services.CustomActions
var usage = request.Usage;
var content = providerContent ?? string.Empty;
// Log endpoint usage
var endpointEvent = new AdvancedPasteEndpointUsageEvent(providerConfig.ProviderType);
PowerToysTelemetry.Log.WriteEvent(endpointEvent);
Logger.LogDebug($"{nameof(CustomActionTransformService)}.{nameof(TransformAsync)} complete; ModelName={providerConfig.Model ?? string.Empty}, PromptTokens={usage.PromptTokens}, CompletionTokens={usage.CompletionTokens}");
return new CustomActionTransformResult(content, usage);
@@ -108,32 +100,10 @@ namespace AdvancedPaste.Services.CustomActions
throw;
}
var statusCode = ExtractStatusCode(ex);
var failureMessage = providerConfig.ProviderType switch
{
AIServiceType.OpenAI or AIServiceType.AzureOpenAI => ErrorHelpers.TranslateErrorText(statusCode),
_ => ResourceLoaderInstance.ResourceLoader.GetString("PasteError"),
};
throw new PasteActionException(failureMessage, ex);
throw new PasteActionException(ErrorHelpers.TranslateErrorText(-1), ex);
}
}
private static int ExtractStatusCode(Exception exception)
{
if (exception is HttpOperationException httpOperationException)
{
return (int?)httpOperationException.StatusCode ?? -1;
}
if (exception is HttpRequestException httpRequestException && httpRequestException.StatusCode is HttpStatusCode statusCode)
{
return (int)statusCode;
}
return -1;
}
private static AIServiceType NormalizeServiceType(AIServiceType serviceType)
{
return serviceType == AIServiceType.Unknown ? AIServiceType.OpenAI : serviceType;
@@ -171,8 +141,8 @@ namespace AdvancedPaste.Services.CustomActions
return string.Empty;
}
credentialsProvider.Refresh();
return credentialsProvider.GetKey() ?? string.Empty;
credentialsProvider.Refresh(AICredentialScope.PasteAI);
return credentialsProvider.GetKey(AICredentialScope.PasteAI) ?? string.Empty;
}
private static bool RequiresApiKey(AIServiceType serviceType)

View File

@@ -47,97 +47,62 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
{
ArgumentNullException.ThrowIfNull(request);
try
var systemPrompt = request.SystemPrompt;
if (string.IsNullOrWhiteSpace(systemPrompt))
{
var systemPrompt = request.SystemPrompt;
if (string.IsNullOrWhiteSpace(systemPrompt))
{
throw new PasteActionException(
"System prompt is required for Foundry Local",
new ArgumentException("System prompt must be provided", nameof(request)));
}
var prompt = request.Prompt;
var inputText = request.InputText;
if (string.IsNullOrWhiteSpace(prompt) || string.IsNullOrWhiteSpace(inputText))
{
throw new PasteActionException(
"Prompt and input text are required",
new ArgumentException("Prompt and input text must be provided", nameof(request)));
}
var modelReference = _config?.Model;
if (string.IsNullOrWhiteSpace(modelReference))
{
throw new PasteActionException(
"No Foundry Local model selected",
new InvalidOperationException("Model identifier is required"),
aiServiceMessage: "Please select a model in the AI provider settings. Model identifier should be in the format 'fl://model-name'.");
}
cancellationToken.ThrowIfCancellationRequested();
var chatClient = LanguageModels.GetClient(modelReference);
if (chatClient is null)
{
throw new PasteActionException(
$"Unable to load Foundry Local model: {modelReference}",
new InvalidOperationException("Chat client resolution failed"),
aiServiceMessage: "The model may not be downloaded or the Foundry Local service may not be running. Please check the model status in settings.");
}
// Extract actual model ID from the URL (format: fl://modelId)
var actualModelId = modelReference.Replace("fl://", string.Empty).Trim('/');
var userMessageContent = $"""
User instructions:
{prompt}
Text:
{inputText}
Output:
""";
var chatMessages = new List<ChatMessage>
{
new(ChatRole.System, systemPrompt),
new(ChatRole.User, userMessageContent),
};
var chatOptions = CreateChatOptions(_config?.SystemPrompt, actualModelId);
progress?.Report(0.1);
var response = await chatClient.GetResponseAsync(chatMessages, chatOptions, cancellationToken).ConfigureAwait(false);
progress?.Report(0.8);
var responseText = GetResponseText(response);
request.Usage = ToUsage(response.Usage);
progress?.Report(1.0);
return responseText ?? string.Empty;
throw new ArgumentException("System prompt must be provided", nameof(request));
}
catch (OperationCanceledException)
var prompt = request.Prompt;
var inputText = request.InputText;
if (string.IsNullOrWhiteSpace(prompt) || string.IsNullOrWhiteSpace(inputText))
{
// Let cancellation exceptions pass through unchanged
throw;
throw new ArgumentException("Prompt and input text must be provided", nameof(request));
}
catch (PasteActionException)
var modelReference = _config?.Model;
if (string.IsNullOrWhiteSpace(modelReference))
{
// Let our custom exceptions pass through unchanged
throw;
throw new InvalidOperationException("Foundry Local requires a model identifier (for example, 'fl://model-name').");
}
catch (Exception ex)
cancellationToken.ThrowIfCancellationRequested();
var chatClient = LanguageModels.GetClient(modelReference);
if (chatClient is null)
{
// Wrap any other exceptions with context
var modelInfo = !string.IsNullOrWhiteSpace(_config?.Model) ? $" (Model: {_config.Model})" : string.Empty;
throw new PasteActionException(
$"Failed to generate response using Foundry Local{modelInfo}",
ex,
aiServiceMessage: $"Error details: {ex.Message}");
throw new InvalidOperationException($"Unable to resolve Foundry Local client for '{modelReference}'. Ensure the model is downloaded.");
}
var userMessageContent = $"""
User instructions:
{prompt}
Text:
{inputText}
Output:
""";
var chatMessages = new List<ChatMessage>
{
new(ChatRole.System, systemPrompt),
new(ChatRole.User, userMessageContent),
};
var chatOptions = CreateChatOptions(_config?.SystemPrompt, modelReference);
progress?.Report(0.1);
var response = await chatClient.GetResponseAsync(chatMessages, chatOptions, cancellationToken).ConfigureAwait(false);
progress?.Report(0.8);
var responseText = GetResponseText(response);
request.Usage = ToUsage(response.Usage);
progress?.Report(1.0);
return responseText ?? string.Empty;
}
private static ChatOptions CreateChatOptions(string systemPrompt, string modelReference)

View File

@@ -146,7 +146,7 @@ namespace AdvancedPaste.Services.CustomActions
kernelBuilder.AddHuggingFaceChatCompletion(_config.Model, apiKey: apiKey);
break;
case AIServiceType.AzureAIInference:
kernelBuilder.AddAzureAIInferenceChatCompletion(_config.Model, apiKey: apiKey, endpoint: new Uri(endpoint));
kernelBuilder.AddAzureAIInferenceChatCompletion(_config.Model, apiKey: apiKey);
break;
case AIServiceType.Ollama:
kernelBuilder.AddOllamaChatCompletion(_config.Model, endpoint: new Uri(endpoint));

View File

@@ -3,8 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using AdvancedPaste.Settings;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.Security.Credentials;
@@ -29,53 +29,59 @@ public sealed class EnhancedVaultCredentialsProvider : IAICredentialsProvider
}
private readonly IUserSettings _userSettings;
private readonly CredentialSlot _slot;
private readonly Lock _syncRoot = new();
private readonly Dictionary<AICredentialScope, CredentialSlot> _slots;
private readonly object _syncRoot = new();
public EnhancedVaultCredentialsProvider(IUserSettings userSettings)
{
_userSettings = userSettings ?? throw new ArgumentNullException(nameof(userSettings));
_slot = new CredentialSlot();
_slots = new Dictionary<AICredentialScope, CredentialSlot>
{
[AICredentialScope.PasteAI] = new CredentialSlot(),
[AICredentialScope.AdvancedAI] = new CredentialSlot(),
};
Refresh();
Refresh(AICredentialScope.PasteAI);
Refresh(AICredentialScope.AdvancedAI);
}
public string GetKey()
public string GetKey(AICredentialScope scope)
{
using (_syncRoot.EnterScope())
lock (_syncRoot)
{
UpdateSlot(forceRefresh: false);
return _slot.Key;
UpdateSlot(scope, forceRefresh: false);
return _slots[scope].Key;
}
}
public bool IsConfigured()
public bool IsConfigured(AICredentialScope scope)
{
return !string.IsNullOrEmpty(GetKey());
return !string.IsNullOrEmpty(GetKey(scope));
}
public bool Refresh()
public bool Refresh(AICredentialScope scope)
{
using (_syncRoot.EnterScope())
lock (_syncRoot)
{
return UpdateSlot(forceRefresh: true);
return UpdateSlot(scope, forceRefresh: true);
}
}
private bool UpdateSlot(bool forceRefresh)
private bool UpdateSlot(AICredentialScope scope, bool forceRefresh)
{
var (serviceType, providerId) = ResolveCredentialTarget();
var slot = _slots[scope];
var (serviceType, providerId) = ResolveCredentialTarget(scope);
var desiredServiceType = NormalizeServiceType(serviceType);
providerId ??= string.Empty;
var hasChanged = false;
if (_slot.ServiceType != desiredServiceType || !string.Equals(_slot.ProviderId, providerId, StringComparison.Ordinal))
if (slot.ServiceType != desiredServiceType || !string.Equals(slot.ProviderId, providerId, StringComparison.Ordinal))
{
_slot.ServiceType = desiredServiceType;
_slot.ProviderId = providerId;
_slot.Entry = BuildCredentialEntry(desiredServiceType, providerId);
slot.ServiceType = desiredServiceType;
slot.ProviderId = providerId;
slot.Entry = BuildCredentialEntry(desiredServiceType, providerId, scope);
forceRefresh = true;
hasChanged = true;
}
@@ -85,17 +91,55 @@ public sealed class EnhancedVaultCredentialsProvider : IAICredentialsProvider
return hasChanged;
}
var newKey = LoadKey(_slot.Entry);
if (!string.Equals(_slot.Key, newKey, StringComparison.Ordinal))
var newKey = LoadKey(slot.Entry);
if (!string.Equals(slot.Key, newKey, StringComparison.Ordinal))
{
_slot.Key = newKey;
slot.Key = newKey;
hasChanged = true;
}
return hasChanged;
}
private (AIServiceType ServiceType, string ProviderId) ResolveCredentialTarget()
private (AIServiceType ServiceType, string ProviderId) ResolveCredentialTarget(AICredentialScope scope)
{
return scope switch
{
AICredentialScope.AdvancedAI => (ResolveAdvancedAiServiceType(), string.Empty),
AICredentialScope.PasteAI => ResolvePasteAiServiceTarget(),
_ => (AIServiceType.OpenAI, string.Empty),
};
}
private static AIServiceType NormalizeServiceType(AIServiceType serviceType)
{
return serviceType == AIServiceType.Unknown ? AIServiceType.OpenAI : serviceType;
}
private AIServiceType ResolveAdvancedAiServiceType()
{
var configuration = _userSettings.PasteAIConfiguration;
if (configuration is null)
{
return AIServiceType.OpenAI;
}
var activeProvider = configuration.ActiveProvider;
if (IsAdvancedProvider(activeProvider))
{
return NormalizeServiceType(activeProvider.ServiceTypeKind);
}
var fallback = configuration.Providers?.FirstOrDefault(IsAdvancedProvider);
if (fallback is not null)
{
return NormalizeServiceType(fallback.ServiceTypeKind);
}
return AIServiceType.OpenAI;
}
private (AIServiceType ServiceType, string ProviderId) ResolvePasteAiServiceTarget()
{
var provider = _userSettings.PasteAIConfiguration?.ActiveProvider;
if (provider is null)
@@ -106,9 +150,19 @@ public sealed class EnhancedVaultCredentialsProvider : IAICredentialsProvider
return (provider.ServiceTypeKind, provider.Id ?? string.Empty);
}
private static AIServiceType NormalizeServiceType(AIServiceType serviceType)
private static bool IsAdvancedProvider(PasteAIProviderDefinition provider)
{
return serviceType == AIServiceType.Unknown ? AIServiceType.OpenAI : serviceType;
if (provider is null || !provider.EnableAdvancedAI)
{
return false;
}
return SupportsAdvancedAI(provider.ServiceTypeKind);
}
private static bool SupportsAdvancedAI(AIServiceType serviceType)
{
return NormalizeServiceType(serviceType) is AIServiceType.OpenAI or AIServiceType.AzureOpenAI;
}
private static string LoadKey((string Resource, string Username)? entry)
@@ -129,7 +183,27 @@ public sealed class EnhancedVaultCredentialsProvider : IAICredentialsProvider
}
}
private static (string Resource, string Username)? BuildCredentialEntry(AIServiceType serviceType, string providerId)
private static (string Resource, string Username)? BuildCredentialEntry(AIServiceType serviceType, string providerId, AICredentialScope scope)
{
return scope switch
{
AICredentialScope.AdvancedAI => GetAdvancedAiEntry(serviceType),
AICredentialScope.PasteAI => GetPasteAiEntry(serviceType, providerId),
_ => null,
};
}
private static (string Resource, string Username)? GetAdvancedAiEntry(AIServiceType serviceType)
{
return serviceType switch
{
AIServiceType.OpenAI => ("https://platform.openai.com/api-keys", "PowerToys_AdvancedPaste_AdvancedAI_OpenAI"),
AIServiceType.AzureOpenAI => ("https://azure.microsoft.com/products/ai-services/openai-service", "PowerToys_AdvancedPaste_AdvancedAI_AzureOpenAI"),
_ => null,
};
}
private static (string Resource, string Username)? GetPasteAiEntry(AIServiceType serviceType, string providerId)
{
string resource;
string serviceKey;

View File

@@ -4,26 +4,38 @@
namespace AdvancedPaste.Services;
/// <summary>
/// Represents the scope a credential lookup is targeting.
/// </summary>
public enum AICredentialScope
{
PasteAI,
AdvancedAI,
}
/// <summary>
/// Provides access to AI credentials stored for Advanced Paste scenarios.
/// </summary>
public interface IAICredentialsProvider
{
/// <summary>
/// Gets a value indicating whether any credential is configured.
/// Gets a value indicating whether the specified scope has a configured credential.
/// </summary>
/// <returns><see langword="true"/> when a non-empty credential exists for the active AI provider.</returns>
bool IsConfigured();
/// <param name="scope">Scope to evaluate.</param>
/// <returns><see langword="true"/> when a non-empty credential exists for the scope.</returns>
bool IsConfigured(AICredentialScope scope);
/// <summary>
/// Retrieves the credential for the active AI provider.
/// Retrieves the credential for the requested scope.
/// </summary>
/// <param name="scope">Scope to evaluate.</param>
/// <returns>Credential string or <see cref="string.Empty"/> when missing.</returns>
string GetKey();
string GetKey(AICredentialScope scope);
/// <summary>
/// Refreshes the cached credential for the active AI provider.
/// Refreshes the cached credential for the provided scope.
/// </summary>
/// <param name="scope">Scope to refresh.</param>
/// <returns><see langword="true"/> when the credential changed.</returns>
bool Refresh();
bool Refresh(AICredentialScope scope);
}

Some files were not shown because too many files have changed in this diff Show More