@typecad/cuttlefish 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 (343) hide show
  1. package/README.md +82 -79
  2. package/assets/editor-extensions/typecad-debug/README.md +141 -0
  3. package/assets/editor-extensions/typecad-debug/out/extension.js +347 -0
  4. package/assets/editor-extensions/typecad-debug/out/extension.js.map +1 -0
  5. package/assets/editor-extensions/typecad-debug/package.json +76 -0
  6. package/assets/editor-extensions/typecad-ui/LICENSE +27 -0
  7. package/assets/editor-extensions/typecad-ui/README.md +52 -0
  8. package/assets/editor-extensions/typecad-ui/file-icon-dark.png +0 -0
  9. package/assets/editor-extensions/typecad-ui/file-icon-light.png +0 -0
  10. package/assets/editor-extensions/typecad-ui/icon.png +0 -0
  11. package/assets/editor-extensions/typecad-ui/language-configuration.json +43 -0
  12. package/assets/editor-extensions/typecad-ui/package.json +54 -0
  13. package/assets/editor-extensions/typecad-ui/snippets/typecad-ui.json +80 -0
  14. package/assets/editor-extensions/typecad-ui/syntaxes/markdown-ui.json +45 -0
  15. package/assets/editor-extensions/typecad-ui/syntaxes/typecad-ui.tmLanguage.json +1269 -0
  16. package/dist/api/config.d.ts +30 -27
  17. package/dist/api/schema/types.d.ts +20 -3
  18. package/dist/api/shared/async-runtime-static.d.ts +1 -1
  19. package/dist/api/shared/async-runtime-static.js +5 -5
  20. package/dist/api/shared/async-types.d.ts +3 -2
  21. package/dist/api/shared/board-catalog.d.ts +2 -0
  22. package/dist/api/shared/board-catalog.js +6 -0
  23. package/dist/api/shared/board-resolver.d.ts +4 -7
  24. package/dist/api/shared/board-resolver.js +2 -1
  25. package/dist/api/shared/coop-scheduler.d.ts +1 -1
  26. package/dist/api/shared/coop-scheduler.js +1 -1
  27. package/dist/api/shared/cpp-type-ir.d.ts +1 -1
  28. package/dist/api/shared/cpp-type-ir.js +1 -1
  29. package/dist/api/shared/display-profile.d.ts +1 -1
  30. package/dist/api/shared/display-profile.js +3 -5
  31. package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
  32. package/dist/api/shared/framework-manifest-registry.js +0 -1
  33. package/dist/api/shared/framework-manifest.d.ts +65 -507
  34. package/dist/api/shared/framework-manifest.js +6 -11
  35. package/dist/api/shared/hal-op-ir.d.ts +294 -685
  36. package/dist/api/shared/hal-op-ir.js +31 -65
  37. package/dist/api/shared/index.d.ts +0 -4
  38. package/dist/api/shared/index.js +1 -7
  39. package/dist/api/shared/ir-core.d.ts +6 -0
  40. package/dist/api/shared/ir-declarations.d.ts +4 -0
  41. package/dist/api/shared/ir.d.ts +1 -3
  42. package/dist/api/shared/platform-strategy.d.ts +14 -37
  43. package/dist/api/shared/polyfill-helper-registry.js +0 -5
  44. package/dist/api/shared/polyfill-types.js +0 -27
  45. package/dist/api/shared/promise-runtime.js +3 -3
  46. package/dist/api/shared/spdx-licenses.d.ts +12 -10
  47. package/dist/api/shared/spdx-licenses.js +1 -1
  48. package/dist/api/shared/toolchain-types.d.ts +1 -1
  49. package/dist/api/shared/toolchain-types.js +3 -3
  50. package/dist/api/shared/types.d.ts +0 -3
  51. package/dist/api/shared/validate-framework-manifest.js +13 -33
  52. package/dist/board-catalog/dts-reader.d.ts +220 -0
  53. package/dist/board-catalog/dts-reader.js +1052 -0
  54. package/dist/board-catalog/index.d.ts +11 -0
  55. package/dist/board-catalog/index.js +12 -0
  56. package/dist/board-catalog/pinconfig.d.ts +48 -0
  57. package/dist/board-catalog/pinconfig.js +263 -0
  58. package/dist/board-catalog/sdk.d.ts +82 -0
  59. package/dist/board-catalog/sdk.js +180 -0
  60. package/dist/board-catalog/store.d.ts +196 -0
  61. package/dist/board-catalog/store.js +363 -0
  62. package/dist/board-catalog/types.d.ts +233 -0
  63. package/dist/board-catalog/types.js +7 -0
  64. package/dist/board-catalog/walker.d.ts +112 -0
  65. package/dist/board-catalog/walker.js +1101 -0
  66. package/dist/cli-utils.d.ts +2 -2
  67. package/dist/cli-utils.js +5 -5
  68. package/dist/cli.js +227 -244
  69. package/dist/config-loader.d.ts +14 -19
  70. package/dist/config-loader.js +242 -78
  71. package/dist/config-schema.d.ts +19 -227
  72. package/dist/config-schema.js +9 -8
  73. package/dist/contract/board-generator.d.ts +4 -4
  74. package/dist/contract/board-generator.js +16 -5
  75. package/dist/contract/contract-parser.d.ts +36 -127
  76. package/dist/contract/contract-parser.js +76 -0
  77. package/dist/contract/index.d.ts +1 -1
  78. package/dist/contract/index.js +70 -21
  79. package/dist/create/active-board-catalog.d.ts +9 -0
  80. package/dist/create/active-board-catalog.js +94 -0
  81. package/dist/create/board-catalog.generated.d.ts +96 -0
  82. package/dist/create/board-catalog.generated.js +128737 -0
  83. package/dist/create/board-search.d.ts +23 -0
  84. package/dist/create/board-search.js +88 -0
  85. package/dist/create/editor-integration.d.ts +32 -0
  86. package/dist/create/editor-integration.js +257 -0
  87. package/dist/create/eslint-rules-template.d.ts +2 -2
  88. package/dist/create/framework-catalog.d.ts +48 -8
  89. package/dist/create/framework-catalog.js +58 -44
  90. package/dist/create/index.d.ts +8 -13
  91. package/dist/create/index.js +5 -9
  92. package/dist/create/mcu-target.d.ts +39 -0
  93. package/dist/create/mcu-target.js +80 -0
  94. package/dist/create/pack-targets.d.ts +19 -0
  95. package/dist/create/pack-targets.js +56 -0
  96. package/dist/create/{init-scaffold.d.ts → scaffold.d.ts} +8 -11
  97. package/dist/create/{init-scaffold.js → scaffold.js} +28 -87
  98. package/dist/create/templates.d.ts +51 -0
  99. package/dist/create/{init-templates.js → templates.js} +135 -116
  100. package/dist/create/wizard.d.ts +19 -0
  101. package/dist/create/wizard.js +314 -0
  102. package/dist/debug/preprocessor.d.ts +5 -0
  103. package/dist/debug/preprocessor.js +31 -7
  104. package/dist/diagnostics/diagnostics-report.d.ts +1 -1
  105. package/dist/diagnostics/diagnostics-report.js +3 -11
  106. package/dist/diagnostics/json-schema.d.ts +1 -1
  107. package/dist/diagnostics/md-writer.js +2 -2
  108. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  109. package/dist/diagnostics/mermaid-builder.js +1 -1
  110. package/dist/emit/cpp-emitter.js +4 -1
  111. package/dist/emit/emitters/class-emitter.js +32 -4
  112. package/dist/emit/emitters/emitter-context.d.ts +11 -0
  113. package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
  114. package/dist/emit/emitters/function-emitter-impl.js +33 -17
  115. package/dist/emit/emitters/output-finalizer.d.ts +7 -0
  116. package/dist/emit/emitters/output-finalizer.js +31 -23
  117. package/dist/emit/emitters/setup.js +147 -63
  118. package/dist/emit/emitters/top-level-prep.js +1 -1
  119. package/dist/emit/emitters/type-decl-emitter.js +13 -8
  120. package/dist/emit/emitters/ui-emitter.js +1 -1
  121. package/dist/emit/expression-renderer.d.ts +3 -3
  122. package/dist/emit/expression-renderer.js +17 -7
  123. package/dist/emit/route-hal-op.js +17 -48
  124. package/dist/emit/snprintf-helpers.d.ts +1 -3
  125. package/dist/emit/snprintf-helpers.js +1 -39
  126. package/dist/emit/statement-renderer.d.ts +0 -4
  127. package/dist/emit/statement-renderer.js +54 -45
  128. package/dist/emit/utils/async-state-machine.d.ts +16 -9
  129. package/dist/emit/utils/async-state-machine.js +56 -54
  130. package/dist/emit/utils/comment-helpers.d.ts +0 -8
  131. package/dist/emit/utils/comment-helpers.js +1 -1
  132. package/dist/emit/utils/cpp-helpers.d.ts +2 -2
  133. package/dist/emit/utils/cpp-helpers.js +2 -2
  134. package/dist/emit/utils/hal-op-cpp-type.js +4 -6
  135. package/dist/emit/utils/index.d.ts +3 -3
  136. package/dist/emit/utils/index.js +3 -3
  137. package/dist/emit/utils/type-inference.d.ts +1 -29
  138. package/dist/emit/utils/type-inference.js +0 -75
  139. package/dist/framework-package.d.ts +3 -0
  140. package/dist/framework-package.js +23 -6
  141. package/dist/framework-registry.d.ts +5 -5
  142. package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
  143. package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
  144. package/dist/frameworks/native/index.d.ts +3 -0
  145. package/dist/frameworks/native/index.js +15 -0
  146. package/dist/frameworks/native/native-compile.d.ts +17 -0
  147. package/dist/frameworks/native/native-compile.js +170 -0
  148. package/dist/frameworks/native/native-config.d.ts +41 -0
  149. package/dist/frameworks/native/native-config.js +7 -0
  150. package/dist/frameworks/native/strategy.d.ts +97 -0
  151. package/dist/frameworks/native/strategy.js +664 -0
  152. package/dist/ir/board-resolver.d.ts +18 -23
  153. package/dist/ir/board-resolver.js +43 -401
  154. package/dist/ir/build-ir-state.d.ts +3 -0
  155. package/dist/ir/build-ir-state.js +42 -0
  156. package/dist/ir/build-ir.d.ts +1 -1
  157. package/dist/ir/build-ir.js +64 -45
  158. package/dist/ir/declaration-builders.js +1 -0
  159. package/dist/ir/expression-to-ir.js +17 -10
  160. package/dist/ir/hal/hal-emitter.d.ts +0 -2
  161. package/dist/ir/hal/hal-emitter.js +92 -41
  162. package/dist/ir/hal/hal-parser.d.ts +5 -5
  163. package/dist/ir/hal/hal-parser.js +128 -36
  164. package/dist/ir/hal/hal-plugins.d.ts +0 -1
  165. package/dist/ir/hal/hal-plugins.js +425 -716
  166. package/dist/ir/heap-analysis.js +2 -41
  167. package/dist/ir/identifier-collector.js +32 -20
  168. package/dist/ir/network-validation.js +7 -11
  169. package/dist/ir/ownership-analysis.js +75 -13
  170. package/dist/ir/peripheral-usage.d.ts +8 -2
  171. package/dist/ir/peripheral-usage.js +78 -149
  172. package/dist/ir/peripheral-validation.js +23 -3
  173. package/dist/ir/pin-capability-validation.d.ts +12 -0
  174. package/dist/ir/pin-capability-validation.js +61 -97
  175. package/dist/ir/pin-mode-validation.js +5 -5
  176. package/dist/ir/program-analysis.d.ts +8 -15
  177. package/dist/ir/program-analysis.js +140 -323
  178. package/dist/ir/pulldown-validation.js +11 -4
  179. package/dist/ir/resource-analysis.js +15 -3
  180. package/dist/ir/statement-to-ir.js +0 -6
  181. package/dist/ir/timing-validation.js +1 -1
  182. package/dist/ir/transformers/array-methods.js +11 -5
  183. package/dist/ir/transformers/call-statement.js +20 -87
  184. package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
  185. package/dist/ir/transformers/callback-context-registry.js +8 -16
  186. package/dist/ir/transformers/control-flow.js +0 -13
  187. package/dist/ir/transformers/expressions.js +10 -9
  188. package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
  189. package/dist/ir/transformers/hal-call-resolver.js +24 -10
  190. package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
  191. package/dist/ir/transformers/hal-emit-helpers.js +2 -2
  192. package/dist/ir/transformers/namespace-methods.js +1 -1
  193. package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
  194. package/dist/ir/transformers/ui-callback-lowering.js +0 -24
  195. package/dist/ir/transformers/variables.js +338 -42
  196. package/dist/ir/try-catch-validation.js +4 -3
  197. package/dist/ir/type-resolution.js +15 -4
  198. package/dist/ir/validation-orchestrator.js +0 -9
  199. package/dist/libdef/cpp-to-decl.d.ts +0 -9
  200. package/dist/libdef/cpp-to-decl.js +0 -72
  201. package/dist/libdef/registry.d.ts +0 -1
  202. package/dist/libdef/registry.js +1 -24
  203. package/dist/library/catalog.d.ts +35 -0
  204. package/dist/library/catalog.js +67 -0
  205. package/dist/library/cli.d.ts +2 -0
  206. package/dist/library/cli.js +168 -0
  207. package/dist/library/init.d.ts +25 -0
  208. package/dist/library/init.js +397 -0
  209. package/dist/library/install.d.ts +9 -0
  210. package/dist/library/install.js +80 -0
  211. package/dist/library/registry-search.d.ts +34 -0
  212. package/dist/library/registry-search.js +50 -0
  213. package/dist/library/validate.d.ts +17 -0
  214. package/dist/library/validate.js +175 -0
  215. package/dist/library-packages.d.ts +95 -0
  216. package/dist/library-packages.js +275 -0
  217. package/dist/mapping/peripheral-names.js +9 -4
  218. package/dist/mapping/source-map.d.ts +3 -4
  219. package/dist/mapping/source-map.js +12 -18
  220. package/dist/orchestrator/graph-builder.d.ts +3 -3
  221. package/dist/orchestrator/graph-builder.js +29 -12
  222. package/dist/orchestrator/type-checker.d.ts +3 -3
  223. package/dist/orchestrator/type-checker.js +3 -3
  224. package/dist/platform/async-runtime.js +1 -1
  225. package/dist/platform/coop-scheduler-runtime.js +2 -2
  226. package/dist/platform/generic-debug-codegen.d.ts +36 -0
  227. package/dist/platform/generic-debug-codegen.js +185 -0
  228. package/dist/platform/generic-strategy.d.ts +3 -4
  229. package/dist/platform/generic-strategy.js +5 -80
  230. package/dist/platform/index.js +1 -1
  231. package/dist/platform/registry.d.ts +2 -2
  232. package/dist/platform/registry.js +2 -2
  233. package/dist/preview/client.js +17 -3
  234. package/dist/safety/asil-decorators.d.ts +32 -0
  235. package/dist/safety/asil-decorators.js +32 -0
  236. package/dist/safety/authoring.d.ts +85 -0
  237. package/dist/safety/authoring.js +61 -0
  238. package/dist/safety/engine.d.ts +3 -0
  239. package/dist/safety/engine.js +83 -0
  240. package/dist/safety/hal/ops.d.ts +48 -0
  241. package/dist/safety/hal/ops.js +46 -0
  242. package/dist/safety/iso26262/analyze.d.ts +13 -0
  243. package/dist/safety/iso26262/analyze.js +29 -0
  244. package/dist/safety/iso26262/asil.d.ts +10 -0
  245. package/dist/safety/iso26262/asil.js +22 -0
  246. package/dist/safety/iso26262/collect.d.ts +14 -0
  247. package/dist/safety/iso26262/collect.js +137 -0
  248. package/dist/safety/iso26262/goto-checker.d.ts +10 -0
  249. package/dist/safety/iso26262/goto-checker.js +72 -0
  250. package/dist/safety/iso26262/heap-checker.d.ts +7 -0
  251. package/dist/safety/iso26262/heap-checker.js +57 -0
  252. package/dist/safety/iso26262/init-checker.d.ts +13 -0
  253. package/dist/safety/iso26262/init-checker.js +127 -0
  254. package/dist/safety/iso26262/loop-checker.d.ts +7 -0
  255. package/dist/safety/iso26262/loop-checker.js +86 -0
  256. package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
  257. package/dist/safety/iso26262/recursion-checker.js +134 -0
  258. package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
  259. package/dist/safety/iso26262/sidecar-writer.js +13 -0
  260. package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
  261. package/dist/safety/passes/pinMode-intercept.js +60 -0
  262. package/dist/safety/runtime/mode-table.d.ts +5 -0
  263. package/dist/safety/runtime/mode-table.js +55 -0
  264. package/dist/safety/runtime/polyfills.d.ts +6 -0
  265. package/dist/safety/runtime/polyfills.js +12 -0
  266. package/dist/safety/runtime/result-struct.d.ts +11 -0
  267. package/dist/safety/runtime/result-struct.js +98 -0
  268. package/dist/safety/runtime/safe-int.d.ts +33 -0
  269. package/dist/safety/runtime/safe-int.js +170 -0
  270. package/dist/safety/runtime/safe-traits.d.ts +4 -0
  271. package/dist/safety/runtime/safe-traits.js +95 -0
  272. package/dist/safety/runtime/safe-variable.d.ts +39 -0
  273. package/dist/safety/runtime/safe-variable.js +226 -0
  274. package/dist/safety/runtime/vote.d.ts +8 -0
  275. package/dist/safety/runtime/vote.js +92 -0
  276. package/dist/safety/runtime/write-verify.d.ts +8 -0
  277. package/dist/safety/runtime/write-verify.js +71 -0
  278. package/dist/safety/safe-int-types.d.ts +45 -0
  279. package/dist/safety/safe-int-types.js +25 -0
  280. package/dist/safety/safe-variable-types.d.ts +29 -0
  281. package/dist/safety/safe-variable-types.js +19 -0
  282. package/dist/safety/safety-bridge.d.ts +5 -6
  283. package/dist/safety/safety-bridge.js +15 -28
  284. package/dist/safety/sidecar-bridge.d.ts +1 -3
  285. package/dist/safety/sidecar-bridge.js +3 -20
  286. package/dist/safety/specifiers.d.ts +6 -0
  287. package/dist/safety/specifiers.js +14 -0
  288. package/dist/safety-hook.d.ts +8 -7
  289. package/dist/safety-hook.js +12 -13
  290. package/dist/testing.d.ts +5 -6
  291. package/dist/testing.js +5 -5
  292. package/dist/transpile/resolution.d.ts +1 -1
  293. package/dist/transpile/resolution.js +18 -9
  294. package/dist/transpile/test-pins.d.ts +18 -0
  295. package/dist/transpile/test-pins.js +142 -0
  296. package/dist/transpile.d.ts +1 -2
  297. package/dist/transpile.js +90 -29
  298. package/dist/types.d.ts +45 -26
  299. package/dist/ui-hook.d.ts +1 -1
  300. package/dist/utils/cli.d.ts +2 -2
  301. package/dist/utils/cli.js +160 -157
  302. package/dist/utils/fs.d.ts +3 -4
  303. package/dist/utils/fs.js +4 -5
  304. package/dist/utils/strings.d.ts +0 -1
  305. package/dist/utils/strings.js +0 -8
  306. package/dist/utils/ui.d.ts +5 -2
  307. package/dist/utils/ui.js +13 -3
  308. package/package.json +158 -149
  309. package/dist/add-preset.d.ts +0 -4
  310. package/dist/add-preset.js +0 -74
  311. package/dist/api/shared/async-symbol-detector.d.ts +0 -11
  312. package/dist/api/shared/async-symbol-detector.js +0 -140
  313. package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
  314. package/dist/api/shared/native-display-op-resolver.js +0 -64
  315. package/dist/create/board-checklist.d.ts +0 -2
  316. package/dist/create/board-checklist.js +0 -52
  317. package/dist/create/board-codegen.d.ts +0 -9
  318. package/dist/create/board-codegen.js +0 -238
  319. package/dist/create/board-generators.d.ts +0 -12
  320. package/dist/create/board-generators.js +0 -651
  321. package/dist/create/board-spec.d.ts +0 -637
  322. package/dist/create/board-spec.js +0 -214
  323. package/dist/create/init-templates.d.ts +0 -28
  324. package/dist/create/init-wizard.d.ts +0 -8
  325. package/dist/create/init-wizard.js +0 -182
  326. package/dist/install/framework-catalog.d.ts +0 -53
  327. package/dist/install/framework-catalog.js +0 -107
  328. package/dist/install/handle-install.d.ts +0 -35
  329. package/dist/install/handle-install.js +0 -177
  330. package/dist/install/index.d.ts +0 -4
  331. package/dist/install/index.js +0 -3
  332. package/dist/ir/pin-state-tracking.d.ts +0 -58
  333. package/dist/ir/pin-state-tracking.js +0 -182
  334. package/dist/ir/pwm-timer-sharing.d.ts +0 -4
  335. package/dist/ir/pwm-timer-sharing.js +0 -94
  336. package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
  337. package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
  338. package/dist/libdef/component-decls.d.ts +0 -2
  339. package/dist/libdef/component-decls.js +0 -6
  340. package/dist/libdef/component-discovery.d.ts +0 -43
  341. package/dist/libdef/component-discovery.js +0 -83
  342. package/dist/theme-tokens.d.ts +0 -22
  343. package/dist/theme-tokens.js +0 -172
