@typecad/framework-zephyr 1.0.0-alpha.13 → 1.0.0-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +22 -35
  2. package/dist/as-built.d.ts +33 -0
  3. package/dist/as-built.js +188 -0
  4. package/dist/async/timer-polyfill.js +1 -1
  5. package/dist/boardgen.d.ts +128 -0
  6. package/dist/boardgen.js +1366 -0
  7. package/dist/chips/board-overrides.d.ts +7 -0
  8. package/dist/chips/board-overrides.js +11 -0
  9. package/dist/chips/controllers.d.ts +28 -8
  10. package/dist/chips/controllers.js +49 -12
  11. package/dist/chips/esp32s3.js +49 -0
  12. package/dist/chips/index.d.ts +6 -12
  13. package/dist/chips/index.js +18 -34
  14. package/dist/chips/resolve.d.ts +16 -2
  15. package/dist/chips/resolve.js +298 -15
  16. package/dist/chips/soc/.d.ts +2 -0
  17. package/dist/chips/soc/.js +129 -0
  18. package/dist/chips/soc/esp32.d.ts +2 -0
  19. package/dist/chips/soc/esp32.js +120 -0
  20. package/dist/chips/soc/esp32c3.d.ts +2 -0
  21. package/dist/chips/soc/esp32c3.js +90 -0
  22. package/dist/chips/soc/esp32c6.d.ts +2 -0
  23. package/dist/chips/soc/esp32c6.js +109 -0
  24. package/dist/chips/soc/esp32s3.d.ts +2 -0
  25. package/dist/chips/soc/esp32s3.js +189 -0
  26. package/dist/chips/soc/index.d.ts +2 -0
  27. package/dist/chips/soc/index.js +23 -0
  28. package/dist/chips/soc/nrf52840.d.ts +2 -0
  29. package/dist/chips/soc/nrf52840.js +130 -0
  30. package/dist/chips/soc/rp2040.d.ts +2 -0
  31. package/dist/chips/soc/rp2040.js +141 -0
  32. package/dist/chips/soc/rp2350a.d.ts +2 -0
  33. package/dist/chips/soc/rp2350a.js +145 -0
  34. package/dist/chips/soc/samd21g18a.d.ts +2 -0
  35. package/dist/chips/soc/samd21g18a.js +143 -0
  36. package/dist/chips/soc/stm32f411xe.d.ts +2 -0
  37. package/dist/chips/soc/stm32f411xe.js +251 -0
  38. package/dist/chips/types.d.ts +382 -12
  39. package/dist/chips/xiao-ble.js +33 -0
  40. package/dist/display/profiles.js +1 -1
  41. package/dist/doctor.js +38 -4
  42. package/dist/dt-config/custom-board.d.ts +23 -0
  43. package/dist/dt-config/custom-board.js +227 -0
  44. package/dist/dt-config/kconfig.d.ts +83 -1
  45. package/dist/dt-config/kconfig.js +116 -27
  46. package/dist/dt-config/overlay.js +623 -18
  47. package/dist/framework.manifest.d.ts +20 -30
  48. package/dist/framework.manifest.js +124 -178
  49. package/dist/index.d.ts +4 -1
  50. package/dist/index.js +8 -2
  51. package/dist/lowering/adc.d.ts +26 -5
  52. package/dist/lowering/adc.js +137 -31
  53. package/dist/lowering/ble.js +31 -28
  54. package/dist/lowering/dac.js +9 -9
  55. package/dist/lowering/fs.js +18 -10
  56. package/dist/lowering/gpio.d.ts +2 -0
  57. package/dist/lowering/gpio.js +90 -10
  58. package/dist/lowering/http.js +39 -14
  59. package/dist/lowering/hwtimer.d.ts +4 -0
  60. package/dist/lowering/hwtimer.js +35 -10
  61. package/dist/lowering/i2c.js +46 -54
  62. package/dist/lowering/index.d.ts +5 -5
  63. package/dist/lowering/index.js +15 -16
  64. package/dist/lowering/interrupts.d.ts +22 -5
  65. package/dist/lowering/interrupts.js +104 -22
  66. package/dist/lowering/mqtt.js +12 -6
  67. package/dist/lowering/power.js +0 -4
  68. package/dist/lowering/preferences.js +49 -77
  69. package/dist/lowering/pulse.js +5 -36
  70. package/dist/lowering/pwm.d.ts +32 -3
  71. package/dist/lowering/pwm.js +105 -17
  72. package/dist/lowering/random.js +3 -3
  73. package/dist/lowering/sensor.d.ts +37 -0
  74. package/dist/lowering/sensor.js +119 -0
  75. package/dist/lowering/spi.d.ts +12 -0
  76. package/dist/lowering/spi.js +65 -40
  77. package/dist/lowering/thread.d.ts +14 -0
  78. package/dist/lowering/thread.js +55 -0
  79. package/dist/lowering/timing.js +20 -46
  80. package/dist/lowering/tone.js +18 -5
  81. package/dist/lowering/uart.d.ts +13 -0
  82. package/dist/lowering/uart.js +72 -51
  83. package/dist/lowering/usb.d.ts +34 -0
  84. package/dist/lowering/usb.js +206 -0
  85. package/dist/lowering/wdt.d.ts +1 -1
  86. package/dist/lowering/wdt.js +17 -7
  87. package/dist/lowering/wifi.d.ts +3 -2
  88. package/dist/lowering/wifi.js +120 -111
  89. package/dist/sdk/board-catalog-sync.d.ts +16 -0
  90. package/dist/sdk/board-catalog-sync.js +41 -0
  91. package/dist/sdk/board-data.generated.d.ts +2 -0
  92. package/dist/sdk/board-data.generated.js +4 -0
  93. package/dist/sdk/catalog-walker.d.ts +90 -0
  94. package/dist/sdk/catalog-walker.js +682 -0
  95. package/dist/sdk/dts-reader.d.ts +83 -0
  96. package/dist/sdk/dts-reader.js +596 -0
  97. package/dist/strategy.d.ts +136 -17
  98. package/dist/strategy.js +881 -212
  99. package/dist/toolchain/bossac-touch.d.ts +18 -0
  100. package/dist/toolchain/bossac-touch.js +88 -0
  101. package/dist/toolchain/compat.d.ts +2 -2
  102. package/dist/toolchain/compat.js +8 -3
  103. package/dist/toolchain/debug-config.d.ts +21 -26
  104. package/dist/toolchain/debug-config.js +212 -72
  105. package/dist/toolchain/env-check.d.ts +4 -4
  106. package/dist/toolchain/env-check.js +5 -5
  107. package/dist/toolchain/index.d.ts +66 -1
  108. package/dist/toolchain/index.js +713 -58
  109. package/dist/toolchain/scaffold.d.ts +9 -0
  110. package/dist/toolchain/scaffold.js +84 -7
  111. package/dist/toolchain/west-discover.d.ts +8 -1
  112. package/dist/toolchain/west-discover.js +19 -6
  113. package/dist/toolchain/west-spawn.js +17 -5
  114. package/installer/CHANGELOG.md +473 -0
  115. package/installer/README.md +328 -0
  116. package/installer/environment.yml +46 -0
  117. package/installer/etc/conda/activate.d/zephyr.bat +7 -0
  118. package/installer/etc/conda/activate.d/zephyr.ps1 +12 -0
  119. package/installer/etc/conda/activate.d/zephyr.sh +20 -0
  120. package/installer/etc/conda/deactivate.d/zephyr.bat +6 -0
  121. package/installer/etc/conda/deactivate.d/zephyr.ps1 +6 -0
  122. package/installer/etc/conda/deactivate.d/zephyr.sh +4 -0
  123. package/installer/install.mjs +580 -0
  124. package/installer/install.ps1 +619 -0
  125. package/installer/install.sh +310 -0
  126. package/installer/lib/detect-platform.sh +62 -0
  127. package/installer/lib/fetch-sdk.sh +304 -0
  128. package/installer/lib/init-workspace.sh +153 -0
  129. package/installer/lib/write-activation.sh +76 -0
  130. package/installer/patches/tfm-c-include-separators.patch +19 -0
  131. package/installer/patches/zephyr-tfm-nordic-zephyr-include.patch +24 -0
  132. package/installer/templates/project/.typecad/activate-zephyr.ps1 +31 -0
  133. package/installer/templates/project/.typecad/activate-zephyr.sh +31 -0
  134. package/installer/templates/project/.vscode/settings.json +30 -0
  135. package/installer/templates/project/README.md +58 -0
  136. package/installer/versions.env +110 -0
  137. package/package.json +16 -16
  138. package/src/as-built.ts +206 -0
  139. package/src/boardgen.ts +1428 -0
  140. package/src/chips/controllers.ts +61 -12
  141. package/src/chips/index.ts +35 -54
  142. package/src/chips/resolve.ts +316 -14
  143. package/src/chips/types.ts +388 -13
  144. package/src/display/profiles.ts +1 -1
  145. package/src/doctor.ts +110 -77
  146. package/src/dt-config/custom-board.ts +325 -0
  147. package/src/dt-config/kconfig.ts +177 -19
  148. package/src/dt-config/overlay.ts +1058 -450
  149. package/src/framework.manifest.ts +125 -178
  150. package/src/index.ts +57 -41
  151. package/src/lowering/adc.ts +222 -102
  152. package/src/lowering/ble.ts +32 -28
  153. package/src/lowering/dac.ts +82 -82
  154. package/src/lowering/fs.ts +18 -10
  155. package/src/lowering/gpio.ts +242 -152
  156. package/src/lowering/http.ts +512 -488
  157. package/src/lowering/hwtimer.ts +139 -101
  158. package/src/lowering/i2c.ts +116 -126
  159. package/src/lowering/index.ts +91 -93
  160. package/src/lowering/interrupts.ts +113 -21
  161. package/src/lowering/mqtt.ts +12 -6
  162. package/src/lowering/preferences.ts +327 -354
  163. package/src/lowering/pwm.ts +167 -74
  164. package/src/lowering/random.ts +3 -3
  165. package/src/lowering/sensor.ts +155 -0
  166. package/src/lowering/spi.ts +164 -124
  167. package/src/lowering/thread.ts +63 -0
  168. package/src/lowering/timing.ts +46 -72
  169. package/src/lowering/uart.ts +73 -51
  170. package/src/lowering/usb.ts +221 -0
  171. package/src/lowering/wdt.ts +95 -84
  172. package/src/lowering/wifi.ts +120 -111
  173. package/src/sdk/board-catalog-sync.ts +62 -0
  174. package/src/strategy.ts +888 -229
  175. package/src/toolchain/bossac-touch.ts +112 -0
  176. package/src/toolchain/compat.ts +8 -3
  177. package/src/toolchain/debug-config.ts +666 -522
  178. package/src/toolchain/env-check.ts +9 -9
  179. package/src/toolchain/index.ts +765 -44
  180. package/src/toolchain/scaffold.ts +81 -7
  181. package/src/toolchain/west-discover.ts +334 -316
  182. package/src/toolchain/west-spawn.ts +17 -5
  183. package/src/async/timer-polyfill.ts +0 -107
  184. package/src/chips/esp32.ts +0 -74
  185. package/src/chips/esp32s3.ts +0 -57
  186. package/src/chips/xiao-ble.ts +0 -70
  187. package/src/lowering/power.ts +0 -70
  188. package/src/lowering/pulse.ts +0 -93
  189. package/src/lowering/tone.ts +0 -60
  190. package/src/lowering/worker-backing.ts +0 -94
  191. package/src/lowering/worker.ts +0 -17
