@typecad/cuttlefish 1.0.0-alpha.15 → 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/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ 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, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard } from "./create/index.js";
6
+ import { scaffoldProject, printCreateNextSteps, KNOWN_TARGETS, frameworksForTarget, frameworkCatalogEntry, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard, probeRunnerQuirks } from "./create/index.js";
7
7
  import { findPackBoard, packBoardAsTarget } from "./create/pack-targets.js";
8
8
  import { activeBoardCatalog, assertZephyrSdkForCreate, formatZephyrSdkFound, ensureFreshBoardCatalog, resetBoardCatalogOverlayCache, sdkFingerprint, PINNED_ZEPHYR_MANIFEST_REV } from "./board-catalog/index.js";
9
9
  import { generateFrameworkDebugArtifacts } from "./create/debug-artifacts.js";
@@ -134,12 +134,17 @@ async function handleCreate(options) {
134
134
  throw new Error(`Unknown probe method '${options.probe}' for ${target.displayName}. Supported: ${list}.`);
135
135
  }
136
136
  const projectName = options.projectName || 'my-project';
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) : [];
137
141
  // Framework-specific build target + toolchain (Zephyr board id + 'west').
138
142
  const profile = frameworkTargetProfile(target, frameworkId);
139
143
  const buildTarget = profile.buildTarget ?? target.buildTarget;
