@typecad/cuttlefish 0.1.0-alpha.2 → 1.0.0-alpha.11

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 (224) hide show
  1. package/README.md +10 -10
  2. package/dist/api/board-types.d.ts +1 -1
  3. package/dist/api/config.d.ts +38 -2
  4. package/dist/api/index.d.ts +1 -1
  5. package/dist/api/schema/types.d.ts +15 -0
  6. package/dist/api/shared/async-runtime-static.d.ts +12 -1
  7. package/dist/api/shared/async-runtime-static.js +69 -24
  8. package/dist/api/shared/async-symbol-detector.d.ts +11 -0
  9. package/dist/api/shared/async-symbol-detector.js +140 -0
  10. package/dist/api/shared/async-types.d.ts +24 -0
  11. package/dist/api/shared/coop-scheduler.d.ts +60 -0
  12. package/dist/api/shared/coop-scheduler.js +149 -0
  13. package/dist/api/shared/display-adapter.d.ts +4 -3
  14. package/dist/api/shared/display-adapter.js +15 -118
  15. package/dist/api/shared/display-adapters/sdl.js +38 -31
  16. package/dist/api/shared/display-profile.d.ts +47 -25
  17. package/dist/api/shared/display-profile.js +31 -164
  18. package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
  19. package/dist/api/shared/framework-manifest-registry.js +27 -0
  20. package/dist/api/shared/framework-manifest.d.ts +595 -0
  21. package/dist/api/shared/framework-manifest.js +193 -0
  22. package/dist/api/shared/glcdfont.d.ts +12 -0
  23. package/dist/api/shared/glcdfont.js +124 -0
  24. package/dist/api/shared/graphics-strategy.d.ts +37 -0
  25. package/dist/api/shared/hal-op-ir.d.ts +764 -1
  26. package/dist/api/shared/hal-op-ir.js +129 -1
  27. package/dist/api/shared/index.d.ts +22 -2
  28. package/dist/api/shared/index.js +26 -1
  29. package/dist/api/shared/ir-core.d.ts +4 -0
  30. package/dist/api/shared/ir-declarations.d.ts +6 -0
  31. package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
  32. package/dist/api/shared/native-display-op-resolver.js +64 -0
  33. package/dist/api/shared/platform-strategy.d.ts +119 -2
  34. package/dist/api/shared/polyfill-helper-registry.js +18 -1
  35. package/dist/api/shared/promise-runtime.d.ts +1 -1
  36. package/dist/api/shared/promise-runtime.js +95 -13
  37. package/dist/api/shared/spdx-licenses.d.ts +139 -0
  38. package/dist/api/shared/spdx-licenses.js +385 -0
  39. package/dist/api/shared/toolchain-types.d.ts +17 -0
  40. package/dist/api/shared/types.d.ts +8 -0
  41. package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
  42. package/dist/api/shared/validate-framework-manifest.js +494 -0
  43. package/dist/api/shared/worker-runtime-polyfill.d.ts +22 -0
  44. package/dist/api/shared/worker-runtime-polyfill.js +34 -0
  45. package/dist/api/shared/worker-runtime.d.ts +69 -0
  46. package/dist/api/shared/worker-runtime.js +163 -0
  47. package/dist/cli-utils.d.ts +1 -0
  48. package/dist/cli-utils.js +3 -1
  49. package/dist/cli.js +249 -32
  50. package/dist/config-loader.d.ts +7 -2
  51. package/dist/config-loader.js +23 -3
  52. package/dist/config-schema.d.ts +112 -70
  53. package/dist/config-schema.js +14 -0
  54. package/dist/contract/board-generator.d.ts +17 -0
  55. package/dist/contract/board-generator.js +57 -0
  56. package/dist/contract/contract-parser.d.ts +217 -0
  57. package/dist/contract/contract-parser.js +224 -0
  58. package/dist/contract/index.d.ts +22 -0
  59. package/dist/contract/index.js +68 -0
  60. package/dist/create/board-codegen.js +4 -4
  61. package/dist/create/board-generators.js +4 -5
  62. package/dist/create/board-spec.d.ts +72 -75
  63. package/dist/create/board-spec.js +0 -1
  64. package/dist/create/framework-catalog.d.ts +64 -0
  65. package/dist/create/framework-catalog.js +136 -0
  66. package/dist/create/index.d.ts +5 -1
  67. package/dist/create/index.js +3 -1
  68. package/dist/create/init-scaffold.d.ts +12 -3
  69. package/dist/create/init-scaffold.js +49 -14
  70. package/dist/create/init-templates.d.ts +4 -0
  71. package/dist/create/init-templates.js +271 -17
  72. package/dist/create/init-wizard.js +41 -27
  73. package/dist/create/install-deps.d.ts +32 -0
  74. package/dist/create/install-deps.js +46 -0
  75. package/dist/debug/preprocessor.js +178 -39
  76. package/dist/debug/types.d.ts +23 -0
  77. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  78. package/dist/diagnostics/mermaid-builder.js +34 -24
  79. package/dist/emit/compliance/arxml-writer.d.ts +11 -0
  80. package/dist/emit/compliance/arxml-writer.js +34 -0
  81. package/dist/emit/compliance/compliance-context.d.ts +57 -0
  82. package/dist/emit/compliance/compliance-context.js +113 -0
  83. package/dist/emit/compliance/deviation-ledger.d.ts +27 -0
  84. package/dist/emit/compliance/deviation-ledger.js +47 -0
  85. package/dist/emit/compliance/deviation-writer.d.ts +30 -0
  86. package/dist/emit/compliance/deviation-writer.js +37 -0
  87. package/dist/emit/compliance/index.d.ts +7 -0
  88. package/dist/emit/compliance/index.js +6 -0
  89. package/dist/emit/compliance/rule-engine.d.ts +13 -0
  90. package/dist/emit/compliance/rule-engine.js +101 -0
  91. package/dist/emit/compliance/rules.d.ts +16 -0
  92. package/dist/emit/compliance/rules.js +191 -0
  93. package/dist/emit/compliance/types.d.ts +59 -0
  94. package/dist/emit/compliance/types.js +8 -0
  95. package/dist/emit/cpp-emitter.js +4 -3
  96. package/dist/emit/emitters/class-emitter.js +6 -1
  97. package/dist/emit/emitters/emitter-context.d.ts +28 -1
  98. package/dist/emit/emitters/function-emitter-impl.js +153 -53
  99. package/dist/emit/emitters/line-appender.js +19 -0
  100. package/dist/emit/emitters/line-marker.d.ts +38 -0
  101. package/dist/emit/emitters/line-marker.js +39 -0
  102. package/dist/emit/emitters/output-finalizer.d.ts +6 -0
  103. package/dist/emit/emitters/output-finalizer.js +101 -12
  104. package/dist/emit/emitters/setup.d.ts +17 -0
  105. package/dist/emit/emitters/setup.js +372 -30
  106. package/dist/emit/emitters/top-level-prep.js +8 -0
  107. package/dist/emit/emitters/type-decl-emitter.js +28 -3
  108. package/dist/emit/emitters/ui-emitter.js +33 -9
  109. package/dist/emit/expression-renderer.d.ts +1 -1
  110. package/dist/emit/expression-renderer.js +91 -6
  111. package/dist/emit/route-hal-op.js +18 -5
  112. package/dist/emit/snprintf-helpers.js +15 -4
  113. package/dist/emit/statement-renderer.d.ts +10 -0
  114. package/dist/emit/statement-renderer.js +34 -5
  115. package/dist/emit/utils/async-state-machine.js +221 -125
  116. package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
  117. package/dist/emit/utils/hal-op-cpp-type.js +40 -0
  118. package/dist/framework-package.js +2 -0
  119. package/dist/framework-registry.d.ts +17 -0
  120. package/dist/install/framework-catalog.d.ts +53 -0
  121. package/dist/install/framework-catalog.js +107 -0
  122. package/dist/install/handle-install.d.ts +35 -0
  123. package/dist/install/handle-install.js +177 -0
  124. package/dist/install/index.d.ts +4 -0
  125. package/dist/install/index.js +3 -0
  126. package/dist/ir/adc-range-validation.js +40 -26
  127. package/dist/ir/build-ir-state.d.ts +1 -0
  128. package/dist/ir/build-ir-state.js +14 -0
  129. package/dist/ir/build-ir.js +9 -5
  130. package/dist/ir/call-graph.js +16 -0
  131. package/dist/ir/expression-to-ir.js +207 -6
  132. package/dist/ir/feature-registry.js +7 -25
  133. package/dist/ir/function-builder.js +22 -0
  134. package/dist/ir/hal/hal-emitter.d.ts +5 -2
  135. package/dist/ir/hal/hal-emitter.js +50 -18
  136. package/dist/ir/hal/hal-parser.d.ts +6 -0
  137. package/dist/ir/hal/hal-parser.js +81 -0
  138. package/dist/ir/hal/hal-plugins.js +733 -1
  139. package/dist/ir/identifier-collector.js +35 -0
  140. package/dist/ir/interrupt-analysis.d.ts +5 -1
  141. package/dist/ir/interrupt-analysis.js +16 -19
  142. package/dist/ir/memory-budget-validation.js +1 -0
  143. package/dist/ir/network-validation.d.ts +4 -0
  144. package/dist/ir/network-validation.js +184 -0
  145. package/dist/ir/ownership-analysis.js +39 -1
  146. package/dist/ir/peripheral-ownership.js +5 -0
  147. package/dist/ir/peripheral-validation.d.ts +1 -1
  148. package/dist/ir/peripheral-validation.js +6 -3
  149. package/dist/ir/pin-alias-conflict.d.ts +1 -1
  150. package/dist/ir/pin-alias-conflict.js +2 -1
  151. package/dist/ir/pin-capability-validation.js +71 -32
  152. package/dist/ir/pin-mode-validation.d.ts +2 -2
  153. package/dist/ir/pin-mode-validation.js +54 -18
  154. package/dist/ir/pin-safety.d.ts +1 -1
  155. package/dist/ir/pin-safety.js +2 -1
  156. package/dist/ir/program-analysis.d.ts +81 -0
  157. package/dist/ir/program-analysis.js +429 -0
  158. package/dist/ir/pulldown-validation.d.ts +1 -1
  159. package/dist/ir/pulldown-validation.js +2 -1
  160. package/dist/ir/pwm-timer-sharing.d.ts +1 -1
  161. package/dist/ir/pwm-timer-sharing.js +2 -1
  162. package/dist/ir/render-expr.js +11 -0
  163. package/dist/ir/resource-analysis.js +2 -0
  164. package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
  165. package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
  166. package/dist/ir/timing-validation.d.ts +6 -1
  167. package/dist/ir/timing-validation.js +61 -13
  168. package/dist/ir/transformers/call-statement.js +105 -0
  169. package/dist/ir/transformers/expressions.js +62 -0
  170. package/dist/ir/transformers/hal-call-resolver.js +21 -0
  171. package/dist/ir/transformers/hal-emit-helpers.js +1 -1
  172. package/dist/ir/transformers/namespace-methods.js +17 -12
  173. package/dist/ir/transformers/ui-reactive.js +2 -2
  174. package/dist/ir/transformers/variables.js +137 -19
  175. package/dist/ir/try-catch-validation.js +2 -0
  176. package/dist/ir/type-resolution.js +20 -2
  177. package/dist/ir/ui-element-auto-wire.js +7 -5
  178. package/dist/ir/unit-suspicion-validation.js +9 -7
  179. package/dist/ir/utils/map-statements.d.ts +4 -0
  180. package/dist/ir/utils/map-statements.js +79 -0
  181. package/dist/ir/validation-orchestrator.js +15 -8
  182. package/dist/ir/worker-analysis.d.ts +10 -0
  183. package/dist/ir/worker-analysis.js +261 -0
  184. package/dist/libdef/c-to-decl.d.ts +27 -0
  185. package/dist/libdef/c-to-decl.js +397 -0
  186. package/dist/libdef/component-decls.d.ts +2 -0
  187. package/dist/libdef/component-decls.js +6 -0
  188. package/dist/libdef/component-discovery.d.ts +43 -0
  189. package/dist/libdef/component-discovery.js +83 -0
  190. package/dist/libdef/cpp-to-decl.d.ts +9 -0
  191. package/dist/libdef/cpp-to-decl.js +72 -0
  192. package/dist/libdef/registry.js +5 -2
  193. package/dist/lint-cache.d.ts +59 -0
  194. package/dist/lint-cache.js +257 -0
  195. package/dist/orchestrator/graph-builder.js +14 -9
  196. package/dist/platform/coop-scheduler-runtime.d.ts +19 -0
  197. package/dist/platform/coop-scheduler-runtime.js +41 -0
  198. package/dist/platform/generic-strategy.d.ts +15 -3
  199. package/dist/platform/generic-strategy.js +49 -4
  200. package/dist/safety/safety-bridge.d.ts +11 -0
  201. package/dist/safety/safety-bridge.js +48 -0
  202. package/dist/safety/sidecar-bridge.d.ts +5 -0
  203. package/dist/safety/sidecar-bridge.js +22 -0
  204. package/dist/safety-hook.d.ts +79 -0
  205. package/dist/safety-hook.js +35 -0
  206. package/dist/testing.d.ts +8 -2
  207. package/dist/testing.js +9 -2
  208. package/dist/transpile.d.ts +3 -0
  209. package/dist/transpile.js +191 -49
  210. package/dist/types.d.ts +22 -3
  211. package/dist/ui-hook.d.ts +17 -3
  212. package/dist/utils/cli.js +123 -2
  213. package/dist/utils/fs.d.ts +13 -0
  214. package/dist/utils/fs.js +50 -0
  215. package/dist/utils/ui.js +3 -1
  216. package/package.json +23 -3
  217. package/dist/api/shared/display-adapters/eink-mono.d.ts +0 -2
  218. package/dist/api/shared/display-adapters/eink-mono.js +0 -53
  219. package/dist/api/shared/display-adapters/ssd1309.d.ts +0 -2
  220. package/dist/api/shared/display-adapters/ssd1309.js +0 -136
  221. package/dist/api/shared/display-adapters/st7796.d.ts +0 -2
  222. package/dist/api/shared/display-adapters/st7796.js +0 -132
  223. package/dist/ir/heap-array-validation.d.ts +0 -24
  224. package/dist/ir/heap-array-validation.js +0 -29
