@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.
- package/README.md +82 -79
- package/assets/editor-extensions/typecad-debug/README.md +141 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js +347 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js.map +1 -0
- package/assets/editor-extensions/typecad-debug/package.json +76 -0
- package/assets/editor-extensions/typecad-ui/LICENSE +27 -0
- package/assets/editor-extensions/typecad-ui/README.md +52 -0
- package/assets/editor-extensions/typecad-ui/file-icon-dark.png +0 -0
- package/assets/editor-extensions/typecad-ui/file-icon-light.png +0 -0
- package/assets/editor-extensions/typecad-ui/icon.png +0 -0
- package/assets/editor-extensions/typecad-ui/language-configuration.json +43 -0
- package/assets/editor-extensions/typecad-ui/package.json +54 -0
- package/assets/editor-extensions/typecad-ui/snippets/typecad-ui.json +80 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/markdown-ui.json +45 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/typecad-ui.tmLanguage.json +1269 -0
- package/dist/api/config.d.ts +30 -27
- package/dist/api/schema/types.d.ts +20 -3
- package/dist/api/shared/async-runtime-static.d.ts +1 -1
- package/dist/api/shared/async-runtime-static.js +5 -5
- package/dist/api/shared/async-types.d.ts +3 -2
- package/dist/api/shared/board-catalog.d.ts +2 -0
- package/dist/api/shared/board-catalog.js +6 -0
- package/dist/api/shared/board-resolver.d.ts +4 -7
- package/dist/api/shared/board-resolver.js +2 -1
- package/dist/api/shared/coop-scheduler.d.ts +1 -1
- package/dist/api/shared/coop-scheduler.js +1 -1
- package/dist/api/shared/cpp-type-ir.d.ts +1 -1
- package/dist/api/shared/cpp-type-ir.js +1 -1
- package/dist/api/shared/display-profile.d.ts +1 -1
- package/dist/api/shared/display-profile.js +3 -5
- package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
- package/dist/api/shared/framework-manifest-registry.js +0 -1
- package/dist/api/shared/framework-manifest.d.ts +65 -507
- package/dist/api/shared/framework-manifest.js +6 -11
- package/dist/api/shared/hal-op-ir.d.ts +294 -685
- package/dist/api/shared/hal-op-ir.js +31 -65
- package/dist/api/shared/index.d.ts +0 -4
- package/dist/api/shared/index.js +1 -7
- package/dist/api/shared/ir-core.d.ts +6 -0
- package/dist/api/shared/ir-declarations.d.ts +4 -0
- package/dist/api/shared/ir.d.ts +1 -3
- package/dist/api/shared/platform-strategy.d.ts +14 -37
- package/dist/api/shared/polyfill-helper-registry.js +0 -5
- package/dist/api/shared/polyfill-types.js +0 -27
- package/dist/api/shared/promise-runtime.js +3 -3
- package/dist/api/shared/spdx-licenses.d.ts +12 -10
- package/dist/api/shared/spdx-licenses.js +1 -1
- package/dist/api/shared/toolchain-types.d.ts +1 -1
- package/dist/api/shared/toolchain-types.js +3 -3
- package/dist/api/shared/types.d.ts +0 -3
- package/dist/api/shared/validate-framework-manifest.js +13 -33
- package/dist/board-catalog/dts-reader.d.ts +220 -0
- package/dist/board-catalog/dts-reader.js +1052 -0
- package/dist/board-catalog/index.d.ts +11 -0
- package/dist/board-catalog/index.js +12 -0
- package/dist/board-catalog/pinconfig.d.ts +48 -0
- package/dist/board-catalog/pinconfig.js +263 -0
- package/dist/board-catalog/sdk.d.ts +82 -0
- package/dist/board-catalog/sdk.js +180 -0
- package/dist/board-catalog/store.d.ts +196 -0
- package/dist/board-catalog/store.js +363 -0
- package/dist/board-catalog/types.d.ts +233 -0
- package/dist/board-catalog/types.js +7 -0
- package/dist/board-catalog/walker.d.ts +112 -0
- package/dist/board-catalog/walker.js +1101 -0
- package/dist/cli-utils.d.ts +2 -2
- package/dist/cli-utils.js +5 -5
- package/dist/cli.js +227 -244
- package/dist/config-loader.d.ts +14 -19
- package/dist/config-loader.js +242 -78
- package/dist/config-schema.d.ts +19 -227
- package/dist/config-schema.js +9 -8
- package/dist/contract/board-generator.d.ts +4 -4
- package/dist/contract/board-generator.js +16 -5
- package/dist/contract/contract-parser.d.ts +36 -127
- package/dist/contract/contract-parser.js +76 -0
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.js +70 -21
- package/dist/create/active-board-catalog.d.ts +9 -0
- package/dist/create/active-board-catalog.js +94 -0
- package/dist/create/board-catalog.generated.d.ts +96 -0
- package/dist/create/board-catalog.generated.js +128737 -0
- package/dist/create/board-search.d.ts +23 -0
- package/dist/create/board-search.js +88 -0
- package/dist/create/editor-integration.d.ts +32 -0
- package/dist/create/editor-integration.js +257 -0
- package/dist/create/eslint-rules-template.d.ts +2 -2
- package/dist/create/framework-catalog.d.ts +48 -8
- package/dist/create/framework-catalog.js +58 -44
- package/dist/create/index.d.ts +8 -13
- package/dist/create/index.js +5 -9
- package/dist/create/mcu-target.d.ts +39 -0
- package/dist/create/mcu-target.js +80 -0
- package/dist/create/pack-targets.d.ts +19 -0
- package/dist/create/pack-targets.js +56 -0
- package/dist/create/{init-scaffold.d.ts → scaffold.d.ts} +8 -11
- package/dist/create/{init-scaffold.js → scaffold.js} +28 -87
- package/dist/create/templates.d.ts +51 -0
- package/dist/create/{init-templates.js → templates.js} +135 -116
- package/dist/create/wizard.d.ts +19 -0
- package/dist/create/wizard.js +314 -0
- package/dist/debug/preprocessor.d.ts +5 -0
- package/dist/debug/preprocessor.js +31 -7
- package/dist/diagnostics/diagnostics-report.d.ts +1 -1
- package/dist/diagnostics/diagnostics-report.js +3 -11
- package/dist/diagnostics/json-schema.d.ts +1 -1
- package/dist/diagnostics/md-writer.js +2 -2
- package/dist/diagnostics/mermaid-builder.d.ts +1 -1
- package/dist/diagnostics/mermaid-builder.js +1 -1
- package/dist/emit/cpp-emitter.js +4 -1
- package/dist/emit/emitters/class-emitter.js +32 -4
- package/dist/emit/emitters/emitter-context.d.ts +11 -0
- package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
- package/dist/emit/emitters/function-emitter-impl.js +33 -17
- package/dist/emit/emitters/output-finalizer.d.ts +7 -0
- package/dist/emit/emitters/output-finalizer.js +31 -23
- package/dist/emit/emitters/setup.js +147 -63
- package/dist/emit/emitters/top-level-prep.js +1 -1
- package/dist/emit/emitters/type-decl-emitter.js +13 -8
- package/dist/emit/emitters/ui-emitter.js +1 -1
- package/dist/emit/expression-renderer.d.ts +3 -3
- package/dist/emit/expression-renderer.js +17 -7
- package/dist/emit/route-hal-op.js +17 -48
- package/dist/emit/snprintf-helpers.d.ts +1 -3
- package/dist/emit/snprintf-helpers.js +1 -39
- package/dist/emit/statement-renderer.d.ts +0 -4
- package/dist/emit/statement-renderer.js +54 -45
- package/dist/emit/utils/async-state-machine.d.ts +16 -9
- package/dist/emit/utils/async-state-machine.js +56 -54
- package/dist/emit/utils/comment-helpers.d.ts +0 -8
- package/dist/emit/utils/comment-helpers.js +1 -1
- package/dist/emit/utils/cpp-helpers.d.ts +2 -2
- package/dist/emit/utils/cpp-helpers.js +2 -2
- package/dist/emit/utils/hal-op-cpp-type.js +4 -6
- package/dist/emit/utils/index.d.ts +3 -3
- package/dist/emit/utils/index.js +3 -3
- package/dist/emit/utils/type-inference.d.ts +1 -29
- package/dist/emit/utils/type-inference.js +0 -75
- package/dist/framework-package.d.ts +3 -0
- package/dist/framework-package.js +23 -6
- package/dist/framework-registry.d.ts +5 -5
- package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
- package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
- package/dist/frameworks/native/index.d.ts +3 -0
- package/dist/frameworks/native/index.js +15 -0
- package/dist/frameworks/native/native-compile.d.ts +17 -0
- package/dist/frameworks/native/native-compile.js +170 -0
- package/dist/frameworks/native/native-config.d.ts +41 -0
- package/dist/frameworks/native/native-config.js +7 -0
- package/dist/frameworks/native/strategy.d.ts +97 -0
- package/dist/frameworks/native/strategy.js +664 -0
- package/dist/ir/board-resolver.d.ts +18 -23
- package/dist/ir/board-resolver.js +43 -401
- package/dist/ir/build-ir-state.d.ts +3 -0
- package/dist/ir/build-ir-state.js +42 -0
- package/dist/ir/build-ir.d.ts +1 -1
- package/dist/ir/build-ir.js +64 -45
- package/dist/ir/declaration-builders.js +1 -0
- package/dist/ir/expression-to-ir.js +17 -10
- package/dist/ir/hal/hal-emitter.d.ts +0 -2
- package/dist/ir/hal/hal-emitter.js +92 -41
- package/dist/ir/hal/hal-parser.d.ts +5 -5
- package/dist/ir/hal/hal-parser.js +128 -36
- package/dist/ir/hal/hal-plugins.d.ts +0 -1
- package/dist/ir/hal/hal-plugins.js +425 -716
- package/dist/ir/heap-analysis.js +2 -41
- package/dist/ir/identifier-collector.js +32 -20
- package/dist/ir/network-validation.js +7 -11
- package/dist/ir/ownership-analysis.js +75 -13
- package/dist/ir/peripheral-usage.d.ts +8 -2
- package/dist/ir/peripheral-usage.js +78 -149
- package/dist/ir/peripheral-validation.js +23 -3
- package/dist/ir/pin-capability-validation.d.ts +12 -0
- package/dist/ir/pin-capability-validation.js +61 -97
- package/dist/ir/pin-mode-validation.js +5 -5
- package/dist/ir/program-analysis.d.ts +8 -15
- package/dist/ir/program-analysis.js +140 -323
- package/dist/ir/pulldown-validation.js +11 -4
- package/dist/ir/resource-analysis.js +15 -3
- package/dist/ir/statement-to-ir.js +0 -6
- package/dist/ir/timing-validation.js +1 -1
- package/dist/ir/transformers/array-methods.js +11 -5
- package/dist/ir/transformers/call-statement.js +20 -87
- package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
- package/dist/ir/transformers/callback-context-registry.js +8 -16
- package/dist/ir/transformers/control-flow.js +0 -13
- package/dist/ir/transformers/expressions.js +10 -9
- package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
- package/dist/ir/transformers/hal-call-resolver.js +24 -10
- package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
- package/dist/ir/transformers/hal-emit-helpers.js +2 -2
- package/dist/ir/transformers/namespace-methods.js +1 -1
- package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
- package/dist/ir/transformers/ui-callback-lowering.js +0 -24
- package/dist/ir/transformers/variables.js +338 -42
- package/dist/ir/try-catch-validation.js +4 -3
- package/dist/ir/type-resolution.js +15 -4
- package/dist/ir/validation-orchestrator.js +0 -9
- package/dist/libdef/cpp-to-decl.d.ts +0 -9
- package/dist/libdef/cpp-to-decl.js +0 -72
- package/dist/libdef/registry.d.ts +0 -1
- package/dist/libdef/registry.js +1 -24
- package/dist/library/catalog.d.ts +35 -0
- package/dist/library/catalog.js +67 -0
- package/dist/library/cli.d.ts +2 -0
- package/dist/library/cli.js +168 -0
- package/dist/library/init.d.ts +25 -0
- package/dist/library/init.js +397 -0
- package/dist/library/install.d.ts +9 -0
- package/dist/library/install.js +80 -0
- package/dist/library/registry-search.d.ts +34 -0
- package/dist/library/registry-search.js +50 -0
- package/dist/library/validate.d.ts +17 -0
- package/dist/library/validate.js +175 -0
- package/dist/library-packages.d.ts +95 -0
- package/dist/library-packages.js +275 -0
- package/dist/mapping/peripheral-names.js +9 -4
- package/dist/mapping/source-map.d.ts +3 -4
- package/dist/mapping/source-map.js +12 -18
- package/dist/orchestrator/graph-builder.d.ts +3 -3
- package/dist/orchestrator/graph-builder.js +29 -12
- package/dist/orchestrator/type-checker.d.ts +3 -3
- package/dist/orchestrator/type-checker.js +3 -3
- package/dist/platform/async-runtime.js +1 -1
- package/dist/platform/coop-scheduler-runtime.js +2 -2
- package/dist/platform/generic-debug-codegen.d.ts +36 -0
- package/dist/platform/generic-debug-codegen.js +185 -0
- package/dist/platform/generic-strategy.d.ts +3 -4
- package/dist/platform/generic-strategy.js +5 -80
- package/dist/platform/index.js +1 -1
- package/dist/platform/registry.d.ts +2 -2
- package/dist/platform/registry.js +2 -2
- package/dist/preview/client.js +17 -3
- package/dist/safety/asil-decorators.d.ts +32 -0
- package/dist/safety/asil-decorators.js +32 -0
- package/dist/safety/authoring.d.ts +85 -0
- package/dist/safety/authoring.js +61 -0
- package/dist/safety/engine.d.ts +3 -0
- package/dist/safety/engine.js +83 -0
- package/dist/safety/hal/ops.d.ts +48 -0
- package/dist/safety/hal/ops.js +46 -0
- package/dist/safety/iso26262/analyze.d.ts +13 -0
- package/dist/safety/iso26262/analyze.js +29 -0
- package/dist/safety/iso26262/asil.d.ts +10 -0
- package/dist/safety/iso26262/asil.js +22 -0
- package/dist/safety/iso26262/collect.d.ts +14 -0
- package/dist/safety/iso26262/collect.js +137 -0
- package/dist/safety/iso26262/goto-checker.d.ts +10 -0
- package/dist/safety/iso26262/goto-checker.js +72 -0
- package/dist/safety/iso26262/heap-checker.d.ts +7 -0
- package/dist/safety/iso26262/heap-checker.js +57 -0
- package/dist/safety/iso26262/init-checker.d.ts +13 -0
- package/dist/safety/iso26262/init-checker.js +127 -0
- package/dist/safety/iso26262/loop-checker.d.ts +7 -0
- package/dist/safety/iso26262/loop-checker.js +86 -0
- package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
- package/dist/safety/iso26262/recursion-checker.js +134 -0
- package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
- package/dist/safety/iso26262/sidecar-writer.js +13 -0
- package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
- package/dist/safety/passes/pinMode-intercept.js +60 -0
- package/dist/safety/runtime/mode-table.d.ts +5 -0
- package/dist/safety/runtime/mode-table.js +55 -0
- package/dist/safety/runtime/polyfills.d.ts +6 -0
- package/dist/safety/runtime/polyfills.js +12 -0
- package/dist/safety/runtime/result-struct.d.ts +11 -0
- package/dist/safety/runtime/result-struct.js +98 -0
- package/dist/safety/runtime/safe-int.d.ts +33 -0
- package/dist/safety/runtime/safe-int.js +170 -0
- package/dist/safety/runtime/safe-traits.d.ts +4 -0
- package/dist/safety/runtime/safe-traits.js +95 -0
- package/dist/safety/runtime/safe-variable.d.ts +39 -0
- package/dist/safety/runtime/safe-variable.js +226 -0
- package/dist/safety/runtime/vote.d.ts +8 -0
- package/dist/safety/runtime/vote.js +92 -0
- package/dist/safety/runtime/write-verify.d.ts +8 -0
- package/dist/safety/runtime/write-verify.js +71 -0
- package/dist/safety/safe-int-types.d.ts +45 -0
- package/dist/safety/safe-int-types.js +25 -0
- package/dist/safety/safe-variable-types.d.ts +29 -0
- package/dist/safety/safe-variable-types.js +19 -0
- package/dist/safety/safety-bridge.d.ts +5 -6
- package/dist/safety/safety-bridge.js +15 -28
- package/dist/safety/sidecar-bridge.d.ts +1 -3
- package/dist/safety/sidecar-bridge.js +3 -20
- package/dist/safety/specifiers.d.ts +6 -0
- package/dist/safety/specifiers.js +14 -0
- package/dist/safety-hook.d.ts +8 -7
- package/dist/safety-hook.js +12 -13
- package/dist/testing.d.ts +5 -6
- package/dist/testing.js +5 -5
- package/dist/transpile/resolution.d.ts +1 -1
- package/dist/transpile/resolution.js +18 -9
- package/dist/transpile/test-pins.d.ts +18 -0
- package/dist/transpile/test-pins.js +142 -0
- package/dist/transpile.d.ts +1 -2
- package/dist/transpile.js +90 -29
- package/dist/types.d.ts +45 -26
- package/dist/ui-hook.d.ts +1 -1
- package/dist/utils/cli.d.ts +2 -2
- package/dist/utils/cli.js +160 -157
- package/dist/utils/fs.d.ts +3 -4
- package/dist/utils/fs.js +4 -5
- package/dist/utils/strings.d.ts +0 -1
- package/dist/utils/strings.js +0 -8
- package/dist/utils/ui.d.ts +5 -2
- package/dist/utils/ui.js +13 -3
- package/package.json +158 -149
- package/dist/add-preset.d.ts +0 -4
- package/dist/add-preset.js +0 -74
- package/dist/api/shared/async-symbol-detector.d.ts +0 -11
- package/dist/api/shared/async-symbol-detector.js +0 -140
- package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
- package/dist/api/shared/native-display-op-resolver.js +0 -64
- package/dist/create/board-checklist.d.ts +0 -2
- package/dist/create/board-checklist.js +0 -52
- package/dist/create/board-codegen.d.ts +0 -9
- package/dist/create/board-codegen.js +0 -238
- package/dist/create/board-generators.d.ts +0 -12
- package/dist/create/board-generators.js +0 -651
- package/dist/create/board-spec.d.ts +0 -637
- package/dist/create/board-spec.js +0 -214
- package/dist/create/init-templates.d.ts +0 -28
- package/dist/create/init-wizard.d.ts +0 -8
- package/dist/create/init-wizard.js +0 -182
- package/dist/install/framework-catalog.d.ts +0 -53
- package/dist/install/framework-catalog.js +0 -107
- package/dist/install/handle-install.d.ts +0 -35
- package/dist/install/handle-install.js +0 -177
- package/dist/install/index.d.ts +0 -4
- package/dist/install/index.js +0 -3
- package/dist/ir/pin-state-tracking.d.ts +0 -58
- package/dist/ir/pin-state-tracking.js +0 -182
- package/dist/ir/pwm-timer-sharing.d.ts +0 -4
- package/dist/ir/pwm-timer-sharing.js +0 -94
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
- package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
- package/dist/libdef/component-decls.d.ts +0 -2
- package/dist/libdef/component-decls.js +0 -6
- package/dist/libdef/component-discovery.d.ts +0 -43
- package/dist/libdef/component-discovery.js +0 -83
- package/dist/theme-tokens.d.ts +0 -22
- package/dist/theme-tokens.js +0 -172
package/dist/cli.js
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { parseCommandLine, printHelp } from "./utils/cli.js";
|
|
5
|
-
import {
|
|
5
|
+
import { runLibraryCommand } from "./library/cli.js";
|
|
6
|
+
import { scaffoldProject, printCreateNextSteps, KNOWN_TARGETS, frameworksForTarget, frameworkCatalogEntry, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard } from "./create/index.js";
|
|
7
|
+
import { findPackBoard, packBoardAsTarget } from "./create/pack-targets.js";
|
|
8
|
+
import { activeBoardCatalog, assertZephyrSdkForCreate, formatZephyrSdkFound, ensureFreshBoardCatalog, resetBoardCatalogOverlayCache, sdkFingerprint, PINNED_ZEPHYR_MANIFEST_REV } from "./board-catalog/index.js";
|
|
6
9
|
import { generateFrameworkDebugArtifacts } from "./create/debug-artifacts.js";
|
|
7
|
-
import {
|
|
10
|
+
import { runCreateWizard } from "./create/index.js";
|
|
8
11
|
import { installProjectDependencies } from "./create/install-deps.js";
|
|
9
|
-
import {
|
|
10
|
-
import { generateDecl, generateDeclsForDirectory
|
|
11
|
-
import { mapCppLocationToTs, readSourceMap, resolveMapPath } from "./mapping/source-map.js";
|
|
12
|
+
import { transpileFile } from "./transpile.js";
|
|
13
|
+
import { generateDecl, generateDeclsForDirectory } from "./libdef/cpp-to-decl.js";
|
|
12
14
|
import { compileSource, uploadFirmware, monitorDevice } from "./platform/toolchain.js";
|
|
13
15
|
import { resolveStrategy } from "./platform/registry.js";
|
|
14
16
|
import { loadFrameworkPackage } from "./framework-package.js";
|
|
15
17
|
import { getLoadedFramework, hasLoadedFramework } from "./framework-registry.js";
|
|
16
|
-
import { loadCuttlefishConfig, generateVirtualTypeDeclaration } from "./config-loader.js";
|
|
18
|
+
import { loadCuttlefishConfig, generateVirtualTypeDeclaration, regenBoardModule } from "./config-loader.js";
|
|
17
19
|
import { generateContractBoard } from "./contract/index.js";
|
|
18
20
|
import { requireUIHook, hasUIHook } from "./ui-hook.js";
|
|
19
21
|
import { loadUIEngine } from "./ui/ui-bridge.js";
|
|
@@ -35,38 +37,67 @@ function displayConfigForTranspile(config) {
|
|
|
35
37
|
}
|
|
36
38
|
return display;
|
|
37
39
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Apply the PSRAM config to the Arduino build: append the `PSRAM={opi|quad}`
|
|
40
|
-
* menu option to the FQBN (so the Arduino core's psramFound()/ps_malloc work
|
|
41
|
-
* at runtime — they're gated on the board menu option, not just the define)
|
|
42
|
-
* and add `-DBOARD_HAS_PSRAM` to the defines (so the framework's PSRAM canvas
|
|
43
|
-
* allocator is compiled in). No-op when psram is unset or the target isn't an
|
|
44
|
-
* Arduino FQBN (the PSRAM= option is Arduino-core-specific).
|
|
45
|
-
*/
|
|
46
|
-
function applyPsramToArduinoBuild(buildTarget, defines, psram) {
|
|
47
|
-
if (!psram || !buildTarget || !buildTarget.includes(':')) {
|
|
48
|
-
return { buildTarget, defines: defines ?? {} };
|
|
49
|
-
}
|
|
50
|
-
// Arduino FQBN config options follow the board:option as `key=value` pairs.
|
|
51
|
-
// Append PSRAM= if not already present (don't clobber an explicit override).
|
|
52
|
-
const psramOpt = `PSRAM=${psram}`;
|
|
53
|
-
const adjustedTarget = buildTarget.includes('PSRAM=') ? buildTarget : `${buildTarget}:${psramOpt}`;
|
|
54
|
-
const adjustedDefines = { ...(defines ?? {}) };
|
|
55
|
-
if (!('BOARD_HAS_PSRAM' in adjustedDefines))
|
|
56
|
-
adjustedDefines.BOARD_HAS_PSRAM = '';
|
|
57
|
-
return { buildTarget: adjustedTarget, defines: adjustedDefines };
|
|
58
|
-
}
|
|
59
40
|
async function handleCreate(options) {
|
|
60
41
|
const targetId = options.target ?? options.board;
|
|
61
42
|
const hasTarget = !!targetId;
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
// SDK gate: the installed Zephyr SDK is the source of truth — boards, pin
|
|
44
|
+
// data, everything derives from it. No SDK (or a wrong-version one) means
|
|
45
|
+
// the project cannot work; fail with the fix instead of scaffolding junk.
|
|
46
|
+
// Native-desktop projects are the one exception (no Zephyr involved).
|
|
47
|
+
const wantsNative = options.framework === "native" || (!options.framework && targetId === "native");
|
|
48
|
+
if (!wantsNative) {
|
|
49
|
+
// The gate doubles as the lookup — its ok-return carries everything the
|
|
50
|
+
// printout needs (no second discovery pass).
|
|
51
|
+
const sdk = assertZephyrSdkForCreate();
|
|
52
|
+
if (sdk) {
|
|
53
|
+
console.log(chalk.gray(' Zephyr SDK:'));
|
|
54
|
+
for (const line of formatZephyrSdkFound(sdk))
|
|
55
|
+
console.log(chalk.gray(line));
|
|
56
|
+
}
|
|
57
|
+
// Build/refresh the board registry from the installed SDK now — the
|
|
58
|
+
// wizard's board list and --board resolution below read it.
|
|
59
|
+
ensureFreshBoardCatalog();
|
|
60
|
+
resetBoardCatalogOverlayCache();
|
|
61
|
+
}
|
|
62
|
+
// Preseeded targets run non-interactively ONLY when stdin is not a TTY
|
|
63
|
+
// (scripts/CI pipe nothing and expect zero prompts). A human typing
|
|
64
|
+
// `cuttlefish create x --board <target>` still gets the wizard — it
|
|
65
|
+
// prints the preseeded answers and asks only what was not specified
|
|
66
|
+
// (probe method, serial port, baud, starter).
|
|
67
|
+
const interactive = process.stdin.isTTY === true;
|
|
68
|
+
if (hasTarget && !interactive) {
|
|
69
|
+
// Target resolution: --target/--board names the native target or any
|
|
70
|
+
// board from the catalog (a qualified target like
|
|
71
|
+
// 'nucleo_f411re/stm32f411xe', or a bare board id).
|
|
72
|
+
let target = KNOWN_TARGETS.find(t => t.id === targetId)
|
|
73
|
+
?? (() => {
|
|
74
|
+
const pack = findPackBoard(targetId);
|
|
75
|
+
return pack ? packBoardAsTarget(pack) : undefined;
|
|
76
|
+
})();
|
|
64
77
|
if (!target) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
// No catalog on this machine (or a typo). A QUALIFIED target passes
|
|
79
|
+
// through raw: the first build syncs the catalog from the Zephyr tree
|
|
80
|
+
// and validates it there, where the real error is actionable.
|
|
81
|
+
if (targetId.includes("/")) {
|
|
82
|
+
target = packBoardAsTarget({
|
|
83
|
+
identifier: targetId,
|
|
84
|
+
name: targetId,
|
|
85
|
+
soc: targetId.split("/")[1] ?? "",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const known = KNOWN_TARGETS.map(t => ` - ${t.id} (${t.displayName})`);
|
|
90
|
+
throw new Error(`Unknown target '${targetId}'. Built-in targets:\n${known.join("\n")}\n` +
|
|
91
|
+
`Or pass any board from the catalog (e.g. --board nucleo_f411re/stm32f411xe) —\n` +
|
|
92
|
+
`the catalog comes from your Zephyr tree; run \`cuttlefish board sync\` (or the\n` +
|
|
93
|
+
`installer) to generate it.`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const compatibleFrameworks = frameworksForTarget(target)
|
|
97
|
+
.filter(f => f.installable);
|
|
98
|
+
// Resolve the framework. --framework wins (validated against the board's
|
|
99
|
+
// compatible set); otherwise narrow via the catalog for the chosen board
|
|
100
|
+
// and auto-pick when exactly one is compatible.
|
|
70
101
|
let frameworkId;
|
|
71
102
|
let frameworkPackage;
|
|
72
103
|
if (options.framework) {
|
|
@@ -75,39 +106,62 @@ async function handleCreate(options) {
|
|
|
75
106
|
const available = FRAMEWORK_CATALOG.filter(f => f.installable).map(f => f.id).join(", ");
|
|
76
107
|
throw new Error(`Unknown framework '${options.framework}'. Available: ${available}`);
|
|
77
108
|
}
|
|
109
|
+
if (!compatibleFrameworks.some(f => f.id === requested.id)) {
|
|
110
|
+
const list = compatibleFrameworks.map(f => f.id).join(", ");
|
|
111
|
+
throw new Error(`Framework '${requested.id}' is not compatible with target '${target.id}' (${target.displayName}). ` +
|
|
112
|
+
`Compatible frameworks: ${list}`);
|
|
113
|
+
}
|
|
78
114
|
frameworkId = requested.id;
|
|
79
115
|
frameworkPackage = requested.packageName;
|
|
80
116
|
}
|
|
81
117
|
else {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
frameworkPackage = compatible[0].packageName;
|
|
118
|
+
if (compatibleFrameworks.length === 1) {
|
|
119
|
+
frameworkId = compatibleFrameworks[0].id;
|
|
120
|
+
frameworkPackage = compatibleFrameworks[0].packageName;
|
|
86
121
|
}
|
|
87
122
|
else {
|
|
88
|
-
const list =
|
|
123
|
+
const list = compatibleFrameworks.map(f => f.id).join(", ");
|
|
89
124
|
throw new Error(`Target '${target.id}' is compatible with multiple frameworks (${list}). ` +
|
|
90
125
|
`Pass --framework <id> to choose one.`);
|
|
91
126
|
}
|
|
92
127
|
}
|
|
128
|
+
// Probe methods (Zephyr boards whose packages ship a table). An explicit
|
|
129
|
+
// --probe id is validated against the catalog so a typo fails at create
|
|
130
|
+
// time, not at the first upload.
|
|
131
|
+
const probeMethods = frameworkId === 'zephyr' ? probeMethodsForBoard(target.id) : [];
|
|
132
|
+
if (options.probe && probeMethods.length > 0 && !probeMethods.some(m => m.id === options.probe)) {
|
|
133
|
+
const list = probeMethods.map(m => `${m.id} (${m.description})`).join('; ');
|
|
134
|
+
throw new Error(`Unknown probe method '${options.probe}' for ${target.displayName}. Supported: ${list}.`);
|
|
135
|
+
}
|
|
93
136
|
const projectName = options.projectName || 'my-project';
|
|
94
|
-
// Framework-specific build target + toolchain (Zephyr board id + 'west'
|
|
95
|
-
// the Arduino FQBN + 'arduino-cli').
|
|
137
|
+
// Framework-specific build target + toolchain (Zephyr board id + 'west').
|
|
96
138
|
const profile = frameworkTargetProfile(target, frameworkId);
|
|
139
|
+
const buildTarget = profile.buildTarget ?? target.buildTarget;
|
|
97
140
|
const result = scaffoldProject({
|
|
141
|
+
probeMethod: options.probe,
|
|
142
|
+
probeMethods,
|
|
98
143
|
projectName,
|
|
99
144
|
targetId: target.id,
|
|
100
145
|
targetDisplayName: target.displayName,
|
|
101
146
|
isNative: target.isNative,
|
|
102
147
|
architecture: target.architecture,
|
|
103
|
-
|
|
148
|
+
board: target.board,
|
|
149
|
+
// Pack fact: does the board's devicetree declare an LED? Drives the
|
|
150
|
+
// starter between LED-blink and console-heartbeat (384 of 1,248 pack
|
|
151
|
+
// boards ship no gpio-leds node).
|
|
152
|
+
...(target.board ? { hasLed: Boolean(activeBoardCatalog()[target.board]?.led) } : {}),
|
|
104
153
|
frameworkPackage,
|
|
105
154
|
framework: frameworkId,
|
|
106
|
-
buildTarget
|
|
155
|
+
buildTarget,
|
|
107
156
|
...(profile.toolchainType ? { toolchainType: profile.toolchainType } : {}),
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
157
|
+
// soc rides the config only for bare-silicon/contract projects — a
|
|
158
|
+
// board target's soc derives from the identifier at boardgen time.
|
|
159
|
+
...(target.board ? {} : { soc: target.soc }),
|
|
160
|
+
// Zephyr consoles default 115200; the 9600 default is the Arduino-class
|
|
161
|
+
// convention.
|
|
162
|
+
baudRate: target.isNative ? undefined : (options.baud ?? (frameworkId === 'zephyr' ? 115200 : 9600)),
|
|
163
|
+
includeStarter: !options.noStarter,
|
|
164
|
+
...(options.port ? { port: options.port } : {}),
|
|
111
165
|
...(target.frameworkData
|
|
112
166
|
? { frameworkData: target.frameworkData }
|
|
113
167
|
: {}),
|
|
@@ -115,12 +169,14 @@ async function handleCreate(options) {
|
|
|
115
169
|
finalizeCreate(result, options);
|
|
116
170
|
}
|
|
117
171
|
else {
|
|
118
|
-
const wizardResult = await
|
|
172
|
+
const wizardResult = await runCreateWizard({
|
|
119
173
|
projectName: options.projectName,
|
|
120
|
-
board: options.board,
|
|
174
|
+
board: options.board ?? options.target,
|
|
121
175
|
framework: options.framework,
|
|
122
176
|
baud: options.baud,
|
|
123
|
-
|
|
177
|
+
noStarter: options.noStarter,
|
|
178
|
+
probe: options.probe,
|
|
179
|
+
port: options.port,
|
|
124
180
|
});
|
|
125
181
|
if (!wizardResult) {
|
|
126
182
|
console.log(chalk.yellow("Project setup cancelled."));
|
|
@@ -170,23 +226,7 @@ function finalizeCreate(result, options) {
|
|
|
170
226
|
if (debugArtifacts.length > 0) {
|
|
171
227
|
console.log(`\n${chalk.green("✓")} Debug profile: ${debugArtifacts.map((f) => chalk.white(f)).join(", ")}`);
|
|
172
228
|
}
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
async function handleBoardAdd(options) {
|
|
176
|
-
const { scaffoldBoardPackages, parseBoardSpec, generateFrameworkChecklist } = await import("./create/index.js");
|
|
177
|
-
if (!fs.existsSync(options.specPath)) {
|
|
178
|
-
throw new Error(`Spec file not found: ${options.specPath}`);
|
|
179
|
-
}
|
|
180
|
-
console.log(`Reading spec: ${options.specPath}`);
|
|
181
|
-
const specText = fs.readFileSync(options.specPath, "utf8");
|
|
182
|
-
const spec = parseBoardSpec(specText);
|
|
183
|
-
console.log(`Generating board packages for ${spec.architecture} (${spec.boardName})...`);
|
|
184
|
-
const result = scaffoldBoardPackages(spec, { force: options.force });
|
|
185
|
-
console.log(`\nCreated ${result.createdFiles.length} files:`);
|
|
186
|
-
for (const f of result.createdFiles) {
|
|
187
|
-
console.log(` ${path.relative(process.cwd(), f)}`);
|
|
188
|
-
}
|
|
189
|
-
console.log(generateFrameworkChecklist(spec));
|
|
229
|
+
printCreateNextSteps(result.options, result.outDir, { installed, debugProfile: debugArtifacts.length > 0 });
|
|
190
230
|
}
|
|
191
231
|
async function main() {
|
|
192
232
|
try {
|
|
@@ -199,8 +239,8 @@ async function main() {
|
|
|
199
239
|
await handleCreate(options);
|
|
200
240
|
return;
|
|
201
241
|
}
|
|
202
|
-
if (options.command === "
|
|
203
|
-
await
|
|
242
|
+
if (options.command === "library") {
|
|
243
|
+
await runLibraryCommand(options);
|
|
204
244
|
return;
|
|
205
245
|
}
|
|
206
246
|
if (options.command === "preview") {
|
|
@@ -210,31 +250,6 @@ async function main() {
|
|
|
210
250
|
});
|
|
211
251
|
return;
|
|
212
252
|
}
|
|
213
|
-
if (options.command === "map-error") {
|
|
214
|
-
if (!options.mapFile || !options.cppLine || !options.cppColumn) {
|
|
215
|
-
throw new Error("map-error requires map file and C++ line/column options.");
|
|
216
|
-
}
|
|
217
|
-
const mapPath = resolveMapPath(options.mapFile);
|
|
218
|
-
const sourceMap = readSourceMap(mapPath);
|
|
219
|
-
const mapped = mapCppLocationToTs(sourceMap, options.cppLine, options.cppColumn, options.message, options.cppFile);
|
|
220
|
-
if (!mapped.mappedTsSpan) {
|
|
221
|
-
console.log("No TypeScript mapping found for the provided C++ location.");
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
console.log([
|
|
225
|
-
`Mapped TS location: ${mapped.mappedTsSpan.filePath}`,
|
|
226
|
-
`(${mapped.mappedTsSpan.startLine},${mapped.mappedTsSpan.startColumn})`,
|
|
227
|
-
`node=${mapped.nodeKind ?? "unknown"}`,
|
|
228
|
-
mapped.symbolName ? `symbol=${mapped.symbolName}` : undefined,
|
|
229
|
-
]
|
|
230
|
-
.filter(Boolean)
|
|
231
|
-
.join(" "));
|
|
232
|
-
}
|
|
233
|
-
if (mapped.message) {
|
|
234
|
-
console.log(`Compiler message: ${mapped.message}`);
|
|
235
|
-
}
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
253
|
if (options.command === "doctor" || options.command === "licenses") {
|
|
239
254
|
// These commands run standalone (often before a build), so the framework
|
|
240
255
|
// isn't loaded yet. Load it from the config's framework field so the
|
|
@@ -267,6 +282,74 @@ async function main() {
|
|
|
267
282
|
fw.licenses(options.strict ?? false, options.all ?? false);
|
|
268
283
|
return;
|
|
269
284
|
}
|
|
285
|
+
// ── Handle board catalog sync / board module regen ────────────────────
|
|
286
|
+
if (options.command === "board") {
|
|
287
|
+
const config = loadCuttlefishConfig(process.cwd());
|
|
288
|
+
if (!config) {
|
|
289
|
+
throw new Error("No cuttlefish.config.ts found in current directory.\n" +
|
|
290
|
+
"Run 'cuttlefish create' to create one.");
|
|
291
|
+
}
|
|
292
|
+
// The framework owns the board catalog + module generation; load it
|
|
293
|
+
// the same way the doctor command does.
|
|
294
|
+
if (!hasLoadedFramework() && config.framework) {
|
|
295
|
+
try {
|
|
296
|
+
loadFrameworkPackage(config.framework, process.cwd());
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// Framework package not resolvable — the hook error below names
|
|
300
|
+
// the problem better than a loader crash would.
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const strategy = hasLoadedFramework()
|
|
304
|
+
? getLoadedFramework().strategy
|
|
305
|
+
: undefined;
|
|
306
|
+
if (options.subcommand === "sync") {
|
|
307
|
+
if (typeof strategy?.syncBoardCatalog !== "function") {
|
|
308
|
+
throw new Error(`Framework '${config.framework ?? "(none)"}' provides no board catalog sync — ` +
|
|
309
|
+
`'cuttlefish board sync' applies to Zephyr-framework projects.`);
|
|
310
|
+
}
|
|
311
|
+
const report = strategy.syncBoardCatalog(options.zephyrBase);
|
|
312
|
+
const version = report.provenance.version || "unknown version";
|
|
313
|
+
const head = report.provenance.gitHead ? ` @ ${report.provenance.gitHead.slice(0, 12)}` : "";
|
|
314
|
+
const fp = sdkFingerprint(report.zephyrBase);
|
|
315
|
+
ui.printSuccess(`Board catalog synced from Zephyr ${version}${head}`);
|
|
316
|
+
console.log(chalk.gray(` tree: ${report.zephyrBase}`));
|
|
317
|
+
if (fp)
|
|
318
|
+
console.log(chalk.gray(` fingerprint: ${fp} (pin ${PINNED_ZEPHYR_MANIFEST_REV})`));
|
|
319
|
+
console.log(chalk.gray(` catalog: ${report.overlayPath}`));
|
|
320
|
+
console.log(` ${report.stats.variants} board variants (${report.stats.withFacts} with pin facts` +
|
|
321
|
+
`${report.stats.failures > 0 ? `, ${report.stats.failures} reader failures` : ""}` +
|
|
322
|
+
`${report.stats.droppedYamls > 0 ? `, ${report.stats.droppedYamls} yamls with no resolvable .dts` : ""})`);
|
|
323
|
+
const { added, changed, removed } = report;
|
|
324
|
+
const list = (ids, verb) => ids.length === 0
|
|
325
|
+
? chalk.gray(` 0 ${verb}`)
|
|
326
|
+
: ` ${ids.length} ${verb}: ${ids.slice(0, 8).join(", ")}${ids.length > 8 ? ", …" : ""}`;
|
|
327
|
+
console.log(chalk.gray(" vs the previous catalog (what changed in your tree):"));
|
|
328
|
+
console.log(list(added, "added"));
|
|
329
|
+
console.log(list(changed, "changed"));
|
|
330
|
+
console.log(list(removed, "removed"));
|
|
331
|
+
// Refresh the project's own board module so the sync lands in this
|
|
332
|
+
// project immediately (not just on the next first-build).
|
|
333
|
+
if (config.board && !config.contract) {
|
|
334
|
+
const dir = regenBoardModule(config);
|
|
335
|
+
ui.printSuccess(`Regenerated the board module for '${config.board}' in ${path.join(dir, "board.ts")}`);
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// regen: refresh a stale catalog overlay first, so a regen after
|
|
340
|
+
// `west update` picks up the tree's boards automatically. Best-effort
|
|
341
|
+
// — a missing tree or a failed walk must not block regenerating from
|
|
342
|
+
// whatever catalog is already present.
|
|
343
|
+
try {
|
|
344
|
+
strategy?.ensureFreshBoardCatalog?.();
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// Non-fatal by design (see above).
|
|
348
|
+
}
|
|
349
|
+
const dir = regenBoardModule(config);
|
|
350
|
+
ui.printSuccess(`Regenerated the board module for '${config.board}' in ${path.join(dir, "board.ts")}`);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
270
353
|
// ── Handle build command — entry point comes from config ──────────
|
|
271
354
|
if (options.command === "build") {
|
|
272
355
|
const buildConfig = loadCuttlefishConfig(process.cwd());
|
|
@@ -276,7 +359,7 @@ async function main() {
|
|
|
276
359
|
}
|
|
277
360
|
if (!buildConfig.entry) {
|
|
278
361
|
throw new Error("cuttlefish.config.ts has no 'entry' field.\n" +
|
|
279
|
-
"Add: entry: './src/
|
|
362
|
+
"Add: entry: './src/main.ts'");
|
|
280
363
|
}
|
|
281
364
|
const entryFile = path.resolve(path.dirname(buildConfig.configPath), buildConfig.entry);
|
|
282
365
|
if (!fs.existsSync(entryFile)) {
|
|
@@ -297,37 +380,6 @@ async function main() {
|
|
|
297
380
|
// it intentionally has no inputFile (it scans scanDir instead), so the
|
|
298
381
|
// generic "Missing input file path" check would otherwise block it.
|
|
299
382
|
if (options.command === "gen-decls") {
|
|
300
|
-
// Check for --components flag (ESP-IDF components: managed + local).
|
|
301
|
-
// Runs before scanDir/single-file branches; components mode has no
|
|
302
|
-
// inputFile by design (it scans managed_components/ + components/).
|
|
303
|
-
const componentsDir = options.componentsDir;
|
|
304
|
-
if (componentsDir) {
|
|
305
|
-
ui.printHeader();
|
|
306
|
-
ui.printStep(`Generating component declarations for ${componentsDir}...`);
|
|
307
|
-
const config = loadCuttlefishConfig(componentsDir);
|
|
308
|
-
const frameworkConfig = (config?.frameworkConfig ?? {});
|
|
309
|
-
const componentsNode = frameworkConfig?.components ?? {};
|
|
310
|
-
const managedSpecs = Object.keys(componentsNode.managed ?? {});
|
|
311
|
-
// idf.py stores managed deps as <namespace>__<name> (slashes → __).
|
|
312
|
-
const managedNames = managedSpecs.map((spec) => spec.replace("/", "__"));
|
|
313
|
-
const localPaths = (componentsNode.local ?? []).map((p) => path.isAbsolute(p) ? p : path.resolve(componentsDir, p));
|
|
314
|
-
const builtinNames = componentsNode.builtin ?? [];
|
|
315
|
-
const created = generateComponentDeclsForProject(componentsDir, {
|
|
316
|
-
managed: managedNames,
|
|
317
|
-
local: localPaths,
|
|
318
|
-
builtin: [],
|
|
319
|
-
idfRoot: undefined,
|
|
320
|
-
});
|
|
321
|
-
if (created.length === 0) {
|
|
322
|
-
ui.printInfo("No component declaration files created.");
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
ui.printSuccess(`Created ${created.length} declaration file(s):`);
|
|
326
|
-
for (const f of created)
|
|
327
|
-
ui.printFileCreated(f);
|
|
328
|
-
}
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
383
|
// Check for --all flag (scan directory)
|
|
332
384
|
const scanDir = options.scanDir;
|
|
333
385
|
if (scanDir) {
|
|
@@ -368,9 +420,9 @@ async function main() {
|
|
|
368
420
|
if (options.expect) {
|
|
369
421
|
const config = loadCuttlefishConfig(process.cwd());
|
|
370
422
|
const exitCode = runExpectTests({
|
|
371
|
-
port: options.port
|
|
423
|
+
port: options.port,
|
|
372
424
|
buildTarget: config?.buildTarget,
|
|
373
|
-
baud:
|
|
425
|
+
baud: options.baud,
|
|
374
426
|
expectFile: options.expectFile,
|
|
375
427
|
});
|
|
376
428
|
process.exitCode = exitCode;
|
|
@@ -379,23 +431,6 @@ async function main() {
|
|
|
379
431
|
throw new Error("Missing input file path.");
|
|
380
432
|
}
|
|
381
433
|
assertTypeScriptInput(options.inputFile);
|
|
382
|
-
if (options.command === "gen-libdefs") {
|
|
383
|
-
const outDir = path.dirname(options.inputFile);
|
|
384
|
-
const created = generateLibraryDefinitions({
|
|
385
|
-
inputFile: options.inputFile,
|
|
386
|
-
outDir,
|
|
387
|
-
});
|
|
388
|
-
if (created.length === 0) {
|
|
389
|
-
console.log("No new library definition files created.");
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
console.log("Created library definition files:");
|
|
393
|
-
for (const filePath of created) {
|
|
394
|
-
console.log(`- ${filePath}`);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
434
|
// ── Load cuttlefish.config.ts (config wins over CLI flags) ──────────
|
|
400
435
|
const inputDir = path.dirname(path.resolve(options.inputFile));
|
|
401
436
|
const config = loadCuttlefishConfig(inputDir);
|
|
@@ -408,42 +443,6 @@ async function main() {
|
|
|
408
443
|
if (config?.contract) {
|
|
409
444
|
await generateContractBoard(config);
|
|
410
445
|
}
|
|
411
|
-
// ── Pre-transpile: generate component .d.ts stubs ───────────────────
|
|
412
|
-
// The transpile type-check needs the .d.ts imports in main.ts to resolve.
|
|
413
|
-
// For ESP-IDF builtin/managed/local components, those .d.ts files are
|
|
414
|
-
// generated by gen-decls — so we must run it BEFORE type-checking, not
|
|
415
|
-
// only as part of --compile. The cache is written under the transpile
|
|
416
|
-
// output dir (the same path --compile uses), so user imports resolve
|
|
417
|
-
// identically in both flows.
|
|
418
|
-
if (config?.frameworkConfig) {
|
|
419
|
-
const fc = config.frameworkConfig;
|
|
420
|
-
const componentsNode = fc?.components ?? {};
|
|
421
|
-
const managedSpecs = Object.keys(componentsNode.managed ?? {});
|
|
422
|
-
const localPaths = (componentsNode.local ?? []).map((p) => path.isAbsolute(p) ? p : path.resolve(inputDir, p));
|
|
423
|
-
const builtinNames = componentsNode.builtin ?? [];
|
|
424
|
-
if (managedSpecs.length > 0 || localPaths.length > 0 || builtinNames.length > 0) {
|
|
425
|
-
// Resolve the transpile output dir — the cache lives under it so the
|
|
426
|
-
// framework's compile path and this pre-transpile pass agree on location.
|
|
427
|
-
// output.outDir in config is relative to the project root (inputDir);
|
|
428
|
-
// if absent, the transpile output goes alongside the entry file.
|
|
429
|
-
const outBase = config.outputOutDir
|
|
430
|
-
? path.resolve(inputDir, config.outputOutDir)
|
|
431
|
-
: inputDir;
|
|
432
|
-
try {
|
|
433
|
-
generateComponentDeclsForProject(outBase, {
|
|
434
|
-
managed: managedSpecs.map((s) => s.replace('/', '__')),
|
|
435
|
-
local: localPaths,
|
|
436
|
-
builtin: [],
|
|
437
|
-
idfRoot: undefined,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
// Non-fatal: if gen-decls fails (e.g. component not yet fetched),
|
|
442
|
-
// the type-checker will surface the missing-import errors with
|
|
443
|
-
// clearer context than crashing here.
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
446
|
// Load the UI engine (if @typecad/ui is installed) before any UI work.
|
|
448
447
|
await loadUIEngine();
|
|
449
448
|
// Load the safety engine (if @typecad/safety is installed) before any
|
|
@@ -452,9 +451,8 @@ async function main() {
|
|
|
452
451
|
let effectivePlatformContext = options.platformContext;
|
|
453
452
|
let effectiveTarget = options.target;
|
|
454
453
|
let effectiveOutDir = options.outDir;
|
|
455
|
-
let
|
|
454
|
+
let effectiveBoardTarget = options.boardTarget;
|
|
456
455
|
let effectiveFrameworkPackage = options.frameworkPackage;
|
|
457
|
-
let effectiveMcuPackage;
|
|
458
456
|
let effectivePort = options.port;
|
|
459
457
|
// CUTTLEFISH_PORT env var sits between the CLI flag and the config file
|
|
460
458
|
// (flag > env > config), so cross-platform uploads don't need a
|
|
@@ -463,15 +461,8 @@ async function main() {
|
|
|
463
461
|
effectivePort = process.env.CUTTLEFISH_PORT;
|
|
464
462
|
}
|
|
465
463
|
if (config) {
|
|
466
|
-
if (config.
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
// Config port is the default; CLI --port flag overrides it.
|
|
470
|
-
if (!effectivePort && config.console?.port) {
|
|
471
|
-
effectivePort = config.console.port;
|
|
472
|
-
}
|
|
473
|
-
if (config.board || config.mcu) {
|
|
474
|
-
effectiveBoardPackage = config.board || config.mcu;
|
|
464
|
+
if (config.board) {
|
|
465
|
+
effectiveBoardTarget = config.board;
|
|
475
466
|
}
|
|
476
467
|
let configBuildTarget = config.buildTarget;
|
|
477
468
|
if (configBuildTarget) {
|
|
@@ -482,7 +473,7 @@ async function main() {
|
|
|
482
473
|
frameworkData: {
|
|
483
474
|
buildTarget: configBuildTarget,
|
|
484
475
|
// Thread the PSRAM type through to the framework so it can emit the
|
|
485
|
-
// PSRAM-enabling Kconfig
|
|
476
|
+
// PSRAM-enabling Kconfig + BOARD_HAS_PSRAM compile definition.
|
|
486
477
|
...(config.psram ? { psram: config.psram } : {}),
|
|
487
478
|
},
|
|
488
479
|
};
|
|
@@ -493,24 +484,6 @@ async function main() {
|
|
|
493
484
|
if (config.framework) {
|
|
494
485
|
effectiveFrameworkPackage = config.framework;
|
|
495
486
|
}
|
|
496
|
-
if (config.target) {
|
|
497
|
-
if (effectiveFrameworkPackage) {
|
|
498
|
-
try {
|
|
499
|
-
loadFrameworkPackage(effectiveFrameworkPackage, inputDir);
|
|
500
|
-
if (hasLoadedFramework()) {
|
|
501
|
-
effectiveTarget = getLoadedFramework().strategy.id;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
catch {
|
|
505
|
-
// Framework not loadable — keep the CLI-provided target
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
// Pass console baud rate to platform context
|
|
510
|
-
if (config.console?.baudRate) {
|
|
511
|
-
effectivePlatformContext = effectivePlatformContext || {};
|
|
512
|
-
effectivePlatformContext.console = { baudRate: config.console.baudRate };
|
|
513
|
-
}
|
|
514
487
|
// Keep cuttlefish-env.d.ts in sync so the TS language server can resolve
|
|
515
488
|
// '@typecad/board' imports in editor without a linter error.
|
|
516
489
|
// Platform-specific declarations come from the strategy if available.
|
|
@@ -536,8 +509,7 @@ async function main() {
|
|
|
536
509
|
ui.printHeader();
|
|
537
510
|
ui.printBuildInfo({
|
|
538
511
|
framework: effectiveFrameworkPackage,
|
|
539
|
-
|
|
540
|
-
board: effectiveBoardPackage,
|
|
512
|
+
board: effectiveBoardTarget,
|
|
541
513
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget,
|
|
542
514
|
});
|
|
543
515
|
// ── Watch mode ────────────────────────────────────────────────────────
|
|
@@ -555,7 +527,7 @@ async function main() {
|
|
|
555
527
|
emitMaps: options.emitMaps,
|
|
556
528
|
platformContext: effectivePlatformContext,
|
|
557
529
|
treeShaking: options.treeShaking,
|
|
558
|
-
|
|
530
|
+
boardTarget: effectiveBoardTarget,
|
|
559
531
|
frameworkPackage: effectiveFrameworkPackage,
|
|
560
532
|
debug: options.debug,
|
|
561
533
|
force: options.force,
|
|
@@ -577,28 +549,29 @@ async function main() {
|
|
|
577
549
|
// Initial compile + upload if flags are set
|
|
578
550
|
if (options.compile) {
|
|
579
551
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
580
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
581
552
|
const watchOpts = {
|
|
582
553
|
outputDir: path.dirname(result.sourcePath),
|
|
583
554
|
sourcePath: result.sourcePath,
|
|
584
|
-
buildTarget,
|
|
555
|
+
buildTarget: baseBuildTarget,
|
|
585
556
|
port: effectivePort,
|
|
586
|
-
baud: options.baud
|
|
557
|
+
baud: options.baud,
|
|
587
558
|
extraFlags: config?.outputExtraFlags,
|
|
588
|
-
defines:
|
|
559
|
+
defines: config?.outputDefines ?? {},
|
|
589
560
|
psram: config?.psram,
|
|
590
561
|
frameworkConfig: config?.frameworkConfig,
|
|
591
562
|
zephyrConfig: config?.zephyrConfig,
|
|
592
563
|
display: displayConfigForTranspile(config),
|
|
593
564
|
debug: options.debug,
|
|
594
565
|
};
|
|
595
|
-
ui.printCompiling(
|
|
566
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
596
567
|
const compileResult = compileSource(watchOpts);
|
|
597
568
|
printMappedCompileErrors(compileResult, result.sourceMapPath, result.sourcePath, path.dirname(result.sourcePath));
|
|
598
569
|
if (compileResult.success) {
|
|
599
570
|
if (compileResult.memoryUsage)
|
|
600
571
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
601
|
-
if (options.upload
|
|
572
|
+
if (options.upload) {
|
|
573
|
+
// No port gate here — probe/USB flashing needs none, and the
|
|
574
|
+
// framework reports a friendly failure when the runner does.
|
|
602
575
|
ui.printUploading(effectivePort);
|
|
603
576
|
const uploadResult = uploadFirmware(watchOpts);
|
|
604
577
|
if (uploadResult.output)
|
|
@@ -633,7 +606,7 @@ async function main() {
|
|
|
633
606
|
process.stdout.write("\x1Bc");
|
|
634
607
|
const timestamp = new Date().toLocaleTimeString();
|
|
635
608
|
const relativePath = path.relative(process.cwd(), changedFile);
|
|
636
|
-
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(`
|
|
609
|
+
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(` v${ui.VERSION}`));
|
|
637
610
|
console.log();
|
|
638
611
|
ui.printInfo(`[${timestamp}] Change detected: ${relativePath}`);
|
|
639
612
|
console.log();
|
|
@@ -654,7 +627,7 @@ async function main() {
|
|
|
654
627
|
emitMaps: options.emitMaps,
|
|
655
628
|
platformContext: effectivePlatformContext,
|
|
656
629
|
treeShaking: options.treeShaking,
|
|
657
|
-
|
|
630
|
+
boardTarget: effectiveBoardTarget,
|
|
658
631
|
frameworkPackage: effectiveFrameworkPackage,
|
|
659
632
|
debug: options.debug,
|
|
660
633
|
force: true, // Always force in watch mode to bypass stale cache
|
|
@@ -677,28 +650,30 @@ async function main() {
|
|
|
677
650
|
ui.printSuccess();
|
|
678
651
|
if (options.compile) {
|
|
679
652
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
680
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
681
653
|
const rebuildOpts = {
|
|
682
654
|
outputDir: path.dirname(rebuildResult.sourcePath),
|
|
683
655
|
sourcePath: rebuildResult.sourcePath,
|
|
684
|
-
buildTarget,
|
|
656
|
+
buildTarget: baseBuildTarget,
|
|
685
657
|
port: effectivePort,
|
|
686
|
-
baud: options.baud
|
|
658
|
+
baud: options.baud,
|
|
687
659
|
extraFlags: config?.outputExtraFlags,
|
|
688
|
-
defines:
|
|
660
|
+
defines: config?.outputDefines ?? {},
|
|
689
661
|
psram: config?.psram,
|
|
690
662
|
frameworkConfig: config?.frameworkConfig,
|
|
691
663
|
zephyrConfig: config?.zephyrConfig,
|
|
692
664
|
display: displayConfigForTranspile(config),
|
|
693
665
|
debug: options.debug,
|
|
694
666
|
};
|
|
695
|
-
ui.printCompiling(
|
|
667
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
696
668
|
const compileResult = compileSource(rebuildOpts);
|
|
697
669
|
printMappedCompileErrors(compileResult, rebuildResult.sourceMapPath, rebuildResult.sourcePath, path.dirname(rebuildResult.sourcePath));
|
|
698
670
|
if (compileResult.success) {
|
|
699
671
|
if (compileResult.memoryUsage)
|
|
700
672
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
701
|
-
if (options.upload
|
|
673
|
+
if (options.upload) {
|
|
674
|
+
// No port gate here — probe/USB flashing needs none, and
|
|
675
|
+
// the framework reports a friendly failure when the
|
|
676
|
+
// runner does.
|
|
702
677
|
ui.printUploading(effectivePort);
|
|
703
678
|
const uploadResult = uploadFirmware(rebuildOpts);
|
|
704
679
|
if (uploadResult.output)
|
|
@@ -747,7 +722,7 @@ async function main() {
|
|
|
747
722
|
emitMaps: options.emitMaps,
|
|
748
723
|
platformContext: effectivePlatformContext,
|
|
749
724
|
treeShaking: options.treeShaking,
|
|
750
|
-
|
|
725
|
+
boardTarget: effectiveBoardTarget,
|
|
751
726
|
frameworkPackage: effectiveFrameworkPackage,
|
|
752
727
|
debug: options.debug,
|
|
753
728
|
force: options.force,
|
|
@@ -775,7 +750,7 @@ async function main() {
|
|
|
775
750
|
const exitCode = runExpectTests({
|
|
776
751
|
port: effectivePort,
|
|
777
752
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget,
|
|
778
|
-
baud:
|
|
753
|
+
baud: options.baud,
|
|
779
754
|
expectFile: options.expectFile,
|
|
780
755
|
});
|
|
781
756
|
process.exitCode = exitCode;
|
|
@@ -784,22 +759,24 @@ async function main() {
|
|
|
784
759
|
}
|
|
785
760
|
// --compile (delegates to the active framework's toolchain)
|
|
786
761
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
787
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
788
762
|
const toolchainOpts = {
|
|
789
763
|
outputDir: path.dirname(result.sourcePath),
|
|
790
764
|
sourcePath: result.sourcePath,
|
|
791
|
-
buildTarget,
|
|
765
|
+
buildTarget: baseBuildTarget,
|
|
792
766
|
port: effectivePort,
|
|
793
|
-
baud: options.baud
|
|
767
|
+
baud: options.baud,
|
|
794
768
|
extraFlags: config?.outputExtraFlags,
|
|
795
|
-
defines:
|
|
769
|
+
defines: config?.outputDefines ?? {},
|
|
796
770
|
psram: config?.psram,
|
|
797
771
|
frameworkConfig: config?.frameworkConfig,
|
|
798
|
-
|
|
772
|
+
// --probe <method> overrides zephyr.probe from the config for this run.
|
|
773
|
+
zephyrConfig: options.probe
|
|
774
|
+
? { ...(config?.zephyrConfig ?? {}), probe: options.probe }
|
|
775
|
+
: config?.zephyrConfig,
|
|
799
776
|
display: displayConfigForTranspile(config),
|
|
800
777
|
debug: options.debug,
|
|
801
778
|
};
|
|
802
|
-
ui.printCompiling(
|
|
779
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
803
780
|
let compileResult;
|
|
804
781
|
try {
|
|
805
782
|
compileResult = compileSource(toolchainOpts);
|
|
@@ -829,10 +806,11 @@ async function main() {
|
|
|
829
806
|
ui.printSuccess();
|
|
830
807
|
return;
|
|
831
808
|
}
|
|
832
|
-
// --upload
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
809
|
+
// --upload. Whether a port is required is the active framework's call —
|
|
810
|
+
// probe-based flashing (openocd/jlink) and USB bootloaders (dfu-util,
|
|
811
|
+
// uf2) need no serial port, so a missing --port only surfaces as the
|
|
812
|
+
// framework's own upload failure for serial-port runners (esptool,
|
|
813
|
+
// bossac).
|
|
836
814
|
const port = effectivePort;
|
|
837
815
|
ui.printUploading(port);
|
|
838
816
|
const uploadResult = uploadFirmware(toolchainOpts);
|
|
@@ -848,9 +826,14 @@ async function main() {
|
|
|
848
826
|
return;
|
|
849
827
|
}
|
|
850
828
|
if (options.monitor) {
|
|
851
|
-
// --monitor (blocks until Ctrl+C).
|
|
852
|
-
//
|
|
853
|
-
|
|
829
|
+
// --monitor (blocks until Ctrl+C). Unlike flashing, monitoring always
|
|
830
|
+
// needs a serial port — there is no probe/USB flavor of it.
|
|
831
|
+
if (!port) {
|
|
832
|
+
throw new Error("--monitor requires a port. Set --port <port> on the command line (or the CUTTLEFISH_PORT env var).");
|
|
833
|
+
}
|
|
834
|
+
// Show the resolved --baud in the banner — toolchainOpts.baud is built
|
|
835
|
+
// the same way, so what the user sees is what the framework monitor
|
|
836
|
+
// opens the port at.
|
|
854
837
|
ui.printMonitoring(port, toolchainOpts.baud ?? 115200);
|
|
855
838
|
monitorDevice(toolchainOpts);
|
|
856
839
|
return;
|
|
@@ -860,8 +843,8 @@ async function main() {
|
|
|
860
843
|
ui.printSuccess();
|
|
861
844
|
const exitCode = runExpectTests({
|
|
862
845
|
port: effectivePort,
|
|
863
|
-
buildTarget,
|
|
864
|
-
baud:
|
|
846
|
+
buildTarget: baseBuildTarget,
|
|
847
|
+
baud: options.baud,
|
|
865
848
|
expectFile: options.expectFile,
|
|
866
849
|
});
|
|
867
850
|
process.exitCode = exitCode;
|