@@ -0,0 +1,23 @@
1
+ /** The discriminator union the wizard switches on. */
2
+ export type TargetPick = {
3
+ kind: 'native';
4
+ } | {
5
+ kind: 'mcu';
6
+ id: string;
7
+ } | {
8
+ kind: 'board';
9
+ entry: {
10
+ identifier: string;
11
+ name: string;
12
+ soc: string;
13
+ };
14
+ };
15
+ export declare function pickTarget(): Promise<TargetPick | undefined>;
16
+ /** Back-compat alias for the board-only picker (still used by tests/tools
17
+ * that want boards only). */
18
+ export declare function pickBoard(): Promise<{
19
+ identifier: string;
20
+ name: string;
21
+ soc: string;
22
+ curated: boolean;
23
+ } | undefined>;
@@ -0,0 +1,88 @@
1
+ // ---------------------------------------------------------------------------
2
+ // board-search.ts — the create-wizard target picker: one filterable select.
3
+ //
4
+ // Everything the wizard can target rides a single searchable list:
5
+ // - Native Desktop (the one non-embedded target)
6
+ // - Bare silicon (soc entries — contract/custom-PCB projects)
7
+ // - Every Zephyr board variant from the generated catalog (1,300+;
8
+ // the curated nine sit wherever their names sort — no badge, the
9
+ // picker is a flat search surface)
10
+ //
11
+ // Typing "esp32" narrows to the espressif variants; typing "nrf52" to the
12
+ // Nordic ones; arrows + enter pick. Uses inquirer-select-pro's filter mode.
13
+ // ---------------------------------------------------------------------------
14
+ import { select } from 'inquirer-select-pro';
15
+ import { activeBoardCatalog } from '../board-catalog/index.js';
16
+ import { KNOWN_TARGETS } from './scaffold.js';
17
+ /** Flat option list: native first, then bare silicon, then every board
18
+ * variant (alphabetical by the pack's directory-walk order). */
19
+ function targetOptions() {
20
+ const native = KNOWN_TARGETS
21
+ .filter((t) => t.isNative)
22
+ .map((t) => ({ name: `${t.displayName} (Windows/Linux executable)`, value: `native:${t.id}` }));
23
+ const boards = Object.values(activeBoardCatalog()).map((b) => ({
24
+ name: `${b.name} (${b.identifier})`,
25
+ value: b.identifier,
26
+ }));
27
+ return [...native, ...boards];
28
+ }
29
+ /** Resolve a picked value back to its discriminated form. */
30
+ function resolvePick(value) {
31
+ if (value.startsWith('native:'))
32
+ return { kind: 'native' };
33
+ // Board: value IS the qualified identifier.
34
+ const entry = activeBoardCatalog()[value];
35
+ if (!entry)
36
+ return undefined;
37
+ return { kind: 'board', entry: { identifier: entry.identifier, name: entry.name, soc: value.split('/')[1] } };
38
+ }
39
+ /**
40
+ * Build a filterable options loader for `inquirer-select-pro`. The select
41
+ * only enables its filter input when `options` is a *function* (a static
42
+ * array disables filtering entirely), so we wrap the flat list in a
43
+ * case-insensitive substring matcher.
44
+ */
45
+ function filterableTargetOptions() {
46
+ const all = targetOptions();
47
+ return (input) => {
48
+ const query = (input ?? '').trim().toLowerCase();
49
+ if (!query)
50
+ return all;
51
+ return all.filter((o) => o.name.toLowerCase().includes(query));
52
+ };
53
+ }
54
+ export async function pickTarget() {
55
+ const value = await select({
56
+ message: 'Target (type to filter — e.g. "esp32", "nucleo", "native"):',
57
+ multiple: false,
58
+ options: filterableTargetOptions(),
59
+ filter: true,
60
+ pageSize: 15,
61
+ });
62
+ if (value === undefined || value === null)
63
+ return undefined;
64
+ return resolvePick(value);
65
+ }
66
+ /** Back-compat alias for the board-only picker (still used by tests/tools
67
+ * that want boards only). */
68
+ export async function pickBoard() {
69
+ const boards = Object.values(activeBoardCatalog()).map((b) => ({ name: `${b.name} (${b.identifier})`, value: b.identifier }));
70
+ const value = await select({
71
+ message: 'Board (type to filter — e.g. "esp32", "nucleo_f411"):',
72
+ multiple: false,
73
+ options: (input) => {
74
+ const query = (input ?? '').trim().toLowerCase();
75
+ if (!query)
76
+ return boards;
77
+ return boards.filter((b) => b.name.toLowerCase().includes(query));
78
+ },
79
+ filter: true,
80
+ pageSize: 15,
81
+ });
82
+ if (value === undefined || value === null)
83
+ return undefined;
84
+ const entry = activeBoardCatalog()[value];
85
+ if (!entry)
86
+ return undefined;
87
+ return { identifier: entry.identifier, name: entry.name, soc: value.split('/')[1], curated: false };
88
+ }
@@ -0,0 +1,32 @@
1
+ /** VS Code extension identifiers (publisher.name) of the bundled extensions. */
2
+ export declare const TYPECAD_UI_EXTENSION_ID = "typecad.typecad-ui";
3
+ export declare const TYPECAD_DEBUG_EXTENSION_ID = "typecad.vscode-typecad-debug";
4
+ /**
5
+ * Source location of an unpacked bundled extension inside the cuttlefish
6
+ * package. Resolved from this module's location so it works from both src/
7
+ * (dev and tests importing source) and dist/ (the published CLI) — assets/
8
+ * sits at the package root either way.
9
+ */
10
+ export declare function bundledExtensionSourceDir(dir: string): string;
11
+ /** Kept for compatibility with the original single-extension helper. */
12
+ export declare function typecadUiExtensionSourceDir(): string;
13
+ /** Content of .vscode/extensions.json — auto-installs the workspace-bundled extensions. */
14
+ export declare function generateExtensionsJson(): string;
15
+ export declare const WATCH_TASK_LABEL = "cuttlefish: watch build";
16
+ /** The watch task entry written to .vscode/tasks.json. */
17
+ export declare function watchBuildTask(): Record<string, unknown>;
18
+ /**
19
+ * Content of .vscode/tasks.json containing the watch task. Kept separate from
20
+ * the merge logic so tests can assert the shape without a filesystem.
21
+ */
22
+ export declare function generateTasksJson(existingTasks?: ReadonlyArray<Record<string, unknown>>): string;
23
+ /**
24
+ * Copy the bundled extensions into <outDir>/.vscode/extensions/, then write the
25
+ * companion .vscode/extensions.json and — when the project has a `dev` watch
26
+ * script — the .vscode/tasks.json watch task. Returns the absolute paths
27
+ * written, or [] when the extension assets are missing (warns, never throws).
28
+ * `assetsRoot` overrides the bundled-asset location (tests). `hideNpm` (used by
29
+ * `cuttlefish create` for end-user projects) also writes settings.json keys
30
+ * that hide VS Code's NPM Scripts view and npm task detection.
31
+ */
32
+ export declare function writeEditorIntegration(outDir: string, assetsRoot?: string, hideNpm?: boolean): string[];
@@ -0,0 +1,257 @@
1
+ // ---------------------------------------------------------------------------
2
+ // editor-integration.ts — create-time editor scaffolding for .ui highlighting
3
+ //
4
+ // Cuttlefish projects keep their UI in .ui single-file components (TS script +
5
+ // CSS style + Svelte-style markup), which no editor knows out of the box. The
6
+ // package ships grammar-only VS Code extensions under
7
+ // assets/editor-extensions/ and `cuttlefish create` copies them into the new
8
+ // project's .vscode/extensions/ folder:
9
+ //
10
+ // typecad-ui — .ui syntax highlighting, snippets, file icons, markdown
11
+ // ```ui fence highlighting (grammar-only, no code).
12
+ // typecad-debug — the built TypeCAD Debug extension (breakpoint syncing +
13
+ // F5 commands), so debugging works with zero install.
14
+ //
15
+ // VS Code (1.89+, trusted workspaces) detects workspace-bundled extensions and
16
+ // installs them scoped to that workspace. The companion .vscode/extensions.json
17
+ // carries forceInstall entries (microsoft/vscode#299830) so VS Code builds with
18
+ // that feature skip the approval prompt; older builds show a one-time install
19
+ // prompt instead.
20
+ //
21
+ // A .vscode/tasks.json watch task is also written: it runs the project's
22
+ // `cuttlefish build --watch` dev script with NO_COLOR=1 and parses the
23
+ // transpiler/ESLint diagnostic lines into Problems-panel squiggles. The task
24
+ // merges by label (never clobbers user edits or the framework debug writer's
25
+ // tasks, which merge the same way).
26
+ //
27
+ // Everything here is best-effort like the debug-artifact generation: a missing
28
+ // or unreadable asset tree warns and skips rather than failing `cuttlefish
29
+ // create`, because a project without editor integration still builds fine.
30
+ // ---------------------------------------------------------------------------
31
+ import fs from 'node:fs';
32
+ import path from 'node:path';
33
+ import { fileURLToPath } from 'node:url';
34
+ /** VS Code extension identifiers (publisher.name) of the bundled extensions. */
35
+ export const TYPECAD_UI_EXTENSION_ID = 'typecad.typecad-ui';
36
+ export const TYPECAD_DEBUG_EXTENSION_ID = 'typecad.vscode-typecad-debug';
37
+ /** Extensions to bundle, as { asset folder name → extension id } pairs. */
38
+ const BUNDLED_EXTENSIONS = [
39
+ { dir: 'typecad-ui', id: TYPECAD_UI_EXTENSION_ID },
40
+ { dir: 'typecad-debug', id: TYPECAD_DEBUG_EXTENSION_ID },
41
+ ];
42
+ const ASSETS_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'assets', 'editor-extensions');
43
+ /**
44
+ * Source location of an unpacked bundled extension inside the cuttlefish
45
+ * package. Resolved from this module's location so it works from both src/
46
+ * (dev and tests importing source) and dist/ (the published CLI) — assets/
47
+ * sits at the package root either way.
48
+ */
49
+ export function bundledExtensionSourceDir(dir) {
50
+ return path.join(ASSETS_ROOT, dir);
51
+ }
52
+ /** Kept for compatibility with the original single-extension helper. */
53
+ export function typecadUiExtensionSourceDir() {
54
+ return bundledExtensionSourceDir('typecad-ui');
55
+ }
56
+ /** Content of .vscode/extensions.json — auto-installs the workspace-bundled extensions. */
57
+ export function generateExtensionsJson() {
58
+ return `${JSON.stringify({ forceInstall: BUNDLED_EXTENSIONS.map(e => e.id) }, null, 2)}\n`;
59
+ }
60
+ // -- watch task + problem matchers ------------------------------------------------
61
+ /**
62
+ * Problem matchers for cuttlefish's two diagnostic line formats:
63
+ * transpiler: "<file> error|warning [code] (line,column): message"
64
+ * eslint gate: "error <file>(line,column) [rule]: message"
65
+ * NO_COLOR=1 is set on the task so chalk stays off and the lines stay greppable.
66
+ */
67
+ const PROBLEM_MATCHERS = [
68
+ {
69
+ owner: 'cuttlefish-transpiler',
70
+ severity: 'error',
71
+ fileLocation: ['relative', '${workspaceFolder}'],
72
+ pattern: {
73
+ regexp: '^\\s*(.*?)\\s+(error|warning)(?:\\s+\\[[^\\]]*\\])?\\s*\\((\\d+),(\\d+)\\):\\s+(.*)$',
74
+ file: 1,
75
+ severity: 2,
76
+ line: 3,
77
+ column: 4,
78
+ message: 5,
79
+ },
80
+ background: {
81
+ beginsPattern: 'Transpiling',
82
+ endsPattern: 'Watching for changes',
83
+ },
84
+ },
85
+ {
86
+ owner: 'cuttlefish-eslint',
87
+ severity: 'error',
88
+ fileLocation: ['relative', '${workspaceFolder}'],
89
+ pattern: {
90
+ regexp: '^\\s*error\\s+(.*?)\\((\\d+),(\\d+)\\)\\s+\\[[^\\]]*\\]:\\s+(.*)$',
91
+ file: 1,
92
+ line: 2,
93
+ column: 3,
94
+ message: 4,
95
+ },
96
+ background: {
97
+ beginsPattern: 'Transpiling',
98
+ endsPattern: 'Watching for changes',
99
+ },
100
+ },
101
+ ];
102
+ export const WATCH_TASK_LABEL = 'cuttlefish: watch build';
103
+ /** The watch task entry written to .vscode/tasks.json. */
104
+ export function watchBuildTask() {
105
+ return {
106
+ label: WATCH_TASK_LABEL,
107
+ command: 'npm run dev',
108
+ type: 'shell',
109
+ isBackground: true,
110
+ group: 'build',
111
+ options: { env: { NO_COLOR: '1' } },
112
+ problemMatcher: PROBLEM_MATCHERS,
113
+ };
114
+ }
115
+ /**
116
+ * Content of .vscode/tasks.json containing the watch task. Kept separate from
117
+ * the merge logic so tests can assert the shape without a filesystem.
118
+ */
119
+ export function generateTasksJson(existingTasks = []) {
120
+ const tasks = [...existingTasks];
121
+ const idx = tasks.findIndex(t => t.label === WATCH_TASK_LABEL);
122
+ const task = watchBuildTask();
123
+ if (idx >= 0)
124
+ tasks[idx] = task;
125
+ else
126
+ tasks.push(task);
127
+ return `${JSON.stringify({ version: '2.0.0', tasks }, null, 2)}\n`;
128
+ }
129
+ /**
130
+ * Read-merge-write .vscode/tasks.json with the watch task (by label), so user
131
+ * edits and the framework debug writer's tasks survive. Mirrors the Zephyr
132
+ * debug-config merge semantics.
133
+ */
134
+ function writeTasksJson(vscodeDir) {
135
+ const tasksPath = path.join(vscodeDir, 'tasks.json');
136
+ let existing = [];
137
+ if (fs.existsSync(tasksPath)) {
138
+ try {
139
+ const doc = JSON.parse(fs.readFileSync(tasksPath, 'utf-8'));
140
+ const tasks = doc.tasks;
141
+ if (Array.isArray(tasks)) {
142
+ existing = tasks.filter((t) => !!t && typeof t === 'object');
143
+ }
144
+ }
145
+ catch {
146
+ // malformed — start fresh
147
+ }
148
+ }
149
+ fs.writeFileSync(tasksPath, generateTasksJson(existing), 'utf-8');
150
+ return tasksPath;
151
+ }
152
+ // -- install -----------------------------------------------------------------
153
+ /** All files under `dir`, as paths relative to `dir`. */
154
+ function listFilesRecursive(dir) {
155
+ const out = [];
156
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
157
+ if (entry.isDirectory()) {
158
+ for (const nested of listFilesRecursive(path.join(dir, entry.name))) {
159
+ out.push(path.join(entry.name, nested));
160
+ }
161
+ }
162
+ else {
163
+ out.push(entry.name);
164
+ }
165
+ }
166
+ return out;
167
+ }
168
+ /**
169
+ * Whether <outDir> has an `npm run dev` script for the watch task to drive.
170
+ * The task is skipped when it doesn't (e.g. the monorepo root or hand-made
171
+ * projects), because a task referencing a missing script just errors on run.
172
+ */
173
+ function hasDevScript(outDir) {
174
+ try {
175
+ const pkg = JSON.parse(fs.readFileSync(path.join(outDir, 'package.json'), 'utf-8'));
176
+ const scripts = pkg.scripts;
177
+ return typeof scripts?.dev === 'string';
178
+ }
179
+ catch {
180
+ return false;
181
+ }
182
+ }
183
+ /**
184
+ * Settings that hide VS Code's web-dev npm surface in end-user projects. The
185
+ * scaffolded package.json is build tooling, not an npm package the user
186
+ * develops — without these, VS Code shows the NPM Scripts explorer view,
187
+ * auto-detected npm tasks, and Debug codelenses over the scripts.
188
+ */
189
+ const END_USER_NPM_SETTINGS = {
190
+ 'npm.autoDetect': 'off',
191
+ 'npm.exclude': '**/package.json',
192
+ 'debug.javascript.codelens.npmScripts': 'never',
193
+ };
194
+ /**
195
+ * Read-merge-write .vscode/settings.json with the npm-hiding settings. Merge-
196
+ * safe because the framework debug writer may also contribute settings
197
+ * (e.g. cortex-debug paths) — those must survive.
198
+ */
199
+ function writeNpmHiddenSettings(vscodeDir) {
200
+ const settingsPath = path.join(vscodeDir, 'settings.json');
201
+ let doc = {};
202
+ if (fs.existsSync(settingsPath)) {
203
+ try {
204
+ const parsed = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
205
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
206
+ doc = parsed;
207
+ }
208
+ }
209
+ catch {
210
+ // malformed — start fresh
211
+ }
212
+ }
213
+ Object.assign(doc, END_USER_NPM_SETTINGS);
214
+ fs.writeFileSync(settingsPath, `${JSON.stringify(doc, null, 2)}\n`, 'utf-8');
215
+ return settingsPath;
216
+ }
217
+ /**
218
+ * Copy the bundled extensions into <outDir>/.vscode/extensions/, then write the
219
+ * companion .vscode/extensions.json and — when the project has a `dev` watch
220
+ * script — the .vscode/tasks.json watch task. Returns the absolute paths
221
+ * written, or [] when the extension assets are missing (warns, never throws).
222
+ * `assetsRoot` overrides the bundled-asset location (tests). `hideNpm` (used by
223
+ * `cuttlefish create` for end-user projects) also writes settings.json keys
224
+ * that hide VS Code's NPM Scripts view and npm task detection.
225
+ */
226
+ export function writeEditorIntegration(outDir, assetsRoot, hideNpm = false) {
227
+ const vscodeDir = path.join(outDir, '.vscode');
228
+ const extensionRoot = path.join(vscodeDir, 'extensions');
229
+ const root = assetsRoot ?? ASSETS_ROOT;
230
+ const written = [];
231
+ let copiedAny = false;
232
+ for (const ext of BUNDLED_EXTENSIONS) {
233
+ const src = path.join(root, ext.dir);
234
+ if (!fs.existsSync(path.join(src, 'package.json'))) {
235
+ console.warn(`! Editor integration: ${ext.dir} extension assets not found at ${src} — skipped`);
236
+ continue;
237
+ }
238
+ const dest = path.join(extensionRoot, ext.dir);
239
+ fs.mkdirSync(dest, { recursive: true });
240
+ fs.cpSync(src, dest, { recursive: true });
241
+ for (const rel of listFilesRecursive(dest))
242
+ written.push(path.join(dest, rel));
243
+ copiedAny = true;
244
+ }
245
+ if (!copiedAny)
246
+ return [];
247
+ const extensionsJsonPath = path.join(vscodeDir, 'extensions.json');
248
+ fs.writeFileSync(extensionsJsonPath, generateExtensionsJson(), 'utf-8');
249
+ written.push(extensionsJsonPath);
250
+ if (hasDevScript(outDir)) {
251
+ written.push(writeTasksJson(vscodeDir));
252
+ }
253
+ if (hideNpm) {
254
+ written.push(writeNpmHiddenSettings(vscodeDir));
255
+ }
256
+ return written;
257
+ }
@@ -1,2 +1,2 @@
1
- import type { InitProjectOptions } from "./init-templates.js";
2
- export declare function generateEslintRules(_options: InitProjectOptions): string;
1
+ import type { CreateProjectOptions } from "./templates.js";
2
+ export declare function generateEslintRules(_options: CreateProjectOptions): string;
@@ -12,13 +12,23 @@ export interface FrameworkCatalogEntry {
12
12
  * be offered (it would fail at the package-manager step).
13
13
  */
14
14
  installable: boolean;
15
+ /**
16
+ * True when the framework ships inside @typecad/cuttlefish (no separate npm
17
+ * package): the scaffold must not add it to project dependencies, and the
18
+ * loader (framework-package.ts) resolves it internally instead of via
19
+ * require.resolve. The config string stays the package name for continuity.
20
+ */
21
+ builtin?: boolean;
15
22
  }