@@ -0,0 +1,64 @@
1
+ /** A framework family that ships as an installable @typecad/framework-* package. */
2
+ export interface FrameworkCatalogEntry {
3
+ /** Short id, e.g. "arduino". Matches the suffix of @typecad/framework-<id>. */
4
+ id: string;
5
+ /** Full npm package name, e.g. "@typecad/framework-arduino". */
6
+ packageName: string;
7
+ /** Human-readable label shown in the create prompt. */
8
+ label: string;
9
+ /**
10
+ * Whether a real package exists on the registry. Used to filter the prompt:
11
+ * "esp-idf" is a known family with no published package yet, so it must not
12
+ * be offered (it would fail at the package-manager step).
13
+ */
14
+ installable: boolean;
15
+ }
16
+ /**
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).
20
+ */
21
+ export declare const FRAMEWORK_CATALOG: readonly FrameworkCatalogEntry[];
22
+ /** Structural shape we need from a board/target. Keeps this module decoupled
23
+ * from the KnownTarget type (and trivially testable with literals). */
24
+ export interface BoardLike {
25
+ isNative?: boolean;
26
+ architecture?: string;
27
+ }
28
+ /** Look up a catalog entry by framework id (e.g. "arduino"). */
29
+ export declare function frameworkCatalogEntry(id: string): FrameworkCatalogEntry | undefined;
30
+ export interface FrameworkTargetProfile {
31
+ /** Framework-specific build target (FQBN for Arduino, board id for Zephyr). */
32
+ buildTarget?: string;
33
+ /** Toolchain backend the framework's compile/upload expects. */
34
+ toolchainType?: string;
35
+ }
36
+ export interface TargetProfileInput {
37
+ id: string;
38
+ isNative?: boolean;
39
+ /** The board's Arduino FQBN, as currently stored on KnownTarget. */
40
+ buildTarget?: string;
41
+ }
42
+ /**
43
+ * 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).
47
+ */
48
+ export declare function frameworkTargetProfile(target: TargetProfileInput, frameworkId: string): FrameworkTargetProfile;
49
+ /**
50
+ * The framework ids compatible with a board. Native boards map to ["native"];
51
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
52
+ * unknown architectures). Order is preserved as the catalog order so the most
53
+ * common framework is offered first in the prompt.
54
+ */
55
+ export declare function frameworksForTarget(target: BoardLike): FrameworkCatalogEntry[];
56
+ export type PackageManager = "npm" | "pnpm" | "yarn";
57
+ /**
58
+ * Detect the package manager for a directory. Priority:
59
+ * 1. package.json#packageManager field (the strongest signal, Corepack-style)
60
+ * 2. lockfile presence (pnpm-lock.yaml / yarn.lock → otherwise npm)
61
+ * 3. default "npm"
62
+ * Never throws — unreadable/missing files fall through to the next signal.
63
+ */
64
+ export declare function detectPackageManager(cwd: string): PackageManager;
@@ -0,0 +1,136 @@
1
+ // Framework catalog + board→framework compatibility for the create wizard.
2
+ //
3
+ // A "framework" is a `@typecad/framework-<id>` npm package. This module is the
4
+ // single source of truth for which frameworks exist as installable packages and
5
+ // which are compatible with a given board architecture. It is deliberately
6
+ // free of side effects (no fs/process beyond lockfile/package.json reads in
7
+ // detectPackageManager) so it unit-tests cleanly.
8
+ import path from "node:path";
9
+ import fs from "node:fs";
10
+ /**
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).
14
+ */
15
+ export const FRAMEWORK_CATALOG = [
16
+ { id: "arduino", packageName: "@typecad/framework-arduino", label: "Arduino (digitalWrite, Wire, SPI)", installable: true },
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 },
19
+ ];
20
+ /**
21
+ * Architecture → compatible framework ids. Derived from each framework
22
+ * package's framework.manifest.ts `profile.targets`:
23
+ * - arduino: avr, esp32 family, rp2040/rp2350, samd, stm32
24
+ * - zephyr: nrf52 (xiao_ble), esp32, esp32s3
25
+ * - native: desktop only
26
+ * Unknown embedded architectures fall back to [arduino] (the broadest core).
27
+ */
28
+ 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"],
39
+ nrf52: ["zephyr"],
40
+ };
41
+ const FALLBACK_FRAMEWORKS = ["arduino"];
42
+ /** Look up a catalog entry by framework id (e.g. "arduino"). */
43
+ export function frameworkCatalogEntry(id) {
44
+ return FRAMEWORK_CATALOG.find((f) => f.id === id);
45
+ }
46
+ // ── 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
52
+ // chip registry (src/chips/index.ts) + the demo configs.
53
+ const FRAMEWORK_TOOLCHAIN = {
54
+ arduino: "arduino-cli",
55
+ zephyr: "west",
56
+ // native has no toolchain (the native config path writes neither field).
57
+ };
58
+ /**
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.
65
+ */
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
+ };
73
+ /**
74
+ * 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
+ */
79
+ export function frameworkTargetProfile(target, frameworkId) {
80
+ if (target.isNative) {
81
+ return {};
82
+ }
83
+ const toolchainType = FRAMEWORK_TOOLCHAIN[frameworkId];
84
+ if (frameworkId === "zephyr") {
85
+ return { buildTarget: ZEPHYR_BOARD_IDS[target.id], toolchainType };
86
+ }
87
+ // Arduino (and any unlisted framework) → use the board's FQBN.
88
+ return { buildTarget: target.buildTarget, toolchainType };
89
+ }
90
+ /**
91
+ * The framework ids compatible with a board. Native boards map to ["native"];
92
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
93
+ * unknown architectures). Order is preserved as the catalog order so the most
94
+ * common framework is offered first in the prompt.
95
+ */
96
+ export function frameworksForTarget(target) {
97
+ let ids;
98
+ if (target.isNative) {
99
+ ids = ["native"];
100
+ }
101
+ else {
102
+ ids = ARCHITECTURE_FRAMEWORKS[target.architecture ?? ""] ?? FALLBACK_FRAMEWORKS;
103
+ }
104
+ // Re-map ids → catalog entries in catalog order (stable ordering), dropping
105
+ // any id that has no catalog entry (defensive — keeps the prompt clean).
106
+ return FRAMEWORK_CATALOG.filter((entry) => ids.includes(entry.id));
107
+ }
108
+ /**
109
+ * Detect the package manager for a directory. Priority:
110
+ * 1. package.json#packageManager field (the strongest signal, Corepack-style)
111
+ * 2. lockfile presence (pnpm-lock.yaml / yarn.lock → otherwise npm)
112
+ * 3. default "npm"
113
+ * Never throws — unreadable/missing files fall through to the next signal.
114
+ */
115
+ export function detectPackageManager(cwd) {
116
+ try {
117
+ const pkgPath = path.join(cwd, "package.json");
118
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
119
+ const pm = typeof pkg.packageManager === "string" ? pkg.packageManager : "";
120
+ if (pm.startsWith("pnpm"))
121
+ return "pnpm";
122
+ if (pm.startsWith("yarn"))
123
+ return "yarn";
124
+ if (pm.startsWith("npm"))
125
+ return "npm";
126
+ }
127
+ catch {
128
+ // no package.json or unparseable JSON — fall through to lockfile detection
129
+ }
130
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml")))
131
+ return "pnpm";
132
+ if (fs.existsSync(path.join(cwd, "yarn.lock")))
133
+ return "yarn";
134
+ // package-lock.json implies npm; absence also defaults to npm.
135
+ return "npm";
136
+ }
@@ -1,6 +1,10 @@
1
1
  export { scaffoldProject, normalizeProjectName, KNOWN_TARGETS, KNOWN_BOARDS, registerKnownTarget, printInitNextSteps } from './init-scaffold.js';
