@typecad/cuttlefish 1.0.0-alpha.14 → 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 +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 +214 -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 +41 -9
- package/dist/create/framework-catalog.js +48 -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 +27 -5
- package/dist/create/templates.js +120 -116
- package/dist/create/wizard.d.ts +12 -1
- package/dist/create/wizard.js +163 -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 } 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,53 @@ 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
|
-
// Framework-specific build target + toolchain (Zephyr board id + 'west'
|
|
102
|
-
// the Arduino FQBN + 'arduino-cli').
|
|
137
|
+
// Framework-specific build target + toolchain (Zephyr board id + 'west').
|
|
103
138
|
const profile = frameworkTargetProfile(target, frameworkId);
|
|
139
|
+
const buildTarget = profile.buildTarget ?? target.buildTarget;
|
|
104
140
|
const result = scaffoldProject({
|
|
141
|
+
probeMethod: options.probe,
|
|
142
|
+
probeMethods,
|
|
105
143
|
projectName,
|
|
106
144
|
targetId: target.id,
|
|
107
145
|
targetDisplayName: target.displayName,
|
|
108
146
|
isNative: target.isNative,
|
|
109
147
|
architecture: target.architecture,
|
|
110
|
-
|
|
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) } : {}),
|
|
111
153
|
frameworkPackage,
|
|
112
154
|
framework: frameworkId,
|
|
113
|
-
buildTarget
|
|
155
|
+
buildTarget,
|
|
114
156
|
...(profile.toolchainType ? { toolchainType: profile.toolchainType } : {}),
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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 } : {}),
|
|
118
165
|
...(target.frameworkData
|
|
119
166
|
? { frameworkData: target.frameworkData }
|
|
120
167
|
: {}),
|
|
@@ -124,10 +171,12 @@ async function handleCreate(options) {
|
|
|
124
171
|
else {
|
|
125
172
|
const wizardResult = await runCreateWizard({
|
|
126
173
|
projectName: options.projectName,
|
|
127
|
-
board: options.board,
|
|
174
|
+
board: options.board ?? options.target,
|
|
128
175
|
framework: options.framework,
|
|
129
176
|
baud: options.baud,
|
|
130
|
-
|
|
177
|
+
noStarter: options.noStarter,
|
|
178
|
+
probe: options.probe,
|
|
179
|
+
port: options.port,
|
|
131
180
|
});
|
|
132
181
|
if (!wizardResult) {
|
|
133
182
|
console.log(chalk.yellow("Project setup cancelled."));
|
|
@@ -179,22 +228,6 @@ function finalizeCreate(result, options) {
|
|
|
179
228
|
}
|
|
180
229
|
printCreateNextSteps(result.options, result.outDir, { installed, debugProfile: debugArtifacts.length > 0 });
|
|
181
230
|
}
|
|
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
231
|
async function main() {
|
|
199
232
|
try {
|
|
200
233
|
const options = parseCommandLine(process.argv);
|
|
@@ -206,10 +239,6 @@ async function main() {
|
|
|
206
239
|
await handleCreate(options);
|
|
207
240
|
return;
|
|
208
241
|
}
|
|
209
|
-
if (options.command === "board-add") {
|
|
210
|
-
await handleBoardAdd(options);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
242
|
if (options.command === "library") {
|
|
214
243
|
await runLibraryCommand(options);
|
|
215
244
|
return;
|
|
@@ -221,31 +250,6 @@ async function main() {
|
|
|
221
250
|
});
|
|
222
251
|
return;
|
|
223
252
|
}
|
|
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
253
|
if (options.command === "doctor" || options.command === "licenses") {
|
|
250
254
|
// These commands run standalone (often before a build), so the framework
|
|
251
255
|
// isn't loaded yet. Load it from the config's framework field so the
|
|
@@ -278,6 +282,74 @@ async function main() {
|
|
|
278
282
|
fw.licenses(options.strict ?? false, options.all ?? false);
|
|
279
283
|
return;
|
|
280
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
|
+
}
|
|
281
353
|
// ── Handle build command — entry point comes from config ──────────
|
|
282
354
|
if (options.command === "build") {
|
|
283
355
|
const buildConfig = loadCuttlefishConfig(process.cwd());
|
|
@@ -287,7 +359,7 @@ async function main() {
|
|
|
287
359
|
}
|
|
288
360
|
if (!buildConfig.entry) {
|
|
289
361
|
throw new Error("cuttlefish.config.ts has no 'entry' field.\n" +
|
|
290
|
-
"Add: entry: './src/
|
|
362
|
+
"Add: entry: './src/main.ts'");
|
|
291
363
|
}
|
|
292
364
|
const entryFile = path.resolve(path.dirname(buildConfig.configPath), buildConfig.entry);
|
|
293
365
|
if (!fs.existsSync(entryFile)) {
|
|
@@ -308,37 +380,6 @@ async function main() {
|
|
|
308
380
|
// it intentionally has no inputFile (it scans scanDir instead), so the
|
|
309
381
|
// generic "Missing input file path" check would otherwise block it.
|
|
310
382
|
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
383
|
// Check for --all flag (scan directory)
|
|
343
384
|
const scanDir = options.scanDir;
|
|
344
385
|
if (scanDir) {
|
|
@@ -379,9 +420,9 @@ async function main() {
|
|
|
379
420
|
if (options.expect) {
|
|
380
421
|
const config = loadCuttlefishConfig(process.cwd());
|
|
381
422
|
const exitCode = runExpectTests({
|
|
382
|
-
port: options.port
|
|
423
|
+
port: options.port,
|
|
383
424
|
buildTarget: config?.buildTarget,
|
|
384
|
-
baud:
|
|
425
|
+
baud: options.baud,
|
|
385
426
|
expectFile: options.expectFile,
|
|
386
427
|
});
|
|
387
428
|
process.exitCode = exitCode;
|
|
@@ -390,23 +431,6 @@ async function main() {
|
|
|
390
431
|
throw new Error("Missing input file path.");
|
|
391
432
|
}
|
|
392
433
|
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
434
|
// ── Load cuttlefish.config.ts (config wins over CLI flags) ──────────
|
|
411
435
|
const inputDir = path.dirname(path.resolve(options.inputFile));
|
|
412
436
|
const config = loadCuttlefishConfig(inputDir);
|
|
@@ -419,42 +443,6 @@ async function main() {
|
|
|
419
443
|
if (config?.contract) {
|
|
420
444
|
await generateContractBoard(config);
|
|
421
445
|
}
|
|
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
446
|
// Load the UI engine (if @typecad/ui is installed) before any UI work.
|
|
459
447
|
await loadUIEngine();
|
|
460
448
|
// Load the safety engine (if @typecad/safety is installed) before any
|
|
@@ -463,9 +451,8 @@ async function main() {
|
|
|
463
451
|
let effectivePlatformContext = options.platformContext;
|
|
464
452
|
let effectiveTarget = options.target;
|
|
465
453
|
let effectiveOutDir = options.outDir;
|
|
466
|
-
let
|
|
454
|
+
let effectiveBoardTarget = options.boardTarget;
|
|
467
455
|
let effectiveFrameworkPackage = options.frameworkPackage;
|
|
468
|
-
let effectiveMcuPackage;
|
|
469
456
|
let effectivePort = options.port;
|
|
470
457
|
// CUTTLEFISH_PORT env var sits between the CLI flag and the config file
|
|
471
458
|
// (flag > env > config), so cross-platform uploads don't need a
|
|
@@ -474,15 +461,8 @@ async function main() {
|
|
|
474
461
|
effectivePort = process.env.CUTTLEFISH_PORT;
|
|
475
462
|
}
|
|
476
463
|
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;
|
|
464
|
+
if (config.board) {
|
|
465
|
+
effectiveBoardTarget = config.board;
|
|
486
466
|
}
|
|
487
467
|
let configBuildTarget = config.buildTarget;
|
|
488
468
|
if (configBuildTarget) {
|
|
@@ -493,7 +473,7 @@ async function main() {
|
|
|
493
473
|
frameworkData: {
|
|
494
474
|
buildTarget: configBuildTarget,
|
|
495
475
|
// Thread the PSRAM type through to the framework so it can emit the
|
|
496
|
-
// PSRAM-enabling Kconfig
|
|
476
|
+
// PSRAM-enabling Kconfig + BOARD_HAS_PSRAM compile definition.
|
|
497
477
|
...(config.psram ? { psram: config.psram } : {}),
|
|
498
478
|
},
|
|
499
479
|
};
|
|
@@ -504,24 +484,6 @@ async function main() {
|
|
|
504
484
|
if (config.framework) {
|
|
505
485
|
effectiveFrameworkPackage = config.framework;
|
|
506
486
|
}
|
|
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
487
|
// Keep cuttlefish-env.d.ts in sync so the TS language server can resolve
|
|
526
488
|
// '@typecad/board' imports in editor without a linter error.
|
|
527
489
|
// Platform-specific declarations come from the strategy if available.
|
|
@@ -547,8 +509,7 @@ async function main() {
|
|
|
547
509
|
ui.printHeader();
|
|
548
510
|
ui.printBuildInfo({
|
|
549
511
|
framework: effectiveFrameworkPackage,
|
|
550
|
-
|
|
551
|
-
board: effectiveBoardPackage,
|
|
512
|
+
board: effectiveBoardTarget,
|
|
552
513
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget,
|
|
553
514
|
});
|
|
554
515
|
// ── Watch mode ────────────────────────────────────────────────────────
|
|
@@ -566,7 +527,7 @@ async function main() {
|
|
|
566
527
|
emitMaps: options.emitMaps,
|
|
567
528
|
platformContext: effectivePlatformContext,
|
|
568
529
|
treeShaking: options.treeShaking,
|
|
569
|
-
|
|
530
|
+
boardTarget: effectiveBoardTarget,
|
|
570
531
|
frameworkPackage: effectiveFrameworkPackage,
|
|
571
532
|
debug: options.debug,
|
|
572
533
|
force: options.force,
|
|
@@ -588,28 +549,29 @@ async function main() {
|
|
|
588
549
|
// Initial compile + upload if flags are set
|
|
589
550
|
if (options.compile) {
|
|
590
551
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
591
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
592
552
|
const watchOpts = {
|
|
593
553
|
outputDir: path.dirname(result.sourcePath),
|
|
594
554
|
sourcePath: result.sourcePath,
|
|
595
|
-
buildTarget,
|
|
555
|
+
buildTarget: baseBuildTarget,
|
|
596
556
|
port: effectivePort,
|
|
597
|
-
baud: options.baud
|
|
557
|
+
baud: options.baud,
|
|
598
558
|
extraFlags: config?.outputExtraFlags,
|
|
599
|
-
defines:
|
|
559
|
+
defines: config?.outputDefines ?? {},
|
|
600
560
|
psram: config?.psram,
|
|
601
561
|
frameworkConfig: config?.frameworkConfig,
|
|
602
562
|
zephyrConfig: config?.zephyrConfig,
|
|
603
563
|
display: displayConfigForTranspile(config),
|
|
604
564
|
debug: options.debug,
|
|
605
565
|
};
|
|
606
|
-
ui.printCompiling(
|
|
566
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
607
567
|
const compileResult = compileSource(watchOpts);
|
|
608
568
|
printMappedCompileErrors(compileResult, result.sourceMapPath, result.sourcePath, path.dirname(result.sourcePath));
|
|
609
569
|
if (compileResult.success) {
|
|
610
570
|
if (compileResult.memoryUsage)
|
|
611
571
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
612
|
-
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.
|
|
613
575
|
ui.printUploading(effectivePort);
|
|
614
576
|
const uploadResult = uploadFirmware(watchOpts);
|
|
615
577
|
if (uploadResult.output)
|
|
@@ -644,7 +606,7 @@ async function main() {
|
|
|
644
606
|
process.stdout.write("\x1Bc");
|
|
645
607
|
const timestamp = new Date().toLocaleTimeString();
|
|
646
608
|
const relativePath = path.relative(process.cwd(), changedFile);
|
|
647
|
-
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(`
|
|
609
|
+
console.log(chalk.cyan(`⤳ Cuttlefish`) + chalk.gray(` v${ui.VERSION}`));
|
|
648
610
|
console.log();
|
|
649
611
|
ui.printInfo(`[${timestamp}] Change detected: ${relativePath}`);
|
|
650
612
|
console.log();
|
|
@@ -665,7 +627,7 @@ async function main() {
|
|
|
665
627
|
emitMaps: options.emitMaps,
|
|
666
628
|
platformContext: effectivePlatformContext,
|
|
667
629
|
treeShaking: options.treeShaking,
|
|
668
|
-
|
|
630
|
+
boardTarget: effectiveBoardTarget,
|
|
669
631
|
frameworkPackage: effectiveFrameworkPackage,
|
|
670
632
|
debug: options.debug,
|
|
671
633
|
force: true, // Always force in watch mode to bypass stale cache
|
|
@@ -688,28 +650,30 @@ async function main() {
|
|
|
688
650
|
ui.printSuccess();
|
|
689
651
|
if (options.compile) {
|
|
690
652
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
691
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
692
653
|
const rebuildOpts = {
|
|
693
654
|
outputDir: path.dirname(rebuildResult.sourcePath),
|
|
694
655
|
sourcePath: rebuildResult.sourcePath,
|
|
695
|
-
buildTarget,
|
|
656
|
+
buildTarget: baseBuildTarget,
|
|
696
657
|
port: effectivePort,
|
|
697
|
-
baud: options.baud
|
|
658
|
+
baud: options.baud,
|
|
698
659
|
extraFlags: config?.outputExtraFlags,
|
|
699
|
-
defines:
|
|
660
|
+
defines: config?.outputDefines ?? {},
|
|
700
661
|
psram: config?.psram,
|
|
701
662
|
frameworkConfig: config?.frameworkConfig,
|
|
702
663
|
zephyrConfig: config?.zephyrConfig,
|
|
703
664
|
display: displayConfigForTranspile(config),
|
|
704
665
|
debug: options.debug,
|
|
705
666
|
};
|
|
706
|
-
ui.printCompiling(
|
|
667
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
707
668
|
const compileResult = compileSource(rebuildOpts);
|
|
708
669
|
printMappedCompileErrors(compileResult, rebuildResult.sourceMapPath, rebuildResult.sourcePath, path.dirname(rebuildResult.sourcePath));
|
|
709
670
|
if (compileResult.success) {
|
|
710
671
|
if (compileResult.memoryUsage)
|
|
711
672
|
ui.printMemoryUsage(compileResult.memoryUsage);
|
|
712
|
-
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.
|
|
713
677
|
ui.printUploading(effectivePort);
|
|
714
678
|
const uploadResult = uploadFirmware(rebuildOpts);
|
|
715
679
|
if (uploadResult.output)
|
|
@@ -758,7 +722,7 @@ async function main() {
|
|
|
758
722
|
emitMaps: options.emitMaps,
|
|
759
723
|
platformContext: effectivePlatformContext,
|
|
760
724
|
treeShaking: options.treeShaking,
|
|
761
|
-
|
|
725
|
+
boardTarget: effectiveBoardTarget,
|
|
762
726
|
frameworkPackage: effectiveFrameworkPackage,
|
|
763
727
|
debug: options.debug,
|
|
764
728
|
force: options.force,
|
|
@@ -786,7 +750,7 @@ async function main() {
|
|
|
786
750
|
const exitCode = runExpectTests({
|
|
787
751
|
port: effectivePort,
|
|
788
752
|
buildTarget: effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget,
|
|
789
|
-
baud:
|
|
753
|
+
baud: options.baud,
|
|
790
754
|
expectFile: options.expectFile,
|
|
791
755
|
});
|
|
792
756
|
process.exitCode = exitCode;
|
|
@@ -795,22 +759,24 @@ async function main() {
|
|
|
795
759
|
}
|
|
796
760
|
// --compile (delegates to the active framework's toolchain)
|
|
797
761
|
const baseBuildTarget = effectivePlatformContext?.frameworkData?.buildTarget ?? options.platformContext?.frameworkData?.buildTarget;
|
|
798
|
-
const { buildTarget, defines: psramDefines } = applyPsramToArduinoBuild(baseBuildTarget, config?.outputDefines, config?.psram);
|
|
799
762
|
const toolchainOpts = {
|
|
800
763
|
outputDir: path.dirname(result.sourcePath),
|
|
801
764
|
sourcePath: result.sourcePath,
|
|
802
|
-
buildTarget,
|
|
765
|
+
buildTarget: baseBuildTarget,
|
|
803
766
|
port: effectivePort,
|
|
804
|
-
baud: options.baud
|
|
767
|
+
baud: options.baud,
|
|
805
768
|
extraFlags: config?.outputExtraFlags,
|
|
806
|
-
defines:
|
|
769
|
+
defines: config?.outputDefines ?? {},
|
|
807
770
|
psram: config?.psram,
|
|
808
771
|
frameworkConfig: config?.frameworkConfig,
|
|
809
|
-
|
|
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,
|
|
810
776
|
display: displayConfigForTranspile(config),
|
|
811
777
|
debug: options.debug,
|
|
812
778
|
};
|
|
813
|
-
ui.printCompiling(
|
|
779
|
+
ui.printCompiling(baseBuildTarget ?? "native");
|
|
814
780
|
let compileResult;
|
|
815
781
|
try {
|
|
816
782
|
compileResult = compileSource(toolchainOpts);
|
|
@@ -840,10 +806,11 @@ async function main() {
|
|
|
840
806
|
ui.printSuccess();
|
|
841
807
|
return;
|
|
842
808
|
}
|
|
843
|
-
// --upload
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
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).
|
|
847
814
|
const port = effectivePort;
|
|
848
815
|
ui.printUploading(port);
|
|
849
816
|
const uploadResult = uploadFirmware(toolchainOpts);
|
|
@@ -859,9 +826,14 @@ async function main() {
|
|
|
859
826
|
return;
|
|
860
827
|
}
|
|
861
828
|
if (options.monitor) {
|
|
862
|
-
// --monitor (blocks until Ctrl+C).
|
|
863
|
-
//
|
|
864
|
-
|
|
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.
|
|
865
837
|
ui.printMonitoring(port, toolchainOpts.baud ?? 115200);
|
|
866
838
|
monitorDevice(toolchainOpts);
|
|
867
839
|
return;
|
|
@@ -871,8 +843,8 @@ async function main() {
|
|
|
871
843
|
ui.printSuccess();
|
|
872
844
|
const exitCode = runExpectTests({
|
|
873
845
|
port: effectivePort,
|
|
874
|
-
buildTarget,
|
|
875
|
-
baud:
|
|
846
|
+
buildTarget: baseBuildTarget,
|
|
847
|
+
baud: options.baud,
|
|
876
848
|
expectFile: options.expectFile,
|
|
877
849
|
});
|
|
878
850
|
process.exitCode = exitCode;
|