16
23
  /**
17
- * The installable frameworks. Kept aligned with the packages/ directory:
18
- * framework-arduino, framework-native, framework-zephyr all ship real packages.
19
- * esp-idf is intentionally absent (no published package in this repo).
24
+ * The usable frameworks. zephyr ships as a real package; native is built
25
+ * into @typecad/cuttlefish (formerly a separate package, now resolved
26
+ * internally). esp-idf is intentionally absent (no published package).
20
27
  */
21
28
  export declare const FRAMEWORK_CATALOG: readonly FrameworkCatalogEntry[];
29
+ /** True iff the framework package ships inside @typecad/cuttlefish and needs
30
+ * no separate npm dependency in scaffolded projects. */
31
+ export declare function isBuiltinFramework(packageName: string): boolean;
22
32
  /** Structural shape we need from a board/target. Keeps this module decoupled
23
33
  * from the KnownTarget type (and trivially testable with literals). */
24
34
  export interface BoardLike {
@@ -27,6 +37,28 @@ export interface BoardLike {
27
37
  }
28
38
  /** Look up a catalog entry by framework id (e.g. "arduino"). */
29
39
  export declare function frameworkCatalogEntry(id: string): FrameworkCatalogEntry | undefined;
40
+ /**
41
+ * Zephyr build targets come straight from the board catalog (the pack or a
42
+ * local `cuttlefish board sync` overlay) — every catalog board carries its
43
+ * own qualified `west build -b` target. There is no curated id→target map.
44
+ */
45
+ /**
46
+ * Probe method a board offers, for `cuttlefish create`'s wizard (which runs
47
+ * BEFORE the framework is installed, so it reads the board data pack — the
48
+ * same table boardgen emits into the generated board module for tier-3
49
+ * boards, extracted from each board's own board.cmake runners).
50
+ */
51
+ export interface CatalogProbeMethod {
52
+ id: string;
53
+ description: string;
54
+ }
55
+ /**
56
+ * The probe methods a board offers, from the board data pack. Accepts a
57
+ * qualified Zephyr target ('blackpill_f401ce/stm32f401xe'), a bare board id,
58
+ * or undefined. Empty when the board ships no runner table — then no probe
59
+ * question is asked and no zephyr.probe section is scaffolded.
60
+ */
61
+ export declare function probeMethodsForBoard(boardId: string | undefined): CatalogProbeMethod[];
30
62
  export interface FrameworkTargetProfile {
31
63
  /** Framework-specific build target (FQBN for Arduino, board id for Zephyr). */
32
64
  buildTarget?: string;
@@ -36,23 +68,31 @@ export interface FrameworkTargetProfile {
36
68
  export interface TargetProfileInput {
37
69
  id: string;
38
70
  isNative?: boolean;
39
- /** The board's Arduino FQBN, as currently stored on KnownTarget. */
71
+ /** The board's default build target, as currently stored on KnownTarget. */
40
72
  buildTarget?: string;
41
73
  }
42
74
  /**
43
75
  * Resolve the framework-specific buildTarget + toolchain type for a
44
- * (board, framework) pair. Arduino reuses the board's FQBN; Zephyr maps to the
45
- * Zephyr board id; native returns an empty profile (the native config writes
46
- * neither field).
76
+ * (board, framework) pair. Zephyr maps the board id to its Zephyr board
77
+ * target; native returns an empty profile (the native config writes neither
78
+ * field); any unlisted framework falls back to the board's stored target.
47
79
  */
48
80
  export declare function frameworkTargetProfile(target: TargetProfileInput, frameworkId: string): FrameworkTargetProfile;
49
81
  /**
50
82
  * The framework ids compatible with a board. Native boards map to ["native"];
51
- * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
83
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to zephyr for
52
84
  * unknown architectures). Order is preserved as the catalog order so the most
53
85
  * common framework is offered first in the prompt.
54
86
  */
55
87
  export declare function frameworksForTarget(target: BoardLike): FrameworkCatalogEntry[];
88
+ /**
89
+ * Whether `frameworkId` is actually offered for `target`: compatible with the
90
+ * board's architecture AND installable. Auto-picking narrows via
91
+ * frameworksForTarget, but an explicit `--framework` bypasses that narrowing —
92
+ * callers accepting one must reject anything this returns false for (e.g.
93
+ * `--framework native` on an embedded board).
94
+ */
95
+ export declare function frameworkCompatibleWithTarget(target: BoardLike, frameworkId: string): boolean;
56
96
  export type PackageManager = "npm" | "pnpm" | "yarn";
57
97
  /**
58
98
  * Detect the package manager for a directory. Priority:
@@ -7,74 +7,77 @@
7
7
  // detectPackageManager) so it unit-tests cleanly.
8
8
  import path from "node:path";
9
9
  import fs from "node:fs";
10
+ import { findPackBoard } from "./pack-targets.js";
10
11
  /**
11
- * The installable frameworks. Kept aligned with the packages/ directory:
12
- * framework-arduino, framework-native, framework-zephyr all ship real packages.
13
- * esp-idf is intentionally absent (no published package in this repo).
12
+ * The usable frameworks. zephyr ships as a real package; native is built
13
+ * into @typecad/cuttlefish (formerly a separate package, now resolved
14
+ * internally). esp-idf is intentionally absent (no published package).
14
15
  */
15
16
  export const FRAMEWORK_CATALOG = [
16
- { id: "arduino", packageName: "@typecad/framework-arduino", label: "Arduino (digitalWrite, Wire, SPI)", installable: true },
17
17
  { id: "zephyr", packageName: "@typecad/framework-zephyr", label: "Zephyr RTOS", installable: true },
18
- { id: "native", packageName: "@typecad/framework-native", label: "Native (Windows/Linux executable)", installable: true },
18
+ { id: "native", packageName: "@typecad/framework-native", label: "Native (Windows/Linux executable)", installable: true, builtin: true },
19
19
  ];
20
+ /** True iff the framework package ships inside @typecad/cuttlefish and needs
21
+ * no separate npm dependency in scaffolded projects. */
22
+ export function isBuiltinFramework(packageName) {
23
+ return FRAMEWORK_CATALOG.some((f) => f.packageName === packageName && f.builtin === true);
24
+ }
20
25
  /**
21
26
  * Architecture → compatible framework ids. Derived from each framework
22
27
  * package's framework.manifest.ts `profile.targets`:
23
- * - arduino: avr, esp32 family, rp2040/rp2350, samd, stm32
24
- * - zephyr: nrf52 (xiao_ble), esp32, esp32s3
28
+ * - zephyr: nrf52 (xiao_ble), esp32 family (esp32, esp32s3, esp32c3, esp32c6),
29
+ * rp2040/rp2350 (rpi_pico, rpi_pico2), stm32f411 (blackpill),
30
+ * samd21 (nano_33_iot)
25
31
  * - native: desktop only
26
- * Unknown embedded architectures fall back to [arduino] (the broadest core).
32
+ * Unknown embedded architectures fall back to [zephyr].
27
33
  */
28
34
  const ARCHITECTURE_FRAMEWORKS = {
29
- avr: ["arduino"],
30
- esp32: ["arduino", "zephyr"],
31
- esp32s2: ["arduino"],
32
- esp32s3: ["arduino", "zephyr"],
33
- esp32c3: ["arduino"],
34
- esp32c6: ["arduino"],
35
- rp2040: ["arduino"],
36
- rp2350: ["arduino"],
37
- samd: ["arduino"],
38
- stm32: ["arduino"],
35
+ esp32: ["zephyr"],
36
+ esp32s3: ["zephyr"],
37
+ esp32c3: ["zephyr"],
38
+ esp32c6: ["zephyr"],
39
+ rp2040: ["zephyr"],
40
+ rp2350: ["zephyr"],
41
+ // Per-chip key (stm32f411 style) — the Black Pill's generic 'stm32' family
42
+ // has no other supported silicon today.
43
+ samd21: ["zephyr"],
44
+ stm32f411: ["zephyr"],
39
45
  nrf52: ["zephyr"],
40
46
  };
41
- const FALLBACK_FRAMEWORKS = ["arduino"];
47
+ const FALLBACK_FRAMEWORKS = ["zephyr"];
42
48
  /** Look up a catalog entry by framework id (e.g. "arduino"). */
43
49
  export function frameworkCatalogEntry(id) {
44
50
  return FRAMEWORK_CATALOG.find((f) => f.id === id);
45
51
  }
46
52
  // ── framework-specific build target + toolchain ─────────────────────────────
47
- // A board's buildTarget string is NOT framework-independent: Arduino uses an
48
- // FQBN (e.g. 'esp32:esp32:esp32s3') while Zephyr uses a board id for
49
- // `west build -b` (e.g. 'esp32s3_devkitc'). The scaffold must pick the right
50
- // one for the chosen framework, and the matching toolchain backend
51
- // ('arduino-cli' vs 'west'). Source for Zephyr board ids: framework-zephyr's
53
+ // A board's buildTarget string is framework-specific: Zephyr uses a board id
54
+ // for `west build -b` (e.g. 'esp32s3_devkitc/esp32s3/procpu'). The scaffold
55
+ // must pick the right one for the chosen framework, and the matching
56
+ // toolchain backend ('west'). Source for Zephyr board ids: framework-zephyr's
52
57
  // chip registry (src/chips/index.ts) + the demo configs.
53
58
  const FRAMEWORK_TOOLCHAIN = {
54
- arduino: "arduino-cli",
55
59
  zephyr: "west",
56
60
  // native has no toolchain (the native config path writes neither field).
57
61
  };
58
62
  /**
59
- * Zephyr board target for each cuttlefish board id that supports Zephyr. These
60
- * are the full qualified targets passed to `west build -b <target>` (framework-
61
- * zephyr's chipForTarget splits on '/' and takes the board id, so the qualified
62
- * form resolves correctly there too). Zephyr 4.3+ REQUIRES the qualifier for
63
- * multi-core ESP32 boards — the bare id (e.g. 'esp32s3_devkitc') is rejected
64
- * with "Board qualifiers ... not found". procpu is the main application core.
63
+ * The probe methods a board offers, from the board data pack. Accepts a
64
+ * qualified Zephyr target ('blackpill_f401ce/stm32f401xe'), a bare board id,
65
+ * or undefined. Empty when the board ships no runner table then no probe
66
+ * question is asked and no zephyr.probe section is scaffolded.
65
67
  */
66
- const ZEPHYR_BOARD_IDS = {
67
- "esp32-devkit": "esp32_devkitc/esp32/procpu",
68
- esp32s3: "esp32s3_devkitc/esp32s3/procpu",
69
- // xiao_ble isn't currently a KNOWN_TARGETS entry, but keep the descriptor
70
- // correct for completeness: nRF52840 (single core), base (non-sense) variant.
71
- "xiao-nrf52840": "xiao_ble/nrf52840",
72
- };
68
+ export function probeMethodsForBoard(boardId) {
69
+ if (!boardId)
70
+ return [];
71
+ const entry = findPackBoard(boardId);
72
+ if (!entry?.probeMethods)
73
+ return [];
74
+ return entry.probeMethods.map((m) => ({ id: m.id, description: m.description }));
75
+ }
73
76
  /**
74
77
  * Resolve the framework-specific buildTarget + toolchain type for a
75
- * (board, framework) pair. Arduino reuses the board's FQBN; Zephyr maps to the
76
- * Zephyr board id; native returns an empty profile (the native config writes
77
- * neither field).
78
+ * (board, framework) pair. Zephyr maps the board id to its Zephyr board
79
+ * target; native returns an empty profile (the native config writes neither
80
+ * field); any unlisted framework falls back to the board's stored target.
78
81
  */
79
82
  export function frameworkTargetProfile(target, frameworkId) {
80
83
  if (target.isNative) {
@@ -82,14 +85,15 @@ export function frameworkTargetProfile(target, frameworkId) {
82
85
  }
83
86
  const toolchainType = FRAMEWORK_TOOLCHAIN[frameworkId];
84
87
  if (frameworkId === "zephyr") {
85
- return { buildTarget: ZEPHYR_BOARD_IDS[target.id], toolchainType };
88
+ // The target input's buildTarget IS the qualified catalog identifier.
89
+ return { buildTarget: target.buildTarget, toolchainType };
86
90
  }
87
- // Arduino (and any unlisted framework)use the board's FQBN.
91
+ // Unlisted framework → pass the board's stored build target through.
88
92
  return { buildTarget: target.buildTarget, toolchainType };
89
93
  }
90
94
  /**
91
95
  * The framework ids compatible with a board. Native boards map to ["native"];
92
- * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
96
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to zephyr for
93
97
  * unknown architectures). Order is preserved as the catalog order so the most
94
98
  * common framework is offered first in the prompt.
95
99
  */
@@ -105,6 +109,16 @@ export function frameworksForTarget(target) {
105
109
  // any id that has no catalog entry (defensive — keeps the prompt clean).
106
110
  return FRAMEWORK_CATALOG.filter((entry) => ids.includes(entry.id));
107
111
  }
112
+ /**
113
+ * Whether `frameworkId` is actually offered for `target`: compatible with the
114
+ * board's architecture AND installable. Auto-picking narrows via
115
+ * frameworksForTarget, but an explicit `--framework` bypasses that narrowing —
116
+ * callers accepting one must reject anything this returns false for (e.g.
117
+ * `--framework native` on an embedded board).
118
+ */
119
+ export function frameworkCompatibleWithTarget(target, frameworkId) {
120
+ return frameworksForTarget(target).some((f) => f.id === frameworkId && f.installable);
121
+ }
108
122
  /**
109
123
  * Detect the package manager for a directory. Priority:
110
124
  * 1. package.json#packageManager field (the strongest signal, Corepack-style)