2
2
  export type { KnownTarget, KnownBoard, ScaffoldProjectResult } from './init-scaffold.js';
3
- export { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateGitignore, generateEslintConfig, } from './init-templates.js';
3
+ export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile } from './framework-catalog.js';
4
+ export type { FrameworkCatalogEntry, BoardLike, PackageManager, FrameworkTargetProfile, TargetProfileInput } from './framework-catalog.js';
5
+ export { installProjectDependencies, __setProjectInstallRunnerForTest } from './install-deps.js';
6
+ export type { ProjectInstallResult } from './install-deps.js';
7
+ export { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateStarterTest, generateStarterSim, generateGitignore, generateEslintConfig, } from './init-templates.js';
4
8
  export type { InitProjectOptions } from './init-templates.js';
5
9
  export { runInitWizard } from './init-wizard.js';
6
10
  export { scaffoldBoardPackages } from './board-codegen.js';
@@ -1,5 +1,7 @@
1
1
  export { scaffoldProject, normalizeProjectName, KNOWN_TARGETS, KNOWN_BOARDS, registerKnownTarget, printInitNextSteps } from './init-scaffold.js';
2
- export { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateGitignore, generateEslintConfig, } from './init-templates.js';
2
+ export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile } from './framework-catalog.js';
3
+ export { installProjectDependencies, __setProjectInstallRunnerForTest } from './install-deps.js';
4
+ export { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateStarterTest, generateStarterSim, generateGitignore, generateEslintConfig, } from './init-templates.js';
3
5
  export { runInitWizard } from './init-wizard.js';