@@ -0,0 +1,619 @@
1
+ # ---------------------------------------------------------------------------
2
+ # typeCAD Zephyr installer - Windows PowerShell bootstrap.
3
+ #
4
+ # Native Windows install of a working Zephyr build environment via micromamba.
5
+ # Mirrors install.sh step-for-step so users without Git Bash get the same
6
+ # one-command experience from PowerShell.
7
+ #
8
+ # 1. download micromamba (win-64 static exe)
9
+ # 2. create the conda env (west, cmake, ninja, gperf, pyelftools, ...)
10
+ # 3. install activation hooks that set ZEPHYR_BASE + ZEPHYR_SDK_INSTALL_DIR
11
+ # 4. fetch + extract the official Zephyr SDK bundle (.7z)
12
+ # 5. west init + west update a vanilla Zephyr workspace
13
+ #
14
+ # Usage:
15
+ # pwsh -File install.ps1 [-DryRun] [-NoSdk] [-NoWorkspace]
16
+ # [-EnvName NAME] [-SdkVersion VER]
17
+ #
18
+ # After install: `micromamba activate zephyr` (after `micromamba shell hook`)
19
+ # and framework-zephyr discovers west via PATH + ZEPHYR_BASE automatically.
20
+ # ---------------------------------------------------------------------------
21
+ [CmdletBinding()]
22
+ param(
23
+ [switch]$DryRun,
24
+ [switch]$NoSdk,
25
+ [switch]$NoWorkspace,
26
+ [switch]$Modify,
27
+ [switch]$Prune,
28
+ [string]$EnvName,
29
+ [string]$SdkVersion,
30
+ [string]$Platforms
31
+ )
32
+
33
+ $ErrorActionPreference = 'Stop'
34
+ $PackageDir = Split-Path -Parent $MyInvocation.MyCommand.Path
35
+
36
+ # Invoke a native executable and throw on non-zero exit. PowerShell's
37
+ # $ErrorActionPreference='Stop' does NOT apply to native exes (micromamba.exe,
38
+ # curl.exe, 7z.exe, tar.exe) — without this guard they fail silently, set
39
+ # $LASTEXITCODE, and the script cascades into a false "done". Every host tool
40
+ # call goes through this so a failure aborts with context.
41
+ function Invoke-Native {
42
+ param([scriptblock]$Block, [string]$Description)
43
+ & $Block
44
+ if ($LASTEXITCODE -ne 0) {
45
+ throw "$Description failed (exit $LASTEXITCODE)"
46
+ }
47
+ }
48
+
49
+ # --- load versions.env into script-scoped variables -------------------------
50
+ function Load-VersionsEnv {
51
+ param([string]$Path)
52
+ Get-Content $Path | ForEach-Object {
53
+ $line = $_.Trim()
54
+ if ($line -and -not $line.StartsWith('#')) {
55
+ $idx = $line.IndexOf('=')
56
+ if ($idx -gt 0) {
57
+ $key = $line.Substring(0, $idx).Trim()
58
+ $val = $line.Substring($idx + 1).Trim()
59
+ # Strip optional surrounding double quotes (multi-word values like
60
+ # PLATFORM_esp32 carry a space-separated toolchain list).
61
+ if ($val.StartsWith('"') -and $val.EndsWith('"') -and $val.Length -ge 2) {
62
+ $val = $val.Substring(1, $val.Length - 2)
63
+ }
64
+ Set-Variable -Name $key -Value $val -Scope Script
65
+ }
66
+ }
67
+ }
68
+ }
69
+ Load-VersionsEnv "$PackageDir\versions.env"
70
+
71
+ # Download via curl.exe (the real Windows curl, shipped on Win10 1803+), not
72
+ # Invoke-WebRequest. The .NET HttpWebRequest stack that Invoke-WebRequest uses
73
+ # resolves DNS through the system/IE proxy path, which can FAIL to resolve a
74
+ # host (e.g. api.anaconda.org behind the micro.mamba.pm redirect) even when the
75
+ # OS resolver and curl succeed. curl.exe resolves directly and adds retry/resume.
76
+ # NB: PowerShell aliases `curl` -> Invoke-WebRequest, so call `curl.exe` explicitly.
77
+ function Download-File {
78
+ param([string]$Url, [string]$OutFile)
79
+ $curl = Get-Command curl.exe -ErrorAction SilentlyContinue
80
+ if ($curl) {
81
+ Invoke-Native { & $curl.Source -fL --retry 3 -C - -o "$OutFile" "$Url" } "download $Url"
82
+ } else {
83
+ # Fallback for rare Windows machines without curl.exe (pre-1803).
84
+ Invoke-WebRequest -Uri $Url -OutFile $OutFile -UseBasicParsing
85
+ }
86
+ }
87
+
88
+ # Windows' native tar.exe (bsdtar). Invoked explicitly because a Git-Bash/MSYS
89
+ # `tar` earlier on PATH mis-parses C:\ paths as host:path remote syntax
90
+ # ("Cannot connect to C:"). Ships on Win10 1803+ alongside curl.exe.
91
+ $TarExe = Join-Path $env:SystemRoot 'System32\tar.exe'
92
+
93
+ # Apply CLI overrides.
94
+ if ($EnvName) { $script:ENV_NAME = $EnvName }
95
+ if ($SdkVersion) { $script:ZEPHYR_SDK_VERSION = $SdkVersion }
96
+
97
+ # --- platform detection (Windows only; the SDK ships no arm64 Windows bundle) -
98
+ $MambaPlat = 'win-64'
99
+ $SdkPlat = 'windows-x86_64'
100
+ $ArchiveExt = '7z'
101
+
102
+ # --- path resolution --------------------------------------------------------
103
+ if (-not $env:MAMBA_ROOT_PREFIX) { $env:MAMBA_ROOT_PREFIX = Join-Path $env:USERPROFILE 'micromamba' }
104
+ if (-not $env:WORKSPACE_DIR) { $env:WORKSPACE_DIR = Join-Path $env:USERPROFILE 'zephyrproject' }
105
+ $EnvPrefix = Join-Path $env:MAMBA_ROOT_PREFIX "envs\$ENV_NAME"
106
+ # The SDK lives OUTSIDE the conda env prefix: `micromamba create` requires the
107
+ # prefix to be empty, and a failed create must not trap a multi-GB SDK download.
108
+ # Keeping them decoupled means env create/remove never threatens the SDK.
109
+ if (-not $env:SDK_INSTALL_PARENT){ $env:SDK_INSTALL_PARENT = Join-Path $env:MAMBA_ROOT_PREFIX 'zephyr-sdk' }
110
+ $ZephyrSdkInstallDir = Join-Path $env:SDK_INSTALL_PARENT "zephyr-sdk-$ZEPHYR_SDK_VERSION"
111
+ $MambaExe = Join-Path $env:MAMBA_ROOT_PREFIX 'Library\bin\micromamba.exe'
112
+
113
+ # --- plan printer (mirrors install.sh's [plan] tags) ------------------------
114
+ # 1.0.x bundle flavor suffix (_gnu); empty for 0.17.x "full" bundles. Individual
115
+ # toolchain tarballs carry the flavor as an infix (toolchain_gnu_<plat>_<target>).
116
+ $SdkSuffix = if ($ZEPHYR_SDK_BUNDLE_SUFFIX) { $ZEPHYR_SDK_BUNDLE_SUFFIX } else { '' }
117
+ $TcInfix = if ($SdkSuffix) { $SdkSuffix.TrimStart('_') + '_' } else { '' }
118
+ $bundle = "zephyr-sdk-$ZEPHYR_SDK_VERSION`_$SdkPlat$SdkSuffix.$ArchiveExt"
119
+ Write-Host "[plan] typeCAD Zephyr installer"
120
+ Write-Host "[plan] env name: $ENV_NAME"
121
+ Write-Host "[plan] conda subdir: $MambaPlat"
122
+ Write-Host "[plan] sdk platform: $SdkPlat"
123
+ Write-Host "[plan] sdk version: $ZEPHYR_SDK_VERSION"
124
+ Write-Host "[plan] platforms: $(if ($Platforms) { $Platforms } else { 'all' })"
125
+ Write-Host "[plan] sdk bundle: $bundle"
126
+ Write-Host "[plan] sdk bundle url: $SDK_RELEASE_BASE/v$ZEPHYR_SDK_VERSION/$bundle"
127
+ Write-Host "[plan] micromamba url: $MICROMAMBA_BASE/$MambaPlat/latest"
128
+ Write-Host "[plan] micromamba bin: $MambaExe"
129
+ Write-Host "[plan] env prefix: $EnvPrefix"
130
+ Write-Host "[plan] sdk install dir: $ZephyrSdkInstallDir"
131
+ Write-Host "[plan] workspace dir: $env:WORKSPACE_DIR"
132
+ Write-Host "[plan] zephyr base: $(Join-Path $env:WORKSPACE_DIR 'zephyr')"
133
+ Write-Host "[plan] manifest url: $ZEPHYR_MANIFEST_URL"
134
+ Write-Host "[plan] manifest rev: $ZEPHYR_MANIFEST_REV"
135
+ Write-Host "[plan] do sdk: $(-not $NoSdk.IsPresent)"
136
+ Write-Host "[plan] do workspace: $(-not $NoWorkspace.IsPresent)"
137
+
138
+ if ($DryRun) {
139
+ Write-Host "[plan] DRY-RUN - no downloads, no env created."
140
+ exit 0
141
+ }
142
+
143
+ # --- 1. micromamba ----------------------------------------------------------
144
+ if (-not (Test-Path $MambaExe)) {
145
+ Write-Host "micromamba: downloading ($MambaPlat)..."
146
+ New-Item -ItemType Directory -Force -Path $env:MAMBA_ROOT_PREFIX | Out-Null
147
+ $tmp = Join-Path $env:TEMP 'typecad-micromamba.tar.bz2'
148
+ Download-File -Url "$MICROMAMBA_BASE/$MambaPlat/latest" -OutFile $tmp
149
+ # Win10+ ships tar.exe (bsdtar), which auto-detects .tar.bz2 compression.
150
+ Push-Location $env:MAMBA_ROOT_PREFIX
151
+ try { Invoke-Native { & $TarExe xf $tmp } "micromamba extract" } finally { Pop-Location }
152
+ Remove-Item $tmp -Force
153
+ if (-not (Test-Path $MambaExe)) {
154
+ $found = Get-ChildItem -Path $env:MAMBA_ROOT_PREFIX -Recurse -Filter 'micromamba.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
155
+ if ($found) { $MambaExe = $found.FullName } else { throw "micromamba: binary not found after extract" }
156
+ }
157
+ Write-Host "micromamba: installed at $MambaExe"
158
+ } else {
159
+ Write-Host "micromamba: already present at $MambaExe"
160
+ }
161
+
162
+ # Register the micromamba shell hook in the user's PowerShell profile so
163
+ # `micromamba` resolves and `micromamba activate <env>` works in NEW shells.
164
+ # This is required because the download above placed micromamba.exe under
165
+ # $MAMBA_ROOT_PREFIX\Library\bin\, which is NOT on PATH by default. The hook
166
+ # both adds it and defines the activate/deactivate functions. (The pipe form
167
+ # `... | Invoke-Expression` and the naive `Invoke-Expression "$(...)"` form both
168
+ # fail under PowerShell because multi-line output collapses to spaces;
169
+ # installing to the profile is the robust path.)
170
+ Write-Host "micromamba: registering shell hook in your PowerShell profile..."
171
+ Invoke-Native { & $MambaExe shell init -s powershell -r $env:MAMBA_ROOT_PREFIX } "micromamba shell init"
172
+
173
+ # --- 2. conda env -----------------------------------------------------------
174
+ if (Test-Path (Join-Path $EnvPrefix 'conda-meta')) {
175
+ Write-Host "env: '$ENV_NAME' already exists - updating"
176
+ Invoke-Native { & $MambaExe env update -y -f "$PackageDir\environment.yml" -p $EnvPrefix } "env update"
177
+ } elseif (Test-Path $EnvPrefix) {
178
+ # Prefix dir exists but is NOT a valid conda env (no conda-meta). This is the
179
+ # residue of a prior failed run; `micromamba create` would abort with
180
+ # "Non-conda folder exists at prefix". Surface it rather than auto-deleting a
181
+ # dir that may hold a multi-GB SDK.
182
+ throw @"
183
+ env: '$EnvPrefix' exists but is not a valid conda env (no conda-meta).
184
+ This is usually left by a prior failed install. Remove it and re-run:
185
+ Remove-Item -Recurse -Force '$EnvPrefix'
186
+ (If a zephyr-sdk-* folder is inside it, it's safe to delete - the SDK is fetched fresh.)
187
+ "@
188
+ } else {
189
+ Write-Host "env: creating '$ENV_NAME' from environment.yml..."
190
+ Invoke-Native { & $MambaExe create -y -f "$PackageDir\environment.yml" -n $ENV_NAME } "env create"
191
+ }
192
+
193
+ # 7zip: required to extract the .7z Windows SDK bundle. conda-forge ships it
194
+ # for win-64. Warn-and-continue here; the fetch-sdk step re-checks 7z and
195
+ # throws a clear error if it's truly unavailable (e.g. pre-1803 Windows).
196
+ Write-Host "env: installing 7zip (for .7z SDK extraction)..."
197
+ & $MambaExe install -y -n $ENV_NAME -c conda-forge 7zip
198
+ if ($LASTEXITCODE -ne 0) {
199
+ Write-Warning "env: 7zip install failed (exit $LASTEXITCODE) - SDK .7z extraction will need 7z.exe elsewhere."
200
+ }
201
+
202
+ # dfu-util: west flash's dfu-util runner (STM32 ROM DFU bootloader boards,
203
+ # e.g. the WeAct Black Pill) shells out to dfu-util, and the runner dies with
204
+ # a raw FileNotFoundError when the executable is missing. conda-forge has no
205
+ # dfu-util build, so fetch MSYS2's mingw64 dfu-util package plus the
206
+ # libusb / libwinpthread runtime DLLs it links, and unpack them into the
207
+ # env's Library\bin — that dir is on the activation PATH and on the PATH of
208
+ # the `micromamba run -n zephyr west flash` the framework toolchain spawns,
209
+ # so flashing works without a global dfu-util install. Idempotent: skipped
210
+ # when dfu-util.exe is already in place. Warn-and-continue on any failure
211
+ # (it only affects DFU-bootloader boards).
212
+ $dfuBinDir = Join-Path $EnvPrefix 'Library\bin'
213
+ if (Test-Path (Join-Path $dfuBinDir 'dfu-util.exe')) {
214
+ Write-Host "dfu-util: already present - skipping"
215
+ } else {
216
+ $dfu7z = Get-ChildItem -Path $EnvPrefix -Recurse -Filter '7z.exe' -ErrorAction SilentlyContinue `
217
+ | Select-Object -First 1 -ExpandProperty FullName
218
+ if (-not $dfu7z) { $found = Get-Command 7z -ErrorAction SilentlyContinue; if ($found) { $dfu7z = $found.Source } }
219
+ if (-not $dfu7z) {
220
+ Write-Warning "dfu-util: 7z.exe not found - skipping (west flash on DFU-bootloader boards will need dfu-util on PATH)."
221
+ } else {
222
+ try {
223
+ New-Item -ItemType Directory -Force -Path $dfuBinDir | Out-Null
224
+ $dfuTmp = Join-Path ([System.IO.Path]::GetTempPath()) "tc-dfu-util-$PID"
225
+ New-Item -ItemType Directory -Force -Path $dfuTmp | Out-Null
226
+ # Each package is a .zst wrapping a .tar; 7z handles both layers.
227
+ $dfuPkgs = @(
228
+ @{ Name = $DFU_UTIL_PKG; Sha256 = $DFU_UTIL_PKG_SHA256 },
229
+ @{ Name = $LIBUSB_PKG; Sha256 = $LIBUSB_PKG_SHA256 },
230
+ @{ Name = $LIBWINPTHREAD_PKG; Sha256 = $LIBWINPTHREAD_PKG_SHA256 }
231
+ )
232
+ foreach ($pkg in $dfuPkgs) {
233
+ $zst = Join-Path $dfuTmp "$($pkg.Name)-any.pkg.tar.zst"
234
+ Download-File -Url "$MSYS2_MINGW64_BASE/$($pkg.Name)-any.pkg.tar.zst" -OutFile $zst
235
+ $actual = (Get-FileHash $zst -Algorithm SHA256).Hash.ToLower()
236
+ if ($pkg.Sha256 -and $pkg.Sha256 -ne 'TODO' -and $actual -ne $pkg.Sha256.ToLower()) {
237
+ throw "SHA256 mismatch for $($pkg.Name) (expected $($pkg.Sha256), got $actual)"
238
+ }
239
+ Invoke-Native { & $dfu7z x -y "-o$dfuTmp" $zst } "dfu-util extract zst ($($pkg.Name))"
240
+ $tar = Join-Path $dfuTmp "$($pkg.Name)-any.pkg.tar"
241
+ Invoke-Native { & $dfu7z x -y "-o$(Join-Path $dfuTmp "x-$($pkg.Name)")" $tar } "dfu-util extract tar ($($pkg.Name))"
242
+ }
243
+ # Payload: the three dfu-* executables + the two runtime DLLs.
244
+ foreach ($root in @(
245
+ (Join-Path $dfuTmp "x-$DFU_UTIL_PKG\mingw64\bin"),
246
+ (Join-Path $dfuTmp "x-$LIBUSB_PKG\mingw64\bin"),
247
+ (Join-Path $dfuTmp "x-$LIBWINPTHREAD_PKG\mingw64\bin")
248
+ )) {
249
+ if (Test-Path $root) { Copy-Item (Join-Path $root '*') $dfuBinDir -Force }
250
+ }
251
+ Remove-Item -Recurse -Force $dfuTmp -ErrorAction SilentlyContinue
252
+ Write-Host "dfu-util: installed - $(Join-Path $dfuBinDir 'dfu-util.exe')"
253
+ } catch {
254
+ Write-Warning "dfu-util: install failed ($_) - west flash on DFU-bootloader boards will need dfu-util on PATH."
255
+ }
256
+ }
257
+ }
258
+
259
+ # bossac: west flash's bossac runner (SAMD SAM-BA bootloader boards - the
260
+ # Arduino Nano 33 IoT, Zero, MKR series) shells out to bossac. Zephyr's
261
+ # FindHostTools resolves find_program(BOSSAC) at BUILD-CONFIGURE time, so a
262
+ # missing binary gets baked into the runner args (BOSSAC-NOTFOUND) and west
263
+ # flash dies with "required program bossac not found" even after bossac
264
+ # lands on PATH without a reconfigure. bossac is in neither the Zephyr SDK
265
+ # nor conda-forge; the official upstream MSI extracts cleanly with 7z and
266
+ # ships a self-contained bossac.exe (system DLLs only). Same placement rules
267
+ # as dfu-util above. Idempotent; warn-and-continue (SAM-BA boards only).
268
+ if (Test-Path (Join-Path $dfuBinDir 'bossac.exe')) {
269
+ Write-Host "bossac: already present - skipping"
270
+ } else {
271
+ $bossa7z = Get-ChildItem -Path $EnvPrefix -Recurse -Filter '7z.exe' -ErrorAction SilentlyContinue `
272
+ | Select-Object -First 1 -ExpandProperty FullName
273
+ if (-not $bossa7z) { $found = Get-Command 7z -ErrorAction SilentlyContinue; if ($found) { $bossa7z = $found.Source } }
274
+ if (-not $bossa7z) {
275
+ Write-Warning "bossac: 7z.exe not found - skipping (west flash on SAM-BA-bootloader boards will need bossac on PATH)."
276
+ } else {
277
+ try {
278
+ $bossaTmp = Join-Path ([System.IO.Path]::GetTempPath()) "tc-bossa-$PID"
279
+ New-Item -ItemType Directory -Force -Path $bossaTmp | Out-Null
280
+ $msi = Join-Path $bossaTmp 'bossa-x64.msi'
281
+ Download-File -Url $BOSSA_URL -OutFile $msi
282
+ $actual = (Get-FileHash $msi -Algorithm SHA256).Hash.ToLower()
283
+ if ($BOSSA_SHA256 -and $actual -ne $BOSSA_SHA256.ToLower()) {
284
+ throw "SHA256 mismatch for bossac MSI (expected $BOSSA_SHA256, got $actual)"
285
+ }
286
+ Invoke-Native { & $bossa7z x -y "-o$bossaTmp" $msi } "bossac extract msi"
287
+ if (-not (Test-Path (Join-Path $bossaTmp 'bossac.exe'))) { throw "bossac.exe not found in MSI payload" }
288
+ Copy-Item (Join-Path $bossaTmp 'bossac.exe') $dfuBinDir -Force
289
+ Remove-Item -Recurse -Force $bossaTmp -ErrorAction SilentlyContinue
290
+ Write-Host "bossac: installed - $(Join-Path $dfuBinDir 'bossac.exe')"
291
+ } catch {
292
+ Write-Warning "bossac: install failed ($_) - west flash on SAM-BA-bootloader boards will need bossac on PATH."
293
+ }
294
+ }
295
+ }
296
+
297
+ # --- 3. activation hooks ----------------------------------------------------
298
+ $actDst = Join-Path $EnvPrefix 'etc\conda\activate.d'
299
+ $deactDst = Join-Path $EnvPrefix 'etc\conda\deactivate.d'
300
+ New-Item -ItemType Directory -Force -Path $actDst, $deactDst | Out-Null
301
+ $zb = Join-Path $env:WORKSPACE_DIR 'zephyr'
302
+
303
+ # Resolved env-vars (PowerShell + cmd). Values live here; hooks stay static.
304
+ @(
305
+ "# Resolved by the typeCAD Zephyr installer. Dot-sourced by activate.d/zephyr.ps1.",
306
+ "`$env:TYPECAD_ZEPHYR_BASE = `"$zb`"",
307
+ "`$env:TYPECAD_ZEPHYR_SDK_INSTALL_DIR = `"$ZephyrSdkInstallDir`""
308
+ ) -join "`n" | Set-Content -NoNewline (Join-Path $EnvPrefix 'etc\conda\env-vars.ps1')
309
+
310
+ @"
311
+ @echo off
312
+ set `"TYPECAD_ZEPHYR_BASE=$zb`"
313
+ set `"TYPECAD_ZEPHYR_SDK_INSTALL_DIR=$ZephyrSdkInstallDir`"
314
+ "@ | Set-Content (Join-Path $EnvPrefix 'etc\conda\env-vars.bat')
315
+
316
+ Copy-Item "$PackageDir\etc\conda\activate.d\zephyr.ps1" (Join-Path $actDst 'zephyr.ps1') -Force
317
+ Copy-Item "$PackageDir\etc\conda\activate.d\zephyr.bat" (Join-Path $actDst 'zephyr.bat') -Force
318
+ Copy-Item "$PackageDir\etc\conda\deactivate.d\zephyr.ps1" (Join-Path $deactDst 'zephyr.ps1') -Force
319
+ Copy-Item "$PackageDir\etc\conda\deactivate.d\zephyr.bat" (Join-Path $deactDst 'zephyr.bat') -Force
320
+ Write-Host "write-activation: done"
321
+
322
+ # --- 4. Zephyr SDK (.7z) ----------------------------------------------------
323
+ if (-not $NoSdk) {
324
+ # Locate 7z once (used by both full-bundle and selective paths).
325
+ # Normalize to the executable path: Get-ChildItem yields a FileInfo (.FullName),
326
+ # Get-Command yields a CommandInfo (.Source) - only one of which is populated.
327
+ $sevenz = Get-ChildItem -Path $EnvPrefix -Recurse -Filter '7z.exe' -ErrorAction SilentlyContinue `
328
+ | Select-Object -First 1 -ExpandProperty FullName
329
+ if (-not $sevenz) { $found = Get-Command 7z -ErrorAction SilentlyContinue; if ($found) { $sevenz = $found.Source } }
330
+ if (-not $sevenz) { $sevenz = $null } # only fatal when extraction is needed
331
+
332
+ $sel = if ($Platforms) { $Platforms } else { 'all' }
333
+ Write-Host "fetch-sdk: platform selection: $sel"
334
+
335
+ if ($sel -eq 'all') {
336
+ # ── FULL BUNDLE (current behavior) ──────────────────────────────────────
337
+ # Idempotent: the SDK full bundle ships a top-level `sdk_version` file once
338
+ # extracted, so its presence means the SDK is already in place.
339
+ if (Test-Path (Join-Path $ZephyrSdkInstallDir 'sdk_version')) {
340
+ Write-Host "fetch-sdk: already present at $ZephyrSdkInstallDir - skipping download"
341
+ } else {
342
+ $url = "$SDK_RELEASE_BASE/v$ZEPHYR_SDK_VERSION/$bundle"
343
+ Write-Host "fetch-sdk: downloading full bundle $bundle from $url"
344
+ New-Item -ItemType Directory -Force -Path $env:SDK_INSTALL_PARENT | Out-Null
345
+ $archive = Join-Path $env:SDK_INSTALL_PARENT $bundle
346
+ Download-File -Url $url -OutFile $archive
347
+ # Verify (skip when TODO).
348
+ $checksumVar = 'SHA256_' + ($SdkPlat -replace '-', '_')
349
+ $expected = (Get-Variable -Name $checksumVar -ErrorAction SilentlyContinue).Value
350
+ $actual = (Get-FileHash $archive -Algorithm SHA256).Hash.ToLower()
351
+ if (-not $expected -or $expected -eq 'TODO') {
352
+ Write-Warning "fetch-sdk: SHA256 not pinned (TODO in versions.env); computed: $actual"
353
+ } elseif ($actual -ne $expected.ToLower()) {
354
+ throw "fetch-sdk: SHA256 mismatch (expected $expected, got $actual)"
355
+ } else {
356
+ Write-Host "fetch-sdk: sha256 OK ($actual)"
357
+ }
358
+ if (-not $sevenz) { throw "fetch-sdk: 7z.exe not found in env or on PATH" }
359
+ Invoke-Native { & $sevenz x -y "-o$env:SDK_INSTALL_PARENT" $archive } "fetch-sdk 7z extract"
360
+ Remove-Item $archive -Force
361
+ Write-Host "fetch-sdk: done - $ZephyrSdkInstallDir"
362
+ }
363
+ } else {
364
+ # ── SELECTIVE: minimal bundle + individual toolchains ───────────────────
365
+ $minimal = "zephyr-sdk-$ZEPHYR_SDK_VERSION`_$SdkPlat`_minimal.$ArchiveExt"
366
+ $minimalUrl = "$SDK_RELEASE_BASE/v$ZEPHYR_SDK_VERSION/$minimal"
367
+
368
+ if ($DryRun) {
369
+ Write-Host "fetch-sdk: [DRY-RUN] would download minimal $minimalUrl (~10 MB)"
370
+ Write-Host "fetch-sdk: [DRY-RUN] selected platforms: $sel"
371
+ foreach ($grp in $sel.Split(',')) {
372
+ $tv = (Get-Variable -Name "PLATFORM_$grp" -ErrorAction SilentlyContinue).Value
373
+ Write-Host "fetch-sdk: [DRY-RUN] ${grp}: $tv"
374
+ }
375
+ } else {
376
+ New-Item -ItemType Directory -Force -Path $env:SDK_INSTALL_PARENT | Out-Null
377
+
378
+ # 1. Minimal bundle (cmake/ + sdk_version — ~10 MB).
379
+ if (Test-Path (Join-Path $ZephyrSdkInstallDir 'sdk_version')) {
380
+ Write-Host "fetch-sdk: SDK base already present - skipping minimal bundle"
381
+ } else {
382
+ Write-Host "fetch-sdk: downloading minimal bundle (~10 MB)"
383
+ $minArchive = Join-Path $env:SDK_INSTALL_PARENT $minimal
384
+ Download-File -Url $minimalUrl -OutFile $minArchive
385
+ if (-not $sevenz) { throw "fetch-sdk: 7z.exe not found in env or on PATH" }
386
+ Invoke-Native { & $sevenz x -y "-o$env:SDK_INSTALL_PARENT" $minArchive } "fetch-sdk minimal extract"
387
+ Remove-Item $minArchive -Force
388
+ }
389
+
390
+ # 1.0.x installs toolchains under <sdk>\gnu\ - the SDK's own setup.cmd
391
+ # does `pushd gnu; 7z x`, and its cmake globs
392
+ # ${ZEPHYR_SDK_INSTALL_DIR}/gnu/*. 0.17.x used the SDK root. Toolchains
393
+ # misplaced at the root by older installers are migrated (moved) into
394
+ # gnu\ instead of re-downloaded. Idempotency checks <target>\bin - a
395
+ # bare <target>\ dir can be a hollow leftover of a failed setup.cmd
396
+ # toolchain download.
397
+ $tcRoot = if ($TcInfix) { Join-Path $ZephyrSdkInstallDir 'gnu' } else { $ZephyrSdkInstallDir }
398
+ New-Item -ItemType Directory -Force -Path $tcRoot | Out-Null
399
+
400
+ # 2. Individual toolchains per selected platform group.
401
+ foreach ($grp in $sel.Split(',')) {
402
+ $targets = (Get-Variable -Name "PLATFORM_$grp" -ErrorAction SilentlyContinue).Value
403
+ if (-not $targets) {
404
+ Write-Warning "fetch-sdk: unknown platform group '$grp' (no PLATFORM_$grp in versions.env); skipping"
405
+ continue
406
+ }
407
+ Write-Host "fetch-sdk: platform '${grp}':"
408
+ foreach ($target in $targets.Split(' ')) {
409
+ if (-not $target) { continue }
410
+ $misplaced = if ($TcInfix) { Join-Path $ZephyrSdkInstallDir $target } else { $null }
411
+ # Migrate / clean a misplaced SDK-root copy from pre-1.0.x-layout installs.
412
+ if ($misplaced -and (Test-Path $misplaced)) {
413
+ if (Test-Path (Join-Path $tcRoot "$target\bin")) {
414
+ Write-Host "fetch-sdk: $target - removing misplaced SDK-root copy (pre-1.0.x-layout install)"
415
+ Remove-Item -Recurse -Force $misplaced
416
+ } else {
417
+ Write-Host "fetch-sdk: $target - migrating misplaced SDK-root copy into gnu\"
418
+ Move-Item $misplaced (Join-Path $tcRoot $target)
419
+ }
420
+ continue
421
+ }
422
+ if (Test-Path (Join-Path $tcRoot "$target\bin")) {
423
+ Write-Host "fetch-sdk: $target - already installed, skipping"
424
+ continue
425
+ }
426
+ # A target dir without bin\ is a hollow leftover - re-download clean.
427
+ if (Test-Path (Join-Path $tcRoot $target)) {
428
+ Write-Host "fetch-sdk: $target - hollow toolchain dir (no bin\), re-downloading"
429
+ Remove-Item -Recurse -Force (Join-Path $tcRoot $target)
430
+ }
431
+ $tcBundle = "toolchain_$TcInfix$($SdkPlat)_$($target).$ArchiveExt"
432
+ $tcUrl = "$SDK_RELEASE_BASE/v$ZEPHYR_SDK_VERSION/$tcBundle"
433
+ Write-Host "fetch-sdk: $target - downloading $tcBundle"
434
+ $tcArchive = Join-Path $env:SDK_INSTALL_PARENT $tcBundle
435
+ Download-File -Url $tcUrl -OutFile $tcArchive
436
+ if (-not $sevenz) { throw "fetch-sdk: 7z.exe not found in env or on PATH" }
437
+ Invoke-Native { & $sevenz x -y "-o$tcRoot" $tcArchive } "fetch-sdk $target extract"
438
+ Remove-Item $tcArchive -Force
439
+ }
440
+ }
441
+
442
+ # 3. -Prune only: remove toolchains installed but NOT in the new
443
+ # selection. Without -Prune the modify step is purely additive —
444
+ # unselected toolchains stay on disk so an existing install never
445
+ # loses anything because of a narrower re-run. On 1.0.x scan both
446
+ # the gnu root and the SDK root so misplaced copies get cleaned up.
447
+ if ($Prune) {
448
+ $selectedTargets = @()
449
+ foreach ($grp in $sel.Split(',')) {
450
+ $t = (Get-Variable -Name "PLATFORM_$grp" -ErrorAction SilentlyContinue).Value
451
+ if ($t) { $selectedTargets += $t.Split(' ') }
452
+ }
453
+ $scanDirs = @($tcRoot)
454
+ if ($TcInfix) { $scanDirs += $ZephyrSdkInstallDir }
455
+ Get-ChildItem -Path $scanDirs -Directory -ErrorAction SilentlyContinue |
456
+ Where-Object { $_.Name -match '^(xtensa-)?.*-zephyr-(eabi|elf)$' } |
457
+ ForEach-Object {
458
+ if ($selectedTargets -notcontains $_.Name) {
459
+ Write-Host "fetch-sdk: removing deselected toolchain: $($_.Name)"
460
+ Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue
461
+ }
462
+ }
463
+ }
464
+
465
+ # 4. Persist the selection. Without -Prune the marker records the UNION
466
+ # of what was here before and the new selection — the marker must
467
+ # describe what is actually on disk, and a narrower re-run must not
468
+ # make previously installed groups vanish from the record.
469
+ $markerPath = Join-Path $ZephyrSdkInstallDir '.typecad-platforms'
470
+ $markerSel = $sel
471
+ if (-not $Prune -and (Test-Path $markerPath)) {
472
+ $prev = (Get-Content $markerPath -Raw).Trim()
473
+ if ($prev) {
474
+ $union = @()
475
+ foreach ($grp in ($prev.Split(',') + $sel.Split(','))) {
476
+ $g = $grp.Trim()
477
+ if ($g -and ($g -ne 'all') -and ($union -notcontains $g)) { $union += $g }
478
+ }
479
+ $markerSel = $union -join ','
480
+ }
481
+ }
482
+ Set-Content -Path $markerPath -Value $markerSel
483
+ Write-Host "fetch-sdk: done - $ZephyrSdkInstallDir (platforms: $sel)"
484
+ }
485
+ }
486
+ } else {
487
+ Write-Host "install: -NoSdk - skipping Zephyr SDK download"
488
+ }
489
+
490
+ # --- 5. west workspace ------------------------------------------------------
491
+ if ($Modify) { Write-Host "install: -Modify - skipping west workspace" }
492
+ elseif (-not $NoWorkspace) {
493
+ Write-Host "init-workspace: west init $env:WORKSPACE_DIR"
494
+ $westDir = Join-Path $env:WORKSPACE_DIR '.west'
495
+ $westConfig = Join-Path $westDir 'config'
496
+ if ((Test-Path $westDir) -and (Test-Path $westConfig)) {
497
+ Write-Host "init-workspace: already initialized - running west update only"
498
+ # A workspace adopted from a pre-existing install (or initialized by an
499
+ # older installer) can track a branch or an older tag - plain `west update`
500
+ # never moves the manifest repository, so it drifts out of sync with the
501
+ # SDK this installer pins. Re-pin the revision AND check the tag out so
502
+ # west update below syncs modules against the pinned manifest.
503
+ Push-Location $env:WORKSPACE_DIR
504
+ try {
505
+ $curRev = (& $MambaExe run -n $ENV_NAME west config manifest.revision)
506
+ if ($LASTEXITCODE -ne 0) { $curRev = '' }
507
+ if ("$curRev".Trim() -ne $ZEPHYR_MANIFEST_REV) {
508
+ $was = if ("$curRev".Trim()) { "$curRev" } else { '<unset - default branch>' }
509
+ Write-Host "init-workspace: pinning manifest revision -> $ZEPHYR_MANIFEST_REV (was: $was)"
510
+ }
511
+ # All three steps are idempotent; they must also run when the config
512
+ # already says the right thing but the tree is still on the old revision.
513
+ Invoke-Native { & $MambaExe run -n $ENV_NAME west config manifest.revision $ZEPHYR_MANIFEST_REV } "west config manifest.revision"
514
+ Invoke-Native { & $MambaExe run -n $ENV_NAME git -C $zb fetch origin "refs/tags/${ZEPHYR_MANIFEST_REV}:refs/tags/${ZEPHYR_MANIFEST_REV}" } "git fetch tag $ZEPHYR_MANIFEST_REV"
515
+ Invoke-Native { & $MambaExe run -n $ENV_NAME git -C $zb checkout $ZEPHYR_MANIFEST_REV } "git checkout $ZEPHYR_MANIFEST_REV"
516
+ } finally { Pop-Location }
517
+ } else {
518
+ if (Test-Path $westDir) {
519
+ Write-Host "init-workspace: .west exists but its config is missing (interrupted init?) - re-initializing"
520
+ Remove-Item -Recurse -Force $westDir
521
+ }
522
+ $parent = Split-Path -Parent $env:WORKSPACE_DIR
523
+ New-Item -ItemType Directory -Force -Path $parent | Out-Null
524
+ Invoke-Native { & $MambaExe run -n $ENV_NAME west init -m $ZEPHYR_MANIFEST_URL --mr $ZEPHYR_MANIFEST_REV $env:WORKSPACE_DIR } "west init"
525
+ }
526
+ Write-Host "init-workspace: running west update (fetches zephyr + modules)..."
527
+ Invoke-Native { & $MambaExe run -n $ENV_NAME west update } "west update"
528
+ # Workspace patches — upstream fixes the pinned manifest revisions don't
529
+ # carry yet. Applied with `git apply --check` first so an already-applied
530
+ # (or already-upstreamed) patch is skipped, never a hard failure. Each
531
+ # patch carries a `# typecad-repo: <workspace-relative path>` header naming
532
+ # the repo it patches (first-directory guesses break on nested projects).
533
+ $patchesDir = Join-Path $PSScriptRoot 'patches'
534
+ if (Test-Path $patchesDir) {
535
+ foreach ($patch in Get-ChildItem -Path $patchesDir -Filter '*.patch' | Sort-Object Name) {
536
+ $patchText = Get-Content $patch.FullName -Raw
537
+ $repoName = if ($patchText -match '# typecad-repo:\s*(\S+)') { $Matches[1] } else { $null }
538
+ if (-not $repoName) { Write-Warning "workspace-patch: $($patch.Name) - no 'typecad-repo:' header, skipping"; continue }
539
+ $repoDir = Join-Path $env:WORKSPACE_DIR ($repoName -replace '/', '\')
540
+ if (-not (Test-Path $repoDir)) { Write-Warning "workspace-patch: $($patch.Name) - $repoDir not present, skipping"; continue }
541
+ Write-Host "init-workspace: applying patch $($patch.Name) to $repoName..."
542
+ # `git apply --check` probes applicability WITHOUT touching stderr —
543
+ # PS 5.1 wraps redirected native stderr in ErrorRecords (never redirect
544
+ # native stderr through the pipeline), so the probe shells out via
545
+ # Start-Process with a file redirect: exit 0 = applicable, else already
546
+ # applied / inapplicable.
547
+ $checkErr = Join-Path $env:TEMP "typecad-patch-check.$PID.err"
548
+ $probe = Start-Process -FilePath 'git' `
549
+ -ArgumentList @('-C', $repoDir, 'apply', '--check', $patch.FullName) `
550
+ -NoNewWindow -Wait -PassThru -RedirectStandardError $checkErr
551
+ if ($probe.ExitCode -ne 0) {
552
+ Remove-Item $checkErr -Force -ErrorAction SilentlyContinue
553
+ Write-Host "init-workspace: already applied (or inapplicable) - skipping"
554
+ } else {
555
+ Remove-Item $checkErr -Force -ErrorAction SilentlyContinue
556
+ Invoke-Native { & git -C $repoDir apply $patch.FullName } "workspace patch $($patch.Name)"
557
+ }
558
+ }
559
+ }
560
+ # Install Zephyr's pinned Python build deps (jsonschema, pykwalify, ...). CMake
561
+ # checks for these and the build fails with "Missing jsonschema dependency"
562
+ # without them; letting Zephyr's requirements file drive it tracks the revision.
563
+ Write-Host "init-workspace: installing Zephyr Python requirements (requirements-base.txt)..."
564
+ Invoke-Native { & $MambaExe run -n $ENV_NAME pip install -r "$zb\scripts\requirements-base.txt" } "pip install zephyr requirements"
565
+ # imgtool — MCUboot's signing tool. Not in requirements-base.txt, but TF-M /
566
+ # FVP signing steps invoke it as a module (mps4 corstone builds fail with
567
+ # "No module named 'imgtool'" without it).
568
+ Invoke-Native { & $MambaExe run -n $ENV_NAME pip install imgtool } "pip install imgtool"
569
+ # TF-M secure-build tooling: the inner TF-M build's bl2_image_config step
570
+ # parses compile_commands (needs the `clang` python bindings) and Nordic's
571
+ # RTE_Device.h needs devicetree headers — requirements + libclang (native
572
+ # library the python `clang` bindings load) from conda-forge.
573
+ $tfmTools = Join-Path $env:WORKSPACE_DIR 'modules/tee/tf-m/trusted-firmware-m/tools/requirements.txt'
574
+ if (Test-Path $tfmTools) {
575
+ Invoke-Native { & $MambaExe run -n $ENV_NAME pip install -r $tfmTools } "pip install TF-M tools requirements"
576
+ }
577
+ Invoke-Native { & $MambaExe install -n $ENV_NAME -c conda-forge libclang -y } "micromamba install libclang"
578
+ # Build-relevant per-module Python requirements ONLY (not docs/test/harness).
579
+ # HAL scripts/zephyr dirs (esptool for espressif, vendor tools) + top-level lib
580
+ # codegen (nanopb, zcbor). Board support is universal (west fetched every
581
+ # module, SDK ships every cross-toolchain); these are the few build extras.
582
+ Write-Host "init-workspace: installing per-module Python requirements (build tooling only)..."
583
+ $patterns = @(
584
+ (Join-Path $env:WORKSPACE_DIR 'modules/hal/*/scripts/requirements.txt'),
585
+ (Join-Path $env:WORKSPACE_DIR 'modules/hal/*/zephyr/requirements.txt'),
586
+ (Join-Path $env:WORKSPACE_DIR 'modules/lib/*/requirements.txt'),
587
+ (Join-Path $env:WORKSPACE_DIR 'modules/lib/*/scripts/requirements.txt')
588
+ )
589
+ foreach ($pat in $patterns) {
590
+ foreach ($req in Get-Item -Path $pat -ErrorAction SilentlyContinue) {
591
+ # Do NOT add a native stderr redirect on this call: under
592
+ # $ErrorActionPreference='Stop', PowerShell 5.1 wraps redirected native
593
+ # stderr in ErrorRecords and the first one becomes a TERMINATING error -
594
+ # pip's live "Running command git clone ..." relay for git-pinned
595
+ # packages (silabs' cmsis-svd) aborted the whole install this way.
596
+ # Un-redirected native stderr just prints to the console.
597
+ & $MambaExe run -n $ENV_NAME pip install -r $req.FullName
598
+ if ($LASTEXITCODE -ne 0) { Write-Warning "init-workspace: module requirements failed: $($req.FullName)" }
599
+ }
600
+ }
601
+ Write-Host "init-workspace: done - ZEPHYR_BASE=$zb"
602
+ } else {
603
+ Write-Host "install: -NoWorkspace - skipping west init/update"
604
+ }
605
+
606
+ # --- done -------------------------------------------------------------------
607
+ Write-Host ""
608
+ Write-Host "install: done."
609
+ Write-Host "The micromamba shell hook has been added to your PowerShell profile."
610
+ Write-Host "Open a NEW PowerShell window (or reload it with '. `$PROFILE'), then:"
611
+ Write-Host " micromamba activate $ENV_NAME"
612
+ Write-Host ""
613
+ Write-Host "Verify:"
614
+ Write-Host " west --version"
615
+ Write-Host " echo `$env:ZEPHYR_BASE # -> $zb"
616
+ Write-Host ""
617
+ Write-Host "For the CURRENT session without a new window, run this (robust hook-load):"
618
+ Write-Host " Invoke-Expression ((& '$MambaExe' shell hook -s powershell) -join [char]10)"
619
+ Write-Host " micromamba activate $ENV_NAME"