140
144
  const result = scaffoldProject({
141
145
  probeMethod: options.probe,
142
146
  probeMethods,
147
+ ...(probeRunnerArgs.length > 0 ? { probeRunnerArgs } : {}),
143
148
  projectName,
144
149
  targetId: target.id,
145
150
  targetDisplayName: target.displayName,
@@ -59,6 +59,22 @@ export interface CatalogProbeMethod {
59
59
  * question is asked and no zephyr.probe section is scaffolded.
60
60
  */
61
61
  export declare function probeMethodsForBoard(boardId: string | undefined): CatalogProbeMethod[];
62
+ /**
63
+ * Pre-baked zephyr.runnerArgs the selected probe method needs to flash
64
+ * reliably — sourced from the method's captured debugCfg (the board's
65
+ * support/openocd.cfg, verbatim), so the scaffold bakes in facts, not board
66
+ * names.
67
+ *
68
+ * The one quirk today: a cfg that drives OpenOCD resets through the SRST pin
69
+ * (`reset_config srst…`) while the probe's NRST line may not reach the target
70
+ * — hobby boards like the WeAct BlackPill break no NRST out at all, so
71
+ * `reset init` asserts a pin that reaches nothing and dies with "timed out
72
+ * while waiting for target halted". Core-domain resets (SYSRESETREQ) are
73
+ * pin-independent. Boards declaring `connect_assert_srst` are excluded: that
74
+ * strategy only works with NRST wired, so the pin is provably connected there
75
+ * and connect-under-reset is worth keeping.
76
+ */
77
+ export declare function probeRunnerQuirks(boardId: string | undefined, methodId: string | undefined): string[];
62
78
  export interface FrameworkTargetProfile {
63
79
  /** Framework-specific build target (FQBN for Arduino, board id for Zephyr). */
64
80
  buildTarget?: string;
@@ -73,6 +73,34 @@ export function probeMethodsForBoard(boardId) {
73
73
  return [];
74
74
  return entry.probeMethods.map((m) => ({ id: m.id, description: m.description }));
75
75
  }
76
+ /**
77
+ * Pre-baked zephyr.runnerArgs the selected probe method needs to flash
78
+ * reliably — sourced from the method's captured debugCfg (the board's
79
+ * support/openocd.cfg, verbatim), so the scaffold bakes in facts, not board
80
+ * names.
81
+ *
82
+ * The one quirk today: a cfg that drives OpenOCD resets through the SRST pin
83
+ * (`reset_config srst…`) while the probe's NRST line may not reach the target
84
+ * — hobby boards like the WeAct BlackPill break no NRST out at all, so
85
+ * `reset init` asserts a pin that reaches nothing and dies with "timed out
86
+ * while waiting for target halted". Core-domain resets (SYSRESETREQ) are
87
+ * pin-independent. Boards declaring `connect_assert_srst` are excluded: that
88
+ * strategy only works with NRST wired, so the pin is provably connected there
89
+ * and connect-under-reset is worth keeping.
90
+ */
91
+ export function probeRunnerQuirks(boardId, methodId) {
92
+ if (!boardId || !methodId)
93
+ return [];
94
+ const method = findPackBoard(boardId)?.probeMethods?.find((m) => m.id === methodId);
95
+ // Only the openocd runner consumes the board cfg's reset_config — other
96
+ // runners (jlink, dfu-util, …) carry their own reset strategy.
97
+ if (!method || method.runner !== 'openocd')
98
+ return [];
99
+ const cfg = method.debugCfg ?? [];
100
+ const srst = cfg.some((line) => /reset_config\s+srst/.test(line));
101
+ const connectAssert = cfg.some((line) => /connect_assert_srst/.test(line));
102
+ return srst && !connectAssert ? ['--cmd-pre-init=reset_config none'] : [];
103
+ }
76
104
  /**
77
105
  * Resolve the framework-specific buildTarget + toolchain type for a
78
106
  * (board, framework) pair. Zephyr maps the board id to its Zephyr board
@@ -1,6 +1,6 @@
1
1
  export { scaffoldProject, normalizeProjectName, KNOWN_TARGETS, printCreateNextSteps } from './scaffold.js';
2
2
  export type { KnownTarget, ScaffoldProjectResult } from './scaffold.js';
3
- export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCompatibleWithTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile, probeMethodsForBoard } from './framework-catalog.js';
3
+ export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCompatibleWithTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile, probeMethodsForBoard, probeRunnerQuirks } from './framework-catalog.js';
4
4
  export type { FrameworkCatalogEntry, BoardLike, PackageManager, FrameworkTargetProfile, TargetProfileInput, CatalogProbeMethod } from './framework-catalog.js';
5
5
  export { installProjectDependencies, __setProjectInstallRunnerForTest } from './install-deps.js';
6
6
  export type { ProjectInstallResult } from './install-deps.js';
@@ -1,5 +1,5 @@
1
1
  export { scaffoldProject, normalizeProjectName, KNOWN_TARGETS, printCreateNextSteps } from './scaffold.js';
2
- export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCompatibleWithTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile, probeMethodsForBoard } from './framework-catalog.js';
2
+ export { FRAMEWORK_CATALOG, frameworksForTarget, frameworkCompatibleWithTarget, frameworkCatalogEntry, detectPackageManager, frameworkTargetProfile, probeMethodsForBoard, probeRunnerQuirks } from './framework-catalog.js';
3
3
  export { installProjectDependencies, __setProjectInstallRunnerForTest } from './install-deps.js';
4
4
  export { generateProjectPackageJson, generateProjectTsconfig, generateProjectConfig, generateProjectEnvDts, generateStarterProgram, generateStarterTest, generateStarterSim, generateGitignore, generateEditorconfig, generateEslintConfig, } from './templates.js';
5
5
  export { runCreateWizard } from './wizard.js';
@@ -29,6 +29,11 @@ export interface CreateProjectOptions {
29
29
  id: string;
30
30
  description?: string;
31
31
  }[];
32
+ /** Pre-baked zephyr.runnerArgs for the selected probe method (from
33
+ * probeRunnerQuirks — board-catalog facts, e.g. an srst-based openocd.cfg
34
+ * behind a debug header with no NRST). Emitted after probe with an
35
+ * explanatory comment. */
36
+ probeRunnerArgs?: string[];
32
37
  /** Serial port picked at create time (test.port). Absent →
33
38
  * the platform hint placeholder. */
34
39
  port?: string;
@@ -197,6 +197,16 @@ export default config;
197
197
  // flashing AND debugging.
198
198
  probe: '${options.probeMethod}',`);
199
199
  }
200
+ if (options.probeRunnerArgs && options.probeRunnerArgs.length > 0) {
201
+ const quirks = options.probeRunnerArgs.map((a) => `'${a}'`).join(', ');
202
+ zephyrFields.push(` // Quirk: this board's openocd.cfg drives OpenOCD resets through the
203
+ // SRST pin. When the probe's NRST line isn't wired to the target (the
204
+ // BlackPill's SWD header has no NRST pin at all), \`reset init\` times out
205
+ // with "timed out while waiting for target halted". These args force
206
+ // pin-independent core resets instead — remove them if NRST is wired and
207
+ // pin resets are wanted.
208
+ runnerArgs: [${quirks}],`);
209
+ }
200
210
  const zephyrProbeBlock = zephyrFields.length > 0
201
211
  ? `
202
212
 
@@ -7,7 +7,7 @@ import { KNOWN_TARGETS } from "./scaffold.js";
7
7
  import { findPackBoard, packBoardAsTarget } from "./pack-targets.js";
8
8
  import { pickTarget } from "./board-search.js";
9
9
  import { activeBoardCatalog } from "../board-catalog/index.js";
10
- import { frameworksForTarget, frameworkCatalogEntry, frameworkCompatibleWithTarget, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard } from './framework-catalog.js';
10
+ import { frameworksForTarget, frameworkCatalogEntry, frameworkCompatibleWithTarget, FRAMEWORK_CATALOG, frameworkTargetProfile, probeMethodsForBoard, probeRunnerQuirks } from './framework-catalog.js';
11
11
  /**
12
12
  * Attached serial ports for the wizard's port question — dependency-free
13
13
  * (the wizard runs before any project deps exist, and cuttlefish itself
@@ -209,6 +209,10 @@ export async function runCreateWizard(partialOptions) {
209
209
  probeMethod = chosen === "" ? undefined : chosen;
210
210
  }
211
211
  }
212
+ // Board-catalog quirk for the chosen probe (e.g. an srst-based openocd.cfg
213
+ // behind a debug header with no NRST) — baked into the scaffolded
214
+ // config's runnerArgs so the first flash works.
215
+ const probeRunnerArgs = probeMethod ? probeRunnerQuirks(target.id, probeMethod) : [];
212
216
  // 4. Serial port (only for embedded) — the port the board rides on.
213
217
  // Detected ports are offered as a choice; the answer seeds test.port in
214
218
  // the scaffolded config (no more guessing COM4). "skip" leaves the
@@ -272,6 +276,7 @@ export async function runCreateWizard(partialOptions) {
272
276
  return {
273
277
  probeMethod,
274
278
  probeMethods,
279
+ ...(probeRunnerArgs.length > 0 ? { probeRunnerArgs } : {}),
275
280
  projectName,
276
281
  targetId: target.id,
277
282
  targetDisplayName: target.displayName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/cuttlefish",
3
- "version": "1.0.0-alpha.15",
3
+ "version": "1.0.0-alpha.16",
4
4
  "description": "TypeScript to C++ transpiler \u2014 native, Arduino, and bare-metal targets",
5
5
  "type": "module",
6
6
  "main": "./dist/transpile.js",
@@ -107,14 +107,14 @@
107
107
  "start": "node dist/cli.js"
108
108
  },
109
109
  "dependencies": {
110
- "@typecad/hal": "1.0.0-alpha.15",
110
+ "@typecad/hal": "1.0.0-alpha.16",
111
111
  "chalk": "^6.0.0",
112
112
  "inquirer-select-pro": "^1.0.0-alpha.9",
113
113
  "typescript": "^5.7.3",
114
114
  "zod": "^4.4.3"
115
115
  },
116
116
  "peerDependencies": {
117
- "@typecad/ui": "1.0.0-alpha.15"
117
+ "@typecad/ui": "1.0.0-alpha.16"
118
118
  },
119
119
  "peerDependenciesMeta": {
120
120
  "@typecad/ui": {
@@ -122,7 +122,7 @@
122
122
  }
123
123
  },
124
124
  "optionalDependencies": {
125
- "@typecad/expect": "1.0.0-alpha.15"
125
+ "@typecad/expect": "1.0.0-alpha.16"
126
126
  },
127
127
  "devDependencies": {
128
128
  "@types/node": "^22.10.7"