4
6
  // Board codegen tool (`cuttlefish board add`)
5
7
  export { scaffoldBoardPackages } from './board-codegen.js';
@@ -6,10 +6,17 @@ export interface KnownTarget {
6
6
  isNative: boolean;
7
7
  architecture?: ArchitectureIdentifier;
8
8
  boardPackage?: string;
9
- frameworkPackage: string;
10
- framework: string;
9
+ /** Framework package + id. Optional on embedded targets: the scaffold wizard
10
+ * fills these in by discovering installed @typecad/framework-* packages, so
11
+ * KNOWN_TARGETS board entries do not hardcode a framework. Native targets
12
+ * set them directly. */
13
+ frameworkPackage?: string;
14
+ framework?: string;
11
15
  buildTarget?: string;
12
16
  mcu?: string;
17
+ /** Framework-specific config (becomes frameworkData in cuttlefish.config.ts).
18
+ * Carries framework-specific target/options data for the selected framework. */
19
+ frameworkData?: Record<string, unknown>;
13
20
  }
14
21
  export declare function registerKnownTarget(target: KnownTarget): void;
15
22
  export declare const KNOWN_TARGETS: ReadonlyArray<KnownTarget>;
@@ -24,4 +31,6 @@ export interface ScaffoldProjectResult {
24
31
  options: InitProjectOptions;
25
32
  }
26
33
  export declare function scaffoldProject(options: InitProjectOptions, outDir?: string): ScaffoldProjectResult;
27
- export declare function printInitNextSteps(options: InitProjectOptions, outDir: string): void;
34
+ export declare function printInitNextSteps(options: InitProjectOptions, outDir: string, opts?: {
35
+ installed?: boolean;
36
+ }): void;
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import fs from "node:fs";
3
3
  import chalk from "chalk";
4
- import { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateGitignore, generateBoardForwardingFile, generateEslintConfig, } from "./init-templates.js";
4
+ import { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterSketch, generateStarterTest, generateStarterSim, generateGitignore, generateBoardForwardingFile, generateEslintConfig, } from "./init-templates.js";
5
5
  import { generateEslintRules } from "./eslint-rules-template.js";
6
6
  const _knownTargets = [
7
7
  {
@@ -17,8 +17,6 @@ const _knownTargets = [
17
17
  isNative: false,
18
18
  architecture: 'avr',
19
19
  boardPackage: '@typecad/board-arduino-uno',
20
- frameworkPackage: '@typecad/framework-arduino',
21
- framework: 'arduino',
22
20
  buildTarget: 'arduino:avr:uno',
23
21
  mcu: 'atmega328p',
24
22
  },
@@ -28,8 +26,6 @@ const _knownTargets = [
28
26
  isNative: false,
29
27
  architecture: 'esp32',
30
28
  boardPackage: '@typecad/board-esp32-devkit',
31
- frameworkPackage: '@typecad/framework-arduino',
32
- framework: 'arduino',
33
29
  buildTarget: 'esp32:esp32:esp32',
34
30
  mcu: 'esp32',
35
31
  },
@@ -39,8 +35,6 @@ const _knownTargets = [
39
35
  isNative: false,
40
36
  architecture: 'esp32s3',
41
37
  boardPackage: '@typecad/board-esp32s3',
42
- frameworkPackage: '@typecad/framework-arduino',
43
- framework: 'arduino',
44
38
  buildTarget: 'esp32:esp32:esp32s3',
45
39
  mcu: 'esp32s3',
46
40
  },
@@ -50,8 +44,6 @@ const _knownTargets = [
50
44
  isNative: false,
51
45
  architecture: 'esp32c3',
52
46
  boardPackage: '@typecad/board-esp32c3',
53
- frameworkPackage: '@typecad/framework-arduino',
54
- framework: 'arduino',
55
47
  buildTarget: 'esp32:esp32:esp32c3',
56
48
  mcu: 'esp32c3',
57
49
  },
@@ -61,11 +53,27 @@ const _knownTargets = [
61
53
  isNative: false,
62
54
  architecture: 'esp32c6',
63
55
  boardPackage: '@typecad/board-esp32c6',
64
- frameworkPackage: '@typecad/framework-arduino',
65
- framework: 'arduino',
66
56
  buildTarget: 'esp32:esp32:esp32c6',
67
57
  mcu: 'esp32c6',
68
58
  },
59
+ {
60
+ id: 'rp2040',
61
+ displayName: 'RP2040 (Pico)',
62
+ isNative: false,
63
+ architecture: 'rp2040',
64
+ boardPackage: '@typecad/board-rp2040',
65
+ buildTarget: 'rp2040:rp2040:rpipico',
66
+ mcu: 'rp2040',
67
+ },
68
+ {
69
+ id: 'rp2350',
70
+ displayName: 'RP2350 (Pico 2)',
71
+ isNative: false,
72
+ architecture: 'rp2350',
73
+ boardPackage: '@typecad/board-rp2350',
74
+ buildTarget: 'rp2040:rp2040:rpipico2',
75
+ mcu: 'rp2350',
76
+ },
69
77
  ];
70
78
  export function registerKnownTarget(target) {
71
79
  const existing = _knownTargets.findIndex(t => t.id === target.id);
@@ -128,23 +136,50 @@ export function scaffoldProject(options, outDir) {
128
136
  fs.writeFileSync(sketchPath, generateStarterSketch(options), 'utf-8');
129
137
  createdFiles.push(sketchPath);
130
138
  }
139
+ // Embedded projects get a starter hardware test (@typecad/expect / cuttlefish-test).
140
+ // Native projects have no serial/board path, so they get no test setup.
141
+ if (!options.isNative) {
142
+ const testsDir = path.join(resolvedOutDir, 'tests');
143
+ fs.mkdirSync(testsDir, { recursive: true });
144
+ const testPath = path.join(testsDir, '01-basics.test.ts');
145
+ fs.writeFileSync(testPath, generateStarterTest(options), 'utf-8');
146
+ createdFiles.push(testPath);
147
+ // Host-side simulation (@typecad/simulator + vitest). sim/ is kept separate
148
+ // from tests/ so `vitest run sim/` never loads the @typecad/expect no-op
149
+ // stubs, and `cuttlefish-test` (which globs tests/) never tries to flash a
150
+ // simulator file as firmware.
151
+ const simDir = path.join(resolvedOutDir, 'sim');
152
+ fs.mkdirSync(simDir, { recursive: true });
153
+ const simPath = path.join(simDir, 'main.test.ts');
154
+ fs.writeFileSync(simPath, generateStarterSim(options), 'utf-8');
155
+ createdFiles.push(simPath);
156
+ }
131
157
  return { createdFiles, outDir: resolvedOutDir, options };
132
158
  }
133
- export function printInitNextSteps(options, outDir) {
159
+ export function printInitNextSteps(options, outDir, opts = {}) {
134
160
  const relativeDir = path.relative(process.cwd(), outDir) || '.';
135
161
  console.log();
136
162
  console.log(chalk.cyan(`⤳ Cuttlefish`));
137
163
  console.log();
138
164
  console.log(chalk.bold.white("Next steps:"));
139
165
  console.log(chalk.dim(` cd ${relativeDir}`));
140
- console.log(chalk.dim(` npm install`));
166
+ // When create already installed dependencies, don't tell the user to do it again.
167
+ if (!opts.installed) {
168
+ console.log(chalk.dim(` npm install`));
169
+ }
141
170
  console.log(` ${chalk.cyan("npm run compile")}`);
142
171
  if (!options.isNative) {
143
172
  const portHint = process.platform === 'win32' ? 'COM4' : '/dev/ttyACM0';
144
173
  console.log();
174
+ console.log(chalk.bold.white("To simulate without hardware:"));
175
+ console.log(` ${chalk.cyan("npm run simulate")}`);
176
+ console.log();
145
177
  console.log(chalk.bold.white("To upload to your board:"));
146
178
  console.log(` ${chalk.cyan("npm run upload")}`);
147
179
  console.log();
148
- console.log(chalk.dim(`Edit ${chalk.white("package.json")} to change the serial port from ${chalk.white(portHint)} to your port.`));
180
+ console.log(chalk.bold.white("To run hardware tests:"));
181
+ console.log(` ${chalk.cyan("npm run test:hw")}`);
182
+ console.log();
183
+ console.log(chalk.dim(`Edit ${chalk.white("cuttlefish.config.ts")} to change the serial port from ${chalk.white(portHint)} to your port.`));
149
184
  }
150
185
  }
@@ -13,12 +13,16 @@ export interface InitProjectOptions {
13
13
  baudRate?: number;
14
14
  includeSketch: boolean;
15
15
  toolchainType?: string;
16
+ /** Extra frameworkData fields (e.g. `{ target: 'esp32s3' }` for framework-esp32). */
17
+ frameworkData?: Record<string, unknown>;
16
18
  }
17
19
  export declare function generateProjectPackageJson(options: InitProjectOptions): string;
18
20
  export declare function generateProjectTsconfig(options: InitProjectOptions): string;
19
21
  export declare function generateProjectConfig(options: InitProjectOptions): string;
20
22
  export declare function generateProjectEnvDts(options: InitProjectOptions): string;
21
23
  export declare function generateStarterSketch(options: InitProjectOptions): string;
24
+ export declare function generateStarterTest(_options: InitProjectOptions): string;
25
+ export declare function generateStarterSim(options: InitProjectOptions): string;
22
26
  export declare function generateBoardForwardingFile(boardPackage: string): string;
23
27
  export declare function generateGitignore(_options: InitProjectOptions): string;
24
28
  export declare function generateEslintConfig(_options: InitProjectOptions): string;