@typecad/cuttlefish 1.0.0-alpha.14 → 1.0.0-alpha.16
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 +25 -26
- package/dist/api/config.d.ts +22 -26
- 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 +7 -6
- 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 +219 -242
- package/dist/config-loader.d.ts +14 -19
- package/dist/config-loader.js +240 -78
- package/dist/config-schema.d.ts +3 -5
- package/dist/config-schema.js +8 -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 +27 -0
- 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 +4 -2
- package/dist/create/editor-integration.js +41 -2
- package/dist/create/framework-catalog.d.ts +57 -9
- package/dist/create/framework-catalog.js +76 -57
- package/dist/create/index.d.ts +5 -11
- package/dist/create/index.js +3 -8
- 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/scaffold.d.ts +4 -7
- package/dist/create/scaffold.js +19 -109
- package/dist/create/templates.d.ts +32 -5
- package/dist/create/templates.js +130 -116
- package/dist/create/wizard.d.ts +12 -1
- package/dist/create/wizard.js +168 -38
- 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 +125 -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 +40 -42
- 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/init.d.ts +1 -1
- package/dist/library/init.js +137 -137
- package/dist/library-packages.d.ts +1 -1
- package/dist/library-packages.js +1 -1
- 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 +13 -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/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 +4 -5
- 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 +36 -30
- package/dist/types.d.ts +26 -26
- package/dist/ui-hook.d.ts +1 -1
- package/dist/utils/cli.d.ts +2 -2
- package/dist/utils/cli.js +92 -154
- 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 -157
- 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 -181
- package/dist/create/board-spec.js +0 -214
- 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
|
@@ -3,18 +3,19 @@ import path from "node:path";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { parseCommandLine, printHelp } from "./utils/cli.js";
|
|
5
5
|
import { runLibraryCommand } from "./library/cli.js";
|
|
6
|
-
import { scaffoldProject, printCreateNextSteps, KNOWN_TARGETS, frameworksForTarget, frameworkCatalogEntry,
|
|
6
|
+
import { scaffoldProject, printCreateNextSteps, KNOWN_TARGETS, frameworksForTarget, frameworkCatalogEntry, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard, probeRunnerQuirks } 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";
|
|
7
9
|
import { generateFrameworkDebugArtifacts } from "./create/debug-artifacts.js";
|
|
8
10
|
import { runCreateWizard } from "./create/index.js";
|
|
9
11
|
import { installProjectDependencies } from "./create/install-deps.js";
|
|
10
|
-
import {
|
|
11
|
-
import { generateDecl, generateDeclsForDirectory
|
|
12
|
-
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";
|
|
13
14
|
import { compileSource, uploadFirmware, monitorDevice } from "./platform/toolchain.js";
|
|
14
15
|
import { resolveStrategy } from "./platform/registry.js";
|
|
15
16
|
import { loadFrameworkPackage } from "./framework-package.js";
|
|
16
17
|
import { getLoadedFramework, hasLoadedFramework } from "./framework-registry.js";
|
|
17
|
-
import { loadCuttlefishConfig, generateVirtualTypeDeclaration } from "./config-loader.js";
|
|
18
|
+
import { loadCuttlefishConfig, generateVirtualTypeDeclaration, regenBoardModule } from "./config-loader.js";
|
|
18
19
|
import { generateContractBoard } from "./contract/index.js";
|
|
19
20
|
import { requireUIHook, hasUIHook } from "./ui-hook.js";
|
|
20
21
|
import { loadUIEngine } from "./ui/ui-bridge.js";
|
|
@@ -36,36 +37,64 @@ function displayConfigForTranspile(config) {
|
|
|
36
37
|
}
|
|
37
38
|
return display;
|
|
38
39
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Apply the PSRAM config to the Arduino build: append the `PSRAM={opi|quad}`
|
|
41
|
-
* menu option to the FQBN (so the Arduino core's psramFound()/ps_malloc work
|
|
42
|
-
* at runtime — they're gated on the board menu option, not just the define)
|
|
43
|
-
* and add `-DBOARD_HAS_PSRAM` to the defines (so the framework's PSRAM canvas
|
|
44
|
-
* allocator is compiled in). No-op when psram is unset or the target isn't an
|
|
45
|
-
* Arduino FQBN (the PSRAM= option is Arduino-core-specific).
|
|
46
|
-
*/
|
|
47
|
-
function applyPsramToArduinoBuild(buildTarget, defines, psram) {
|
|
48
|
-
if (!psram || !buildTarget || !buildTarget.includes(':')) {
|
|
49
|
-
return { buildTarget, defines: defines ?? {} };
|
|
50
|
-
}
|
|
51
|
-
// Arduino FQBN config options follow the board:option as `key=value` pairs.
|
|
52
|
-
// Append PSRAM= if not already present (don't clobber an explicit override).
|
|
53
|
-
const psramOpt = `PSRAM=${psram}`;
|
|
54
|
-
const adjustedTarget = buildTarget.includes('PSRAM=') ? buildTarget : `${buildTarget}:${psramOpt}`;
|
|
55
|
-
const adjustedDefines = { ...(defines ?? {}) };
|
|
56
|
-
if (!('BOARD_HAS_PSRAM' in adjustedDefines))
|
|
57
|
-
adjustedDefines.BOARD_HAS_PSRAM = '';
|
|
58
|
-
return { buildTarget: adjustedTarget, defines: adjustedDefines };
|
|
59
|
-
}
|
|
60
40
|
async function handleCreate(options) {
|
|
61
41
|
const targetId = options.target ?? options.board;
|
|
62
42
|
const hasTarget = !!targetId;
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
})();
|
|
65
77
|
if (!target) {
|
|
66
|
-
|
|
67
|
-
|
|
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
|
+
}
|
|
68
95
|
}
|
|
96
|
+
const compatibleFrameworks = frameworksForTarget(target)
|
|
97
|
+
.filter(f => f.installable);
|
|
69
98
|
// Resolve the framework. --framework wins (validated against the board's
|
|
70
99
|
// compatible set); otherwise narrow via the catalog for the chosen board
|
|
71
100
|
// and auto-pick when exactly one is compatible.
|
|
@@ -77,8 +106,8 @@ async function handleCreate(options) {
|
|
|
77
106
|
const available = FRAMEWORK_CATALOG.filter(f => f.installable).map(f => f.id).join(", ");
|
|
78
107
|
throw new Error(`Unknown framework '${options.framework}'. Available: ${available}`);
|
|
79
108
|
}
|
|
80
|
-
if (!
|
|
81
|
-
const list =
|
|
109
|
+
if (!compatibleFrameworks.some(f => f.id === requested.id)) {
|
|
110
|
+
const list = compatibleFrameworks.map(f => f.id).join(", ");
|
|
82
111
|
throw new Error(`Framework '${requested.id}' is not compatible with target '${target.id}' (${target.displayName}). ` +
|
|
83
112
|
`Compatible frameworks: ${list}`);
|
|
84
113
|
}
|
|
@@ -86,35 +115,58 @@ async function handleCreate(options) {
|
|
|
86
115
|
frameworkPackage = requested.packageName;
|
|
87
116
|
}
|
|
88
117
|
else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
frameworkPackage = compatible[0].packageName;
|
|
118
|
+
if (compatibleFrameworks.length === 1) {
|
|
119
|
+
frameworkId = compatibleFrameworks[0].id;
|
|
120
|
+
frameworkPackage = compatibleFrameworks[0].packageName;
|
|
93
121
|
}
|
|
94
122
|
else {
|
|
95
|
-
const list =
|
|
123
|
+
const list = compatibleFrameworks.map(f => f.id).join(", ");
|
|
96
124
|
throw new Error(`Target '${target.id}' is compatible with multiple frameworks (${list}). ` +
|
|
97
125
|
`Pass --framework <id> to choose one.`);
|
|
98
126
|
}
|
|
99
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
|
+
}
|
|
100
136
|
const projectName = options.projectName || 'my-project';
|
|
101
|
-
//
|
|
102
|
-
//
|
|
137
|
+
// Board-catalog quirk for the chosen probe method (e.g. an srst-based
|
|
138
|
+
// openocd.cfg behind a debug header with no NRST) — baked into the
|
|
139
|
+
// scaffolded config's runnerArgs so the first flash works.
|
|
140
|
+
const probeRunnerArgs = options.probe && frameworkId === 'zephyr' ? probeRunnerQuirks(target.id, options.probe) : [];
|
|
141
|
+
// Framework-specific build target + toolchain (Zephyr board id + 'west').
|
|
103
142
|
const profile = frameworkTargetProfile(target, frameworkId);
|
|
143
|
+
const buildTarget = profile.buildTarget ?? target.buildTarget;
|
|
104
144
|
const result = scaffoldProject({
|
|
145
|
+
probeMethod: options.probe,
|
|
146
|
+
probeMethods,
|
|
147
|
+
...(probeRunnerArgs.length > 0 ? { probeRunnerArgs } : {}),
|
|
105
148
|
projectName,
|
|
106
149
|
targetId: target.id,
|
|
107
150
|
targetDisplayName: target.displayName,
|
|
108
151
|
isNative: target.isNative,
|
|
109
152
|
architecture: target.architecture,
|
|
110
|
-
|
|
153
|
+
board: target.board,
|
|
154
|
+
// Pack fact: does the board's devicetree declare an LED? Drives the
|
|
155
|
+
// starter between LED-blink and console-heartbeat (384 of 1,248 pack
|
|
156
|
+
// boards ship no gpio-leds node).
|
|
157
|
+
...(target.board ? { hasLed: Boolean(activeBoardCatalog()[target.board]?.led) } : {}),
|
|
111
158
|
frameworkPackage,
|
|
112
159
|
framework: frameworkId,
|
|
113
|
-
buildTarget
|
|
160
|
+
buildTarget,
|
|
114
161
|
...(profile.toolchainType ? { toolchainType: profile.toolchainType } : {}),
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
162
|
+
// soc rides the config only for bare-silicon/contract projects — a
|
|
163
|
+
// board target's soc derives from the identifier at boardgen time.
|
|
164
|
+
...(target.board ? {} : { soc: target.soc }),
|
|
165
|
+
// Zephyr consoles default 115200; the 9600 default is the Arduino-class
|
|
166
|
+
// convention.
|
|
167
|
+
baudRate: target.isNative ? undefined : (options.baud ?? (frameworkId === 'zephyr' ? 115200 : 9600)),
|
|
168
|
+
includeStarter: !options.noStarter,
|
|
169
|
+
...(options.port ? { port: options.port } : {}),
|
|
118
170
|
...(target.frameworkData
|
|
119
171
|
? { frameworkData: target.frameworkData }
|
|
120
172
|
: {}),
|
|
@@ -124,10 +176,12 @@ async function handleCreate(options) {
|
|
|
124
176
|
else {
|
|
125
177
|
const wizardResult = await runCreateWizard({
|
|
126
178
|
projectName: options.projectName,
|
|
127
|
-
board: options.board,
|
|
179
|
+
board: options.board ?? options.target,
|
|
128
180
|
framework: options.framework,
|
|
129
181
|
baud: options.baud,
|
|
130
|
-
|
|
182
|
+
noStarter: options.noStarter,
|
|
183
|
+
probe: options.probe,
|
|
184
|
+
port: options.port,
|
|
131
185
|
});
|
|
132
186
|
if (!wizardResult) {
|
|
133
187
|
console.log(chalk.yellow("Project setup cancelled."));
|
|
@@ -179,22 +233,6 @@ function finalizeCreate(result, options) {
|
|
|
179
233
|
}
|
|
180
234
|
printCreateNextSteps(result.options, result.outDir, { installed, debugProfile: debugArtifacts.length > 0 });
|
|
181
235
|
}
|
|
182
|
-
async function handleBoardAdd(options) {
|
|
183
|
-
const { scaffoldBoardPackages, parseBoardSpec, generateFrameworkChecklist } = await import("./create/index.js");
|
|
184
|
-
if (!fs.existsSync(options.specPath)) {
|
|
185
|
-
throw new Error(`Spec file not found: ${options.specPath}`);
|
|
186
|
-
}
|
|
187
|
-
console.log(`Reading spec: ${options.specPath}`);
|
|
188
|
-
const specText = fs.readFileSync(options.specPath, "utf8");
|
|
189
|
-
const spec = parseBoardSpec(specText);
|
|
190
|
-
console.log(`Generating board packages for ${spec.architecture} (${spec.boardName})...`);
|
|
191
|
-
const result = scaffoldBoardPackages(spec, { force: options.force });
|
|
192
|
-
console.log(`\nCreated ${result.createdFiles.length} files:`);
|
|
193
|
-
for (const f of result.createdFiles) {
|
|
194
|
-
console.log(` ${path.relative(process.cwd(), f)}`);
|
|
195
|
-
}
|
|
196
|
-
console.log(generateFrameworkChecklist(spec));
|
|
197
|
-
}
|
|
198
236
|
async function main() {
|
|
199
237
|
try {
|
|
200
238
|
const options = parseCommandLine(process.argv);
|
|
@@ -206,10 +244,6 @@ async function main() {
|
|
|
206
244
|
await handleCreate(options);
|
|
207
245
|
return;
|
|
208
246
|
}
|
|
209
|
-
if (options.command === "board-add") {
|
|
210
|
-
await handleBoardAdd(options);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
247
|
if (options.command === "library") {
|
|
214
248
|
await runLibraryCommand(options);
|
|
215
249
|
return;
|
|
@@ -221,31 +255,6 @@ async function main() {
|
|
|
221
255
|
});
|
|
222
256
|
return;
|
|
223
257
|
}
|
|
224
|
-
if (options.command === "map-error") {
|
|
225
|
-
if (!options.mapFile || !options.cppLine || !options.cppColumn) {
|
|
226
|
-
throw new Error("map-error requires map file and C++ line/column options.");
|
|
227
|
-
}
|
|
228
|
-
const mapPath = resolveMapPath(options.mapFile);
|
|
229
|
-
const sourceMap = readSourceMap(mapPath);
|
|
230
|
-
const mapped = mapCppLocationToTs(sourceMap, options.cppLine, options.cppColumn, options.message, options.cppFile);
|
|
231
|
-
if (!mapped.mappedTsSpan) {
|
|
232
|
-
console.log("No TypeScript mapping found for the provided C++ location.");
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
console.log([
|
|
236
|
-
`Mapped TS location: ${mapped.mappedTsSpan.filePath}`,
|
|
237
|
-
`(${mapped.mappedTsSpan.startLine},${mapped.mappedTsSpan.startColumn})`,
|
|
238
|
-
`node=${mapped.nodeKind ?? "unknown"}`,
|
|
239
|
-
mapped.symbolName ? `symbol=${mapped.symbolName}` : undefined,
|
|
240
|
-
]
|
|
241
|
-
.filter(Boolean)
|
|
242
|
-
.join(" "));
|
|
243
|
-
}
|
|
244
|
-
if (mapped.message) {
|
|
245
|
-
console.log(`Compiler message: ${mapped.message}`);
|
|
246
|
-
}
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
258
|
if (options.command === "doctor" || options.command === "licenses") {
|
|
250
259
|
// These commands run standalone (often before a build), so the framework
|
|
251
260
|
// isn't loaded yet. Load it from the config's framework field so the
|
|
@@ -278,6 +287,74 @@ async function main() {
|
|
|
278
287
|
fw.licenses(options.strict ?? false, options.all ?? false);
|
|
279
288
|
return;
|
|
280
289
|
}
|
|
290
|
+
// ── Handle board catalog sync / board module regen ────────────────────
|
|
291
|
+
if (options.command === "board") {
|
|
292
|
+
const config = loadCuttlefishConfig(process.cwd());
|
|
293
|
+
if (!config) {
|
|
294
|
+
throw new Error("No cuttlefish.config.ts found in current directory.\n" +
|
|
295
|
+
"Run 'cuttlefish create' to create one.");
|
|
296
|
+
}
|
|
297
|
+
// The framework owns the board catalog + module generation; load it
|
|
298
|
+
// the same way the doctor command does.
|
|
299
|
+
if (!hasLoadedFramework() && config.framework) {
|
|
300
|
+
try {
|
|
301
|
+
loadFrameworkPackage(config.framework, process.cwd());
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Framework package not resolvable — the hook error below names
|
|
305
|
+
// the problem better than a loader crash would.
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const strategy = hasLoadedFramework()
|
|
309
|
+
? getLoadedFramework().strategy
|
|
310
|
+
: undefined;
|
|
311
|
+
if (options.subcommand === "sync") {
|
|
312
|
+
if (typeof strategy?.syncBoardCatalog !== "function") {
|
|
313
|
+
throw new Error(`Framework '${config.framework ?? "(none)"}' provides no board catalog sync — ` +
|
|
314
|
+
`'cuttlefish board sync' applies to Zephyr-framework projects.`);
|
|
315
|
+
}
|
|
316
|
+
const report = strategy.syncBoardCatalog(options.zephyrBase);
|
|
317
|
+
const version = report.provenance.version || "unknown version";
|
|
318
|
+
const head = report.provenance.gitHead ? ` @ ${report.provenance.gitHead.slice(0, 12)}` : "";
|
|
319
|
+
const fp = sdkFingerprint(report.zephyrBase);
|
|
320
|
+
ui.printSuccess(`Board catalog synced from Zephyr ${version}${head}`);
|
|
321
|
+
console.log(chalk.gray(` tree: ${report.zephyrBase}`));
|
|
322
|
+
if (fp)
|
|
323
|
+
console.log(chalk.gray(` fingerprint: ${fp} (pin ${PINNED_ZEPHYR_MANIFEST_REV})`));
|
|
324
|
+
console.log(chalk.gray(` catalog: ${report.overlayPath}`));
|
|
325
|
+
console.log(` ${report.stats.variants} board variants (${report.stats.withFacts} with pin facts` +
|
|
326
|
+
`${report.stats.failures > 0 ? `, ${report.stats.failures} reader failures` : ""}` +
|
|
327
|
+
`${report.stats.droppedYamls > 0 ? `, ${report.stats.droppedYamls} yamls with no resolvable .dts` : ""})`);
|
|
328
|
+
const { added, changed, removed } = report;
|
|
329
|
+
const list = (ids, verb) => ids.length === 0
|
|
330
|
+
? chalk.gray(` 0 ${verb}`)
|
|
331
|
+
: ` ${ids.length} ${verb}: ${ids.slice(0, 8).join(", ")}${ids.length > 8 ? ", …" : ""}`;
|
|
332
|
+
console.log(chalk.gray(" vs the previous catalog (what changed in your tree):"));
|
|
333
|
+
console.log(list(added, "added"));
|
|
334
|
+
console.log(list(changed, "changed"));
|
|
335
|
+
console.log(list(removed, "removed"));
|
|
336
|
+
// Refresh the project's own board module so the sync lands in this
|
|
337
|
+
// project immediately (not just on the next first-build).
|
|
338
|
+
if (config.board && !config.contract) {
|
|
339
|
+
const dir = regenBoardModule(config);
|
|
340
|
+
ui.printSuccess(`Regenerated the board module for '${config.board}' in ${path.join(dir, "board.ts")}`);
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// regen: refresh a stale catalog overlay first, so a regen after
|
|
345
|
+
// `west update` picks up the tree's boards automatically. Best-effort
|
|
346
|
+
// — a missing tree or a failed walk must not block regenerating from
|
|
347
|
+
// whatever catalog is already present.
|
|
348
|
+
try {
|
|
349
|
+
strategy?.ensureFreshBoardCatalog?.();
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
// Non-fatal by design (see above).
|
|
353
|
+
}
|
|
354
|
+
const dir = regenBoardModule(config);
|
|
355
|
+
ui.printSuccess(`Regenerated the board module for '${config.board}' in ${path.join(dir, "board.ts")}`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
281
358
|
// ── Handle build command — entry point comes from config ──────────
|
|
282
359
|
if (options.command === "build") {
|
|
283
360
|
const buildConfig = loadCuttlefishConfig(process.cwd());
|
|
@@ -287,7 +364,7 @@ async function main() {
|
|
|
287
364
|
}
|
|
288
365
|
if (!buildConfig.entry) {
|
|
289
366
|
throw new Error("cuttlefish.config.ts has no 'entry' field.\n" +
|
|
290
|
-
"Add: entry: './src/
|
|
367
|
+
"Add: entry: './src/main.ts'");
|
|
291
368
|
}
|
|
292
369
|
const entryFile = path.resolve(path.dirname(buildConfig.configPath), buildConfig.entry);
|
|
293
370
|
if (!fs.existsSync(entryFile)) {
|
|
@@ -308,37 +385,6 @@ async function main() {
|
|
|
308
385
|
// it intentionally has no inputFile (it scans scanDir instead), so the
|
|
309
386
|
// generic "Missing input file path" check would otherwise block it.
|
|
310
387
|
if (options.command === "gen-decls") {
|
|
311
|
-
// Check for --components flag (ESP-IDF components: managed + local).
|
|
312
|
-
// Runs before scanDir/single-file branches; components mode has no
|
|
313
|
-
// inputFile by design (it scans managed_components/ + components/).
|
|
314
|
-
const componentsDir = options.componentsDir;
|
|
315
|
-
if (componentsDir) {
|
|
316
|
-
ui.printHeader();
|
|
317
|
-
ui.printStep(`Generating component declarations for ${componentsDir}...`);
|
|
318
|
-
const config = loadCuttlefishConfig(componentsDir);
|
|
319
|
-
const frameworkConfig = (config?.frameworkConfig ?? {});
|
|
320
|
-
const componentsNode = frameworkConfig?.components ?? {};
|
|
321
|
-
const managedSpecs = Object.keys(componentsNode.managed ?? {});
|
|
322
|
-
// idf.py stores managed deps as <namespace>__<name> (slashes → __).
|
|
323
|
-
const managedNames = managedSpecs.map((spec) => spec.replace("/", "__"));
|
|
324
|
-
const localPaths = (componentsNode.local ?? []).map((p) => path.isAbsolute(p) ? p : path.resolve(componentsDir, p));
|
|
325
|
-
const builtinNames = componentsNode.builtin ?? [];
|
|
326
|
-
const created = generateComponentDeclsForProject(componentsDir, {
|
|
327
|
-
managed: managedNames,
|
|
328
|
-
local: localPaths,
|
|
329
|
-
builtin: [],
|
|
330
|
-
idfRoot: undefined,
|
|
331
|
-
});
|
|
332
|
-
if (created.length === 0) {
|
|
333
|
-
ui.printInfo("No component declaration files created.");
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
ui.printSuccess(`Created ${created.length} declaration file(s):`);
|
|
337
|
-
for (const f of created)
|
|
338
|
-
ui.printFileCreated(f);
|
|
339
|
-
}
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
388
|
// Check for --all flag (scan directory)
|
|
343
389
|
const scanDir = options.scanDir;
|
|
344
390
|
if (scanDir) {
|
|
@@ -379,9 +425,9 @@ async function main() {
|
|
|
379
425
|
if (options.expect) {
|
|
380
426
|
const config = loadCuttlefishConfig(process.cwd());
|
|
381
427
|
const exitCode = runExpectTests({
|
|
382
|
-
port: options.port
|
|
428
|
+
port: options.port,
|
|
383
429
|
buildTarget: config?.buildTarget,
|
|
384
|
-
baud:
|
|
430
|
+
baud: options.baud,
|
|
385
431
|
expectFile: options.expectFile,
|
|
386
432
|
});
|
|
387
433
|
process.exitCode = exitCode;
|
|
@@ -390,23 +436,6 @@ async function main() {
|
|
|
390
436
|
throw new Error("Missing input file path.");
|
|
391
437
|
}
|
|
392
438
|
assertTypeScriptInput(options.inputFile);
|
|
393
|
-
if (options.command === "gen-libdefs") {
|
|
394
|
-
const outDir = path.dirname(options.inputFile);
|
|
395
|
-
const created = generateLibraryDefinitions({
|
|
396
|
-
inputFile: options.inputFile,
|
|
397
|
-
outDir,
|
|
398
|
-
});
|
|
399
|
-
if (created.length === 0) {
|
|
400
|
-
console.log("No new library definition files created.");
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
console.log("Created library definition files:");
|
|
404
|
-
for (const filePath of created) {
|
|
405
|
-
console.log(`- ${filePath}`);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
439
|
// ── Load cuttlefish.config.ts (config wins over CLI flags) ──────────
|
|
411
440
|
const inputDir = path.dirname(path.resolve(options.inputFile));
|
|
412
441
|
const config = loadCuttlefishConfig(inputDir);
|
|
@@ -419,42 +448,6 @@ async function main() {
|
|
|
419
448
|
if (config?.contract) {
|
|
420
449
|
await generateContractBoard(config);
|
|
421
450
|
}
|
|
422
|
-
// ── Pre-transpile: generate component .d.ts stubs ───────────────────
|
|
423
|
-
// The transpile type-check needs the .d.ts imports in main.ts to resolve.
|
|
424
|
-
// For ESP-IDF builtin/managed/local components, those .d.ts files are
|
|
425
|
-
// generated by gen-decls — so we must run it BEFORE type-checking, not
|
|
426
|
-
// only as part of --compile. The cache is written under the transpile
|
|
427
|
-
// output dir (the same path --compile uses), so user imports resolve
|
|
428
|
-
// identically in both flows.
|
|
429
|
-
if (config?.frameworkConfig) {
|
|
430
|
-
const fc = config.frameworkConfig;
|
|
431
|
-
const componentsNode = fc?.components ?? {};
|
|
432
|
-
const managedSpecs = Object.keys(componentsNode.managed ?? {});
|
|
433
|
-
const localPaths = (componentsNode.local ?? []).map((p) => path.isAbsolute(p) ? p : path.resolve(inputDir, p));
|
|
434
|
-
const builtinNames = componentsNode.builtin ?? [];
|
|
435
|
-
if (managedSpecs.length > 0 || localPaths.length > 0 || builtinNames.length > 0) {
|
|
436
|
-
// Resolve the transpile output dir — the cache lives under it so the
|
|
437
|
-
// framework's compile path and this pre-transpile pass agree on location.
|
|
438
|
-
// output.outDir in config is relative to the project root (inputDir);
|
|
439
|
-
// if absent, the transpile output goes alongside the entry file.
|
|
440
|
-
const outBase = config.outputOutDir
|
|
441
|
-
? path.resolve(inputDir, config.outputOutDir)
|
|
442
|
-
: inputDir;
|
|
443
|
-
try {
|
|
444
|
-
generateComponentDeclsForProject(outBase, {
|
|
445
|
-
managed: managedSpecs.map((s) => s.replace('/', '__')),
|
|
446
|
-
local: localPaths,
|
|
447
|
-
builtin: [],
|
|
448
|
-
idfRoot: undefined,
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
catch {
|
|
452
|
-
// Non-fatal: if gen-decls fails (e.g. component not yet fetched),
|
|
453
|
-
// the type-checker will surface the missing-import errors with
|
|
454
|
-
// clearer context than crashing here.
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
451
|
// Load the UI engine (if @typecad/ui is installed) before any UI work.
|
|
459
452
|
await loadUIEngine();
|
|
460
453
|
// Load the safety engine (if @typecad/safety is installed) before any
|
|
@@ -463,9 +456,8 @@ async function main() {
|
|
|
463
456
|
let effectivePlatformContext = options.platformContext;
|
|
464
457
|
let effectiveTarget = options.target;
|
|
465
458
|
let effectiveOutDir = options.outDir;
|
|
466
|
-
let
|
|
459
|
+
let effectiveBoardTarget = options.boardTarget;
|
|
467
460
|
let effectiveFrameworkPackage = options.frameworkPackage;
|
|
468
|
-
let effectiveMcuPackage;
|
|
469
461
|
let effectivePort = options.port;
|
|
470
462
|
// CUTTLEFISH_PORT env var sits between the CLI flag and the config file
|
|
471
463
|
// (flag > env > config), so cross-platform uploads don't need a
|
|
@@ -474,15 +466,8 @@ async function main() {
|
|
|
474
466
|
effectivePort = process.env.CUTTLEFISH_PORT;
|
|
475
467
|
}
|
|
476
468
|
if (config) {
|
|
477
|
-
if (config.
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
// Config port is the default; CLI --port flag overrides it.
|
|
481
|
-
if (!effectivePort && config.console?.port) {
|
|
482
|
-
effectivePort = config.console.port;
|
|
483
|
-
}
|
|
484
|
-
if (config.board || config.mcu) {
|
|
485
|
-
effectiveBoardPackage = config.board || config.mcu;
|
|
469
|
+
if (config.board) {
|
|
470
|
+
effectiveBoardTarget = config.board;
|
|
486
471
|
}
|
|
487
472
|
let configBuildTarget = config.buildTarget;
|
|
488
473
|
if (configBuildTarget) {
|
|
@@ -493,7 +478,7 @@ async function main() {
|
|
|
493
478
|
frameworkData: {
|
|
494
479
|
buildTarget: configBuildTarget,
|
|
495
480
|
// Thread the PSRAM type through to the framework so it can emit the
|
|
496
|
-
// PSRAM-enabling Kconfig
|
|
481
|
+
// PSRAM-enabling Kconfig + BOARD_HAS_PSRAM compile definition.
|
|
497
482
|
...(config.psram ? { psram: config.psram } : {}),
|
|
498
483
|
},
|
|
499
484
|
};
|
|
@@ -504,24 +489,6 @@ async function main() {
|
|
|
504
489
|
if (config.framework) {
|
|
505
490
|
effectiveFrameworkPackage = config.framework;
|
|
506
491
|
}
|
|
507
|
-
if (config.target) {
|
|
508
|
-
if (effectiveFrameworkPackage) {
|
|
509
|
-
try {
|
|
510
|
-
loadFrameworkPackage(effectiveFrameworkPackage, inputDir);
|
|
511
|
-
if (hasLoadedFramework()) {
|
|
512
|
-
effectiveTarget = getLoadedFramework().strategy.id;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
catch {
|
|
516
|
-
// Framework not loadable — keep the CLI-provided target
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// Pass console baud rate to platform context
|
|
521
|
-
if (config.console?.baudRate) {
|
|
522
|
-
effectivePlatformContext = effectivePlatformContext || {};
|
|
523
|
-
effectivePlatformContext.console = { baudRate: config.console.baudRate };
|
|
524
|
-
}
|
|
525
492
|
// Keep cuttlefish-env.d.ts in sync so the TS language server can resolve
|
|
526
493
|
// '@typecad/board' imports in editor without a linter error.
|
|
527
494
|
// Platform-specific declarations come from the strategy if available.
|
|
@@ -547,8 +514,7 @@ async function main() {
|
|
|
547
514
|
ui.printHeader();
|
|
548
515
|
ui.printBuildInfo({
|
|
549
516
|
framework: effectiveFrameworkPackage,
|
|
550
|
-
|
|
551
|
-
board: effectiveBoardPackage,
|
|
517
|
+
board: effectiveBoardTarget,
|
|
552
518
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget,
|
|
553
519
|
});
|
|
554
520
|
// ── Watch mode ────────────────────────────────────────────────────────
|
|
@@ -566,7 +532,7 @@ async function main() {
|
|
|
566
532
|
emitMaps: options.emitMaps,
|
|
567
533
|
platformContext: effectivePlatformContext,
|
|
568
534
|
treeShaking: options.treeShaking,
|
|
569
|
-
|
|
535
|
+
boardTarget: effectiveBoardTarget,
|
|
570
536
|
frameworkPackage: effectiveFrameworkPackage,
|
|
571
537
|
debug: options.debug,
|
|
572
538
|
force: options.force,
|
|
@@ -588,28 +554,29 @@ async function main() {
|
|
|
588
554
|
// Initial compile + upload if flags are set
|
|
589
555
|
if (options.compile) {
|
|
590
556
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
591
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
592
557
|
const watchOpts = {
|
|
593
558
|
outputDir: path.dirname(result.sourcePath),
|
|
594
559
|
sourcePath: result.sourcePath,
|
|
595
|
-
buildTarget,
|
|
560
|
+
buildTarget: baseBuildTarget,
|
|
596
561
|
port: effectivePort,
|
|
597
|
-
baud: options.baud
|
|
562
|
+
baud: options.baud,
|
|
598
563
|
extraFlags: config?.outputExtraFlags,
|
|
599
|
-
defines:
|
|
564
|
+
defines: config?.outputDefines ?? {},
|
|
600
565
|
psram: config?.psram,
|
|
601
566
|
frameworkConfig: config?.frameworkConfig,
|
|
602
567
|
zephyrConfig: config?.zephyrConfig,
|
|
603
568
|
display: displayConfigForTranspile(config),
|
|
604
569
|
debug: options.debug,
|
|
605
570
|
};
|
|
606
|
-
ui.printCompiling(
|
|
571
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
607
572
|
const compileResult = compileSource(watchOpts);
|
|
608
573
|
printMappedCompileErrors(compileResult, result.sourceMapPath, result.sourcePath, path.dirname(result.sourcePath));
|
|
609
574
|
if (compileResult.success) {
|
|
610
575
|
if (compileResult.memoryUsage)
|
|
611
576
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
612
|
-
if (options.upload
|
|
577
|
+
if (options.upload) {
|
|
578
|
+
// No port gate here — probe/USB flashing needs none, and the
|
|
579
|
+
// framework reports a friendly failure when the runner does.
|
|
613
580
|
ui.printUploading(effectivePort);
|
|
614
581
|
const uploadResult = uploadFirmware(watchOpts);
|
|
615
582
|
if (uploadResult.output)
|
|
@@ -644,7 +611,7 @@ async function main() {
|
|
|
644
611
|
process.stdout.write("\x1Bc");
|
|
645
612
|
const timestamp = new Date().toLocaleTimeString();
|
|
646
613
|
const relativePath = path.relative(process.cwd(), changedFile);
|
|
647
|
-
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(`
|
|
614
|
+
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(` v${ui.VERSION}`));
|
|
648
615
|
console.log();
|
|
649
616
|
ui.printInfo(`[${timestamp}] Change detected: ${relativePath}`);
|
|
650
617
|
console.log();
|
|
@@ -665,7 +632,7 @@ async function main() {
|
|
|
665
632
|
emitMaps: options.emitMaps,
|
|
666
633
|
platformContext: effectivePlatformContext,
|
|
667
634
|
treeShaking: options.treeShaking,
|
|
668
|
-
|
|
635
|
+
boardTarget: effectiveBoardTarget,
|
|
669
636
|
frameworkPackage: effectiveFrameworkPackage,
|
|
670
637
|
debug: options.debug,
|
|
671
638
|
force: true, // Always force in watch mode to bypass stale cache
|
|
@@ -688,28 +655,30 @@ async function main() {
|
|
|
688
655
|
ui.printSuccess();
|
|
689
656
|
if (options.compile) {
|
|
690
657
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
691
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
692
658
|
const rebuildOpts = {
|
|
693
659
|
outputDir: path.dirname(rebuildResult.sourcePath),
|
|
694
660
|
sourcePath: rebuildResult.sourcePath,
|
|
695
|
-
buildTarget,
|
|
661
|
+
buildTarget: baseBuildTarget,
|
|
696
662
|
port: effectivePort,
|
|
697
|
-
baud: options.baud
|
|
663
|
+
baud: options.baud,
|
|
698
664
|
extraFlags: config?.outputExtraFlags,
|
|
699
|
-
defines:
|
|
665
|
+
defines: config?.outputDefines ?? {},
|
|
700
666
|
psram: config?.psram,
|
|
701
667
|
frameworkConfig: config?.frameworkConfig,
|
|
702
668
|
zephyrConfig: config?.zephyrConfig,
|
|
703
669
|
display: displayConfigForTranspile(config),
|
|
704
670
|
debug: options.debug,
|
|
705
671
|
};
|
|
706
|
-
ui.printCompiling(
|
|
672
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
707
673
|
const compileResult = compileSource(rebuildOpts);
|
|
708
674
|
printMappedCompileErrors(compileResult, rebuildResult.sourceMapPath, rebuildResult.sourcePath, path.dirname(rebuildResult.sourcePath));
|
|
709
675
|
if (compileResult.success) {
|
|
710
676
|
if (compileResult.memoryUsage)
|
|
711
677
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
712
|
-
if (options.upload
|
|
678
|
+
if (options.upload) {
|
|
679
|
+
// No port gate here — probe/USB flashing needs none, and
|
|
680
|
+
// the framework reports a friendly failure when the
|
|
681
|
+
// runner does.
|
|
713
682
|
ui.printUploading(effectivePort);
|
|
714
683
|
const uploadResult = uploadFirmware(rebuildOpts);
|
|
715
684
|
if (uploadResult.output)
|
|
@@ -758,7 +727,7 @@ async function main() {
|
|
|
758
727
|
emitMaps: options.emitMaps,
|
|
759
728
|
platformContext: effectivePlatformContext,
|
|
760
729
|
treeShaking: options.treeShaking,
|
|
761
|
-
|
|
730
|
+
boardTarget: effectiveBoardTarget,
|
|
762
731
|
frameworkPackage: effectiveFrameworkPackage,
|
|
763
732
|
debug: options.debug,
|
|
764
733
|
force: options.force,
|
|
@@ -786,7 +755,7 @@ async function main() {
|
|
|
786
755
|
const exitCode = runExpectTests({
|
|
787
756
|
port: effectivePort,
|
|
788
757
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget,
|
|
789
|
-
baud:
|
|
758
|
+
baud: options.baud,
|
|
790
759
|
expectFile: options.expectFile,
|
|
791
760
|
});
|
|
792
761
|
process.exitCode = exitCode;
|
|
@@ -795,22 +764,24 @@ async function main() {
|
|
|
795
764
|
}
|
|
796
765
|
// --compile (delegates to the active framework's toolchain)
|
|
797
766
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
798
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
799
767
|
const toolchainOpts = {
|
|
800
768
|
outputDir: path.dirname(result.sourcePath),
|
|
801
769
|
sourcePath: result.sourcePath,
|
|
802
|
-
buildTarget,
|
|
770
|
+
buildTarget: baseBuildTarget,
|
|
803
771
|
port: effectivePort,
|
|
804
|
-
baud: options.baud
|
|
772
|
+
baud: options.baud,
|
|
805
773
|
extraFlags: config?.outputExtraFlags,
|
|
806
|
-
defines:
|
|
774
|
+
defines: config?.outputDefines ?? {},
|
|
807
775
|
psram: config?.psram,
|
|
808
776
|
frameworkConfig: config?.frameworkConfig,
|
|
809
|
-
|
|
777
|
+
// --probe <method> overrides zephyr.probe from the config for this run.
|
|
778
|
+
zephyrConfig: options.probe
|
|
779
|
+
? { ...(config?.zephyrConfig ?? {}), probe: options.probe }
|
|
780
|
+
: config?.zephyrConfig,
|
|
810
781
|
display: displayConfigForTranspile(config),
|
|
811
782
|
debug: options.debug,
|
|
812
783
|
};
|
|
813
|
-
ui.printCompiling(
|
|
784
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
814
785
|
let compileResult;
|
|
815
786
|
try {
|
|
816
787
|
compileResult = compileSource(toolchainOpts);
|
|
@@ -840,10 +811,11 @@ async function main() {
|
|
|
840
811
|
ui.printSuccess();
|
|
841
812
|
return;
|
|
842
813
|
}
|
|
843
|
-
// --upload
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
814
|
+
// --upload. Whether a port is required is the active framework's call —
|
|
815
|
+
// probe-based flashing (openocd/jlink) and USB bootloaders (dfu-util,
|
|
816
|
+
// uf2) need no serial port, so a missing --port only surfaces as the
|
|
817
|
+
// framework's own upload failure for serial-port runners (esptool,
|
|
818
|
+
// bossac).
|
|
847
819
|
const port = effectivePort;
|
|
848
820
|
ui.printUploading(port);
|
|
849
821
|
const uploadResult = uploadFirmware(toolchainOpts);
|
|
@@ -859,9 +831,14 @@ async function main() {
|
|
|
859
831
|
return;
|
|
860
832
|
}
|
|
861
833
|
if (options.monitor) {
|
|
862
|
-
// --monitor (blocks until Ctrl+C).
|
|
863
|
-
//
|
|
864
|
-
|
|
834
|
+
// --monitor (blocks until Ctrl+C). Unlike flashing, monitoring always
|
|
835
|
+
// needs a serial port — there is no probe/USB flavor of it.
|
|
836
|
+
if (!port) {
|
|
837
|
+
throw new Error("--monitor requires a port. Set --port <port> on the command line (or the CUTTLEFISH_PORT env var).");
|
|
838
|
+
}
|
|
839
|
+
// Show the resolved --baud in the banner — toolchainOpts.baud is built
|
|
840
|
+
// the same way, so what the user sees is what the framework monitor
|
|
841
|
+
// opens the port at.
|
|
865
842
|
ui.printMonitoring(port, toolchainOpts.baud ?? 115200);
|
|
866
843
|
monitorDevice(toolchainOpts);
|
|
867
844
|
return;
|
|
@@ -871,8 +848,8 @@ async function main() {
|
|
|
871
848
|
ui.printSuccess();
|
|
872
849
|
const exitCode = runExpectTests({
|
|
873
850
|
port: effectivePort,
|
|
874
|
-
buildTarget,
|
|
875
|
-
baud:
|
|
851
|
+
buildTarget: baseBuildTarget,
|
|
852
|
+
baud: options.baud,
|
|
876
853
|
expectFile: options.expectFile,
|
|
877
854
|
});
|
|
878
855
|
process.exitCode = exitCode;
|