@typecad/cuttlefish 1.0.0-alpha.8 → 1.0.0-alpha.9

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
@@ -4,6 +4,7 @@ import fs from "node:fs";
4
4
  import { parseCommandLine, printHelp } from "./utils/cli.js";
5
5
  import { scaffoldProject, printInitNextSteps, KNOWN_TARGETS } from "./create/index.js";
6
6
  import { runInitWizard } from "./create/index.js";
7
+ import { handleInstall } from "./install/index.js";
7
8
  import { generateLibraryDefinitions, transpileFile } from "./transpile.js";
8
9
  import { generateDecl, generateDeclsForDirectory, generateComponentDeclsForProject } from "./libdef/cpp-to-decl.js";
9
10
  import { mapCppLocationToTs, readSourceMap, resolveMapPath } from "./mapping/source-map.js";
@@ -151,6 +152,10 @@ async function main() {
151
152
  await handleBoardAdd(options);
152
153
  return;
153
154
  }
155
+ if (options.command === "install") {
156
+ await handleInstall(options);
157
+ return;
158
+ }
154
159
  if (options.command === "preview") {
155
160
  await runPreviewServer({
156
161
  configPath: options.configPath,
@@ -119,7 +119,7 @@ export async function runInitWizard(partialOptions) {
119
119
  // rather than produce a broken scaffold with an empty framework field
120
120
  // (which would generate invalid package.json + cuttlefish.config.ts).
121
121
  throw new Error("No @typecad/framework-* packages found in this project. " +
122
- "Install one before scaffolding, e.g.: npm i @typecad/framework-arduino");
122
+ "Run 'cuttlefish install' to add one (e.g. 'cuttlefish install arduino').");
123
123
  }
124
124
  else if (frameworkOptions.length === 1) {
125
125
  framework = frameworkOptions[0].value;
@@ -0,0 +1,53 @@
1
+ /** A framework family that ships as an installable @typecad/framework-* package. */
2
+ export interface FrameworkCatalogEntry {
3
+ /** Short id, e.g. "arduino". Matches the suffix of @typecad/framework-<id>. */
4
+ id: string;
5
+ /** Full npm package name, e.g. "@typecad/framework-arduino". */
6
+ packageName: string;
7
+ /** Human-readable label shown in the install prompt. */
8
+ label: string;
9
+ /**
10
+ * Whether a real package exists on the registry. Used to filter the prompt:
11
+ * "esp-idf" is a known family with no published package yet, so it must not
12
+ * be offered for install (it would fail at the package-manager step).
13
+ */
14
+ installable: boolean;
15
+ }
16
+ /**
17
+ * The installable frameworks. Kept aligned with the packages/ directory:
18
+ * framework-arduino, framework-native, framework-zephyr all ship real packages.
19
+ * esp-idf is intentionally absent (no published package in this repo).
20
+ */
21
+ export declare const FRAMEWORK_CATALOG: readonly FrameworkCatalogEntry[];
22
+ /** Structural shape we need from a board/target. Keeps this module decoupled
23
+ * from the create/ module's KnownTarget (and trivially testable with literals). */
24
+ export interface BoardLike {
25
+ isNative?: boolean;
26
+ architecture?: string;
27
+ }
28
+ /** Look up a catalog entry by framework id (e.g. "arduino"). */
29
+ export declare function frameworkCatalogEntry(id: string): FrameworkCatalogEntry | undefined;
30
+ /**
31
+ * The framework ids compatible with a board. Native boards map to ["native"];
32
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
33
+ * unknown architectures). Order is preserved as the catalog order so the most
34
+ * common framework is offered first in the prompt.
35
+ */
36
+ export declare function frameworksForTarget(target: BoardLike): FrameworkCatalogEntry[];
37
+ export type PackageManager = "npm" | "pnpm" | "yarn";
38
+ /**
39
+ * Detect the package manager for a directory. Priority:
40
+ * 1. package.json#packageManager field (the strongest signal, Corepack-style)
41
+ * 2. lockfile presence (pnpm-lock.yaml / yarn.lock → otherwise npm)
42
+ * 3. default "npm"
43
+ * Never throws — unreadable/missing files fall through to the next signal.
44
+ */
45
+ export declare function detectPackageManager(cwd: string): PackageManager;
46
+ /**
47
+ * Build the package-manager invocation that installs `packageName` into the
48
+ * current project (project-local, never global — per the install command spec).
49
+ */
50
+ export declare function buildInstallCommand(pm: PackageManager, packageName: string): {
51
+ bin: string;
52
+ args: string[];
53
+ };
@@ -0,0 +1,107 @@
1
+ // Framework catalog + board→framework compatibility for `cuttlefish install`.
2
+ //
3
+ // A "framework" is a `@typecad/framework-<id>` npm package. This module is the
4
+ // single source of truth for which frameworks exist as installable packages and
5
+ // which are compatible with a given board architecture. It is deliberately
6
+ // free of side effects (no fs/process beyond lockfile/package.json reads in
7
+ // detectPackageManager) so it unit-tests cleanly.
8
+ import path from "node:path";
9
+ import fs from "node:fs";
10
+ /**
11
+ * The installable frameworks. Kept aligned with the packages/ directory:
12
+ * framework-arduino, framework-native, framework-zephyr all ship real packages.
13
+ * esp-idf is intentionally absent (no published package in this repo).
14
+ */
15
+ export const FRAMEWORK_CATALOG = [
16
+ { id: "arduino", packageName: "@typecad/framework-arduino", label: "Arduino (digitalWrite, Wire, SPI)", installable: true },
17
+ { id: "zephyr", packageName: "@typecad/framework-zephyr", label: "Zephyr RTOS", installable: true },
18
+ { id: "native", packageName: "@typecad/framework-native", label: "Native (Windows/Linux executable)", installable: true },
19
+ ];
20
+ /**
21
+ * Architecture → compatible framework ids. Derived from each framework
22
+ * package's framework.manifest.ts `profile.targets`:
23
+ * - arduino: avr, esp32 family, rp2040/rp2350, samd, stm32
24
+ * - zephyr: nrf52 (xiao_ble), esp32, esp32s3
25
+ * - native: desktop only
26
+ * Unknown embedded architectures fall back to [arduino] (the broadest core).
27
+ */
28
+ const ARCHITECTURE_FRAMEWORKS = {
29
+ avr: ["arduino"],
30
+ esp32: ["arduino", "zephyr"],
31
+ esp32s2: ["arduino"],
32
+ esp32s3: ["arduino", "zephyr"],
33
+ esp32c3: ["arduino"],
34
+ esp32c6: ["arduino"],
35
+ rp2040: ["arduino"],
36
+ rp2350: ["arduino"],
37
+ samd: ["arduino"],
38
+ stm32: ["arduino"],
39
+ nrf52: ["zephyr"],
40
+ };
41
+ const FALLBACK_FRAMEWORKS = ["arduino"];
42
+ /** Look up a catalog entry by framework id (e.g. "arduino"). */
43
+ export function frameworkCatalogEntry(id) {
44
+ return FRAMEWORK_CATALOG.find((f) => f.id === id);
45
+ }
46
+ /**
47
+ * The framework ids compatible with a board. Native boards map to ["native"];
48
+ * embedded boards map via ARCHITECTURE_FRAMEWORKS (falling back to arduino for
49
+ * unknown architectures). Order is preserved as the catalog order so the most
50
+ * common framework is offered first in the prompt.
51
+ */
52
+ export function frameworksForTarget(target) {
53
+ let ids;
54
+ if (target.isNative) {
55
+ ids = ["native"];
56
+ }
57
+ else {
58
+ ids = ARCHITECTURE_FRAMEWORKS[target.architecture ?? ""] ?? FALLBACK_FRAMEWORKS;
59
+ }
60
+ // Re-map ids → catalog entries in catalog order (stable ordering), dropping
61
+ // any id that has no catalog entry (defensive — keeps the prompt clean).
62
+ return FRAMEWORK_CATALOG.filter((entry) => ids.includes(entry.id));
63
+ }
64
+ /**
65
+ * Detect the package manager for a directory. Priority:
66
+ * 1. package.json#packageManager field (the strongest signal, Corepack-style)
67
+ * 2. lockfile presence (pnpm-lock.yaml / yarn.lock → otherwise npm)
68
+ * 3. default "npm"
69
+ * Never throws — unreadable/missing files fall through to the next signal.
70
+ */
71
+ export function detectPackageManager(cwd) {
72
+ try {
73
+ const pkgPath = path.join(cwd, "package.json");
74
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
75
+ const pm = typeof pkg.packageManager === "string" ? pkg.packageManager : "";
76
+ if (pm.startsWith("pnpm"))
77
+ return "pnpm";
78
+ if (pm.startsWith("yarn"))
79
+ return "yarn";
80
+ if (pm.startsWith("npm"))
81
+ return "npm";
82
+ }
83
+ catch {
84
+ // no package.json or unparseable JSON — fall through to lockfile detection
85
+ }
86
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml")))
87
+ return "pnpm";
88
+ if (fs.existsSync(path.join(cwd, "yarn.lock")))
89
+ return "yarn";
90
+ // package-lock.json implies npm; absence also defaults to npm.
91
+ return "npm";
92
+ }
93
+ /**
94
+ * Build the package-manager invocation that installs `packageName` into the
95
+ * current project (project-local, never global — per the install command spec).
96
+ */
97
+ export function buildInstallCommand(pm, packageName) {
98
+ switch (pm) {
99
+ case "pnpm":
100
+ return { bin: "pnpm", args: ["add", packageName] };
101
+ case "yarn":
102
+ return { bin: "yarn", args: ["add", packageName] };
103
+ case "npm":
104
+ default:
105
+ return { bin: "npm", args: ["install", packageName] };
106
+ }
107
+ }
@@ -0,0 +1,35 @@
1
+ import type { InstallCommandOptions } from "../types.js";
2
+ import { type FrameworkCatalogEntry, type PackageManager } from "./framework-catalog.js";
3
+ interface InstallCommand {
4
+ bin: string;
5
+ args: string[];
6
+ cwd: string;
7
+ }
8
+ interface InstallRunResult {
9
+ /** Exit status; null when the process could not be launched (ENOENT, etc.). */
10
+ status: number | null;
11
+ /** Populated only when the binary could not be launched. */
12
+ launchError?: string;
13
+ }
14
+ type InstallRunner = (cmd: InstallCommand) => InstallRunResult;
15
+ /**
16
+ * FOR TESTS ONLY. Replaces the real spawn-based installer with `runner`.
17
+ * Pass `undefined` to restore the real executor.
18
+ */
19
+ export declare function __setInstallRunnerForTest(runner: InstallRunner | undefined): void;
20
+ export interface InstallResult {
21
+ pm: PackageManager;
22
+ bin: string;
23
+ args: string[];
24
+ }
25
+ /**
26
+ * Resolve the package manager and run the install for `entry`'s package. In
27
+ * dry-run mode the command is printed but not executed. Throws on launch
28
+ * failure or non-zero exit so the CLI surfaces a clear error.
29
+ */
30
+ export declare function installFrameworkPackage(entry: FrameworkCatalogEntry, opts: {
31
+ cwd: string;
32
+ dryRun?: boolean;
33
+ }): InstallResult;
34
+ export declare function handleInstall(options: InstallCommandOptions): Promise<void>;
35
+ export {};
@@ -0,0 +1,177 @@
1
+ // `cuttlefish install` — installs a chosen @typecad/framework-* package into the
2
+ // current project. The flow asks which board to target first, then narrows the
3
+ // framework choices to those compatible with that board (see framework-catalog).
4
+ // A framework id may be passed directly (`cuttlefish install arduino`) to skip
5
+ // the prompts entirely, which also makes the command usable in CI.
6
+ import * as readline from "node:readline/promises";
7
+ import { stdin as input, stdout as output } from "node:process";
8
+ import { spawnSync } from "node:child_process";
9
+ import chalk from "chalk";
10
+ import { KNOWN_TARGETS } from "../create/index.js";
11
+ import { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
12
+ // ── prompts (mirror the create wizard's style for a consistent UX) ──────────
13
+ async function promptSelect(rl, prompt, options) {
14
+ console.log(`${chalk.cyan("?")} ${prompt}:`);
15
+ for (let i = 0; i < options.length; i++) {
16
+ console.log(` ${chalk.dim(`${i + 1})`)} ${options[i].label}`);
17
+ }
18
+ while (true) {
19
+ const answer = await rl.question(` Enter number (1-${options.length}): `);
20
+ const idx = parseInt(answer.trim(), 10) - 1;
21
+ if (idx >= 0 && idx < options.length) {
22
+ return options[idx].value;
23
+ }
24
+ console.log(` ${chalk.red("✗")} Please enter a number between 1 and ${options.length}.`);
25
+ }
26
+ }
27
+ async function selectBoardInteractively(rl) {
28
+ const options = KNOWN_TARGETS.map((t) => ({
29
+ label: t.isNative
30
+ ? `${t.displayName} (Windows/Linux executable)`
31
+ : `${t.displayName} (${t.architecture.toUpperCase()})`,
32
+ value: t.id,
33
+ }));
34
+ const selectedId = await promptSelect(rl, "Target board", options);
35
+ return KNOWN_TARGETS.find((t) => t.id === selectedId);
36
+ }
37
+ /**
38
+ * Pick a framework for `target`. When only one framework is compatible with the
39
+ * board it is auto-selected (mirrors the create wizard's single-option path) so
40
+ * the user isn't asked a question with one answer.
41
+ */
42
+ async function selectFrameworkInteractively(rl, target, compatible) {
43
+ if (compatible.length === 1) {
44
+ const only = compatible[0];
45
+ console.log(`${chalk.cyan("?")} Framework: ${chalk.white(only.label)} ${chalk.dim(`(only option for ${target.id})`)}`);
46
+ return only;
47
+ }
48
+ const selectedId = await promptSelect(rl, "Framework", compatible.map((f) => ({ label: f.label, value: f.id })));
49
+ return compatible.find((f) => f.id === selectedId);
50
+ }
51
+ let testRunner;
52
+ /**
53
+ * FOR TESTS ONLY. Replaces the real spawn-based installer with `runner`.
54
+ * Pass `undefined` to restore the real executor.
55
+ */
56
+ export function __setInstallRunnerForTest(runner) {
57
+ testRunner = runner;
58
+ }
59
+ function runRealInstall(cmd) {
60
+ // stdio: "inherit" streams the package manager's own output to the terminal
61
+ // (install progress, deprecation warnings, etc.). On failure the user has
62
+ // already seen the details above, so we only need to report the exit code.
63
+ const result = spawnSync(cmd.bin, cmd.args, {
64
+ cwd: cmd.cwd,
65
+ stdio: "inherit",
66
+ });
67
+ if (result.error) {
68
+ const errno = result.error.code;
69
+ return {
70
+ status: null,
71
+ launchError: errno === "ENOENT" ? `'${cmd.bin}' not found on PATH` : String(result.error),
72
+ };
73
+ }
74
+ return { status: result.status };
75
+ }
76
+ /**
77
+ * Resolve the package manager and run the install for `entry`'s package. In
78
+ * dry-run mode the command is printed but not executed. Throws on launch
79
+ * failure or non-zero exit so the CLI surfaces a clear error.
80
+ */
81
+ export function installFrameworkPackage(entry, opts) {
82
+ const pm = detectPackageManager(opts.cwd);
83
+ const { bin, args } = buildInstallCommand(pm, entry.packageName);
84
+ if (opts.dryRun) {
85
+ console.log(`${chalk.cyan("$")} ${bin} ${args.join(" ")}`);
86
+ return { pm, bin, args };
87
+ }
88
+ const cmd = { bin, args, cwd: opts.cwd };
89
+ const run = testRunner ?? runRealInstall;
90
+ const result = run(cmd);
91
+ if (result.launchError) {
92
+ throw new Error(`Failed to run '${bin}': ${result.launchError}`);
93
+ }
94
+ if (result.status !== 0) {
95
+ throw new Error(`'${bin} ${args.join(" ")}' exited with code ${result.status}. See the package manager output above for details.`);
96
+ }
97
+ return { pm, bin, args };
98
+ }
99
+ // ── command entry point ─────────────────────────────────────────────────────
100
+ export async function handleInstall(options) {
101
+ const cwd = process.cwd();
102
+ // 1. Resolve which framework to install.
103
+ let entry;
104
+ if (options.framework) {
105
+ const resolved = frameworkCatalogEntry(options.framework);
106
+ if (!resolved) {
107
+ const available = FRAMEWORK_CATALOG.filter((f) => f.installable).map((f) => f.id).join(", ");
108
+ throw new Error(`Unknown framework '${options.framework}'. Available: ${available}`);
109
+ }
110
+ if (!resolved.installable) {
111
+ throw new Error(`Framework '${options.framework}' has no published package yet and cannot be installed.`);
112
+ }
113
+ entry = resolved;
114
+ console.log(`${chalk.cyan("?")} Framework: ${chalk.white(entry.label)}`);
115
+ }
116
+ else {
117
+ // Resolve the target board. --board skips the board prompt; otherwise the
118
+ // board is chosen interactively (which requires a TTY — handled below).
119
+ let target;
120
+ if (options.board) {
121
+ const found = KNOWN_TARGETS.find((t) => t.id === options.board);
122
+ if (!found) {
123
+ const available = KNOWN_TARGETS.map((t) => t.id).join(", ");
124
+ throw new Error(`Unknown board '${options.board}'. Available: ${available}`);
125
+ }
126
+ target = found;
127
+ console.log(`${chalk.cyan("?")} Board: ${chalk.white(target.displayName)} (${chalk.dim(target.id)})`);
128
+ }
129
+ // Narrow to the frameworks compatible with that board.
130
+ let compatible;
131
+ if (target) {
132
+ compatible = frameworksForTarget(target).filter((f) => f.installable);
133
+ if (compatible.length === 0) {
134
+ throw new Error(`No installable frameworks are compatible with board '${target.id}'.`);
135
+ }
136
+ }
137
+ if (compatible && compatible.length === 1) {
138
+ // Only one framework fits this board — auto-select it (no prompt, so this
139
+ // path also works under CI / non-interactive stdin).
140
+ entry = compatible[0];
141
+ console.log(`${chalk.cyan("?")} Framework: ${chalk.white(entry.label)} ${chalk.dim(`(only option for ${target.id})`)}`);
142
+ }
143
+ else {
144
+ // Need to prompt — for the board (if --board wasn't given) and/or for the
145
+ // framework (when 2+ are compatible). Refuse to hang on a readline that
146
+ // can't be answered (e.g. piped stdin under CI).
147
+ if (!process.stdin.isTTY) {
148
+ throw new Error("No framework specified and stdin is not interactive. " +
149
+ "Pass a framework id (e.g. 'cuttlefish install arduino'), " +
150
+ "or a board with a single compatible framework (e.g. '--board arduino-uno').");
151
+ }
152
+ const rl = readline.createInterface({ input, output });
153
+ try {
154
+ if (!target) {
155
+ target = await selectBoardInteractively(rl);
156
+ compatible = frameworksForTarget(target).filter((f) => f.installable);
157
+ if (compatible.length === 0) {
158
+ throw new Error(`No installable frameworks are compatible with board '${target.id}'.`);
159
+ }
160
+ }
161
+ entry = await selectFrameworkInteractively(rl, target, compatible);
162
+ }
163
+ finally {
164
+ rl.close();
165
+ }
166
+ }
167
+ }
168
+ // 2. Install it.
169
+ console.log(`\n${chalk.cyan("⤳")} Installing ${chalk.white(entry.packageName)} into ${chalk.dim(cwd)}…`);
170
+ const result = installFrameworkPackage(entry, { cwd, dryRun: options.dryRun });
171
+ if (options.dryRun) {
172
+ console.log(chalk.dim("(dry-run — nothing was installed)"));
173
+ return;
174
+ }
175
+ console.log(`\n${chalk.green("✓")} Installed ${chalk.white(entry.packageName)} via ${result.pm}.`);
176
+ console.log(chalk.dim(`Next: run 'cuttlefish create' and pick ${entry.id}, or set framework: "${entry.packageName}" in cuttlefish.config.ts.`));
177
+ }
@@ -0,0 +1,4 @@
1
+ export { handleInstall, installFrameworkPackage, __setInstallRunnerForTest } from "./handle-install.js";
2
+ export type { InstallResult } from "./handle-install.js";
3
+ export { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
4
+ export type { FrameworkCatalogEntry, BoardLike, PackageManager, } from "./framework-catalog.js";
@@ -0,0 +1,3 @@
1
+ // `cuttlefish install` command — install a @typecad/framework-* package.
2
+ export { handleInstall, installFrameworkPackage, __setInstallRunnerForTest } from "./handle-install.js";
3
+ export { FRAMEWORK_CATALOG, frameworkCatalogEntry, frameworksForTarget, detectPackageManager, buildInstallCommand, } from "./framework-catalog.js";
package/dist/types.d.ts CHANGED
@@ -231,4 +231,13 @@ export interface BoardAddCommandOptions {
231
231
  specPath: string;
232
232
  force?: boolean;
233
233
  }
234
+ export interface InstallCommandOptions {
235
+ command: "install";
236
+ /** Framework id to install directly (e.g. "arduino"), skipping the prompts. */
237
+ framework?: string;
238
+ /** Board/target id to narrow framework choices (e.g. "esp32-devkit"). */
239
+ board?: string;
240
+ /** Resolve and print the package-manager command without running it. */
241
+ dryRun?: boolean;
242
+ }
234
243
  export {};
@@ -1,3 +1,3 @@
1
- import { CommandLineOptions, CreateCommandOptions, BoardAddCommandOptions } from "../types.js";
1
+ import { CommandLineOptions, CreateCommandOptions, BoardAddCommandOptions, InstallCommandOptions } from "../types.js";
2
2
  export declare function printHelp(): void;
3
- export declare function parseCommandLine(argv: string[]): CommandLineOptions | CreateCommandOptions | BoardAddCommandOptions | "help";
3
+ export declare function parseCommandLine(argv: string[]): CommandLineOptions | CreateCommandOptions | BoardAddCommandOptions | InstallCommandOptions | "help";
package/dist/utils/cli.js CHANGED
@@ -11,6 +11,7 @@ export function printHelp() {
11
11
  console.log();
12
12
  console.log(` cuttlefish <input.ts> [options]`);
13
13
  console.log(` cuttlefish create [name] [options]`);
14
+ console.log(` cuttlefish install [framework] [--board id] Install a @typecad/framework-* package (asks board, then narrows frameworks)`);
14
15
  console.log(` cuttlefish build [options]`);
15
16
  console.log(` cuttlefish preview [--config <path>] [--port <port>]`);
16
17
  console.log(` cuttlefish gen-libdefs <input.ts>`);
@@ -357,6 +358,22 @@ export function parseCommandLine(argv) {
357
358
  outDir: outDir ? path.resolve(process.cwd(), outDir) : undefined,
358
359
  };
359
360
  }
361
+ // install subcommand — install a @typecad/framework-* package. A framework id
362
+ // may be passed positionally (`cuttlefish install arduino`) or via --framework;
363
+ // --board narrows the interactive framework prompt to that board's options.
364
+ if (firstArg === "install") {
365
+ const secondArg = argv[3];
366
+ const positionalFramework = secondArg && !secondArg.startsWith("-") ? secondArg : undefined;
367
+ const framework = positionalFramework ?? readFirstFlagValue(argv, ["--framework", "-f"]);
368
+ const board = readFirstFlagValue(argv, ["--board", "-b"]);
369
+ const dryRun = argv.includes("--dry-run");
370
+ return {
371
+ command: "install",
372
+ framework,
373
+ board,
374
+ dryRun,
375
+ };
376
+ }
360
377
  if (firstArg === "create-board") {
361
378
  throw new Error(`The 'create-board' command has been removed. Board scaffolding is now in @typecad/create.`);
362
379
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/cuttlefish",
3
- "version": "1.0.0-alpha.8",
3
+ "version": "1.0.0-alpha.9",
4
4
  "description": "TypeScript to C++ transpiler — native, Arduino, and bare-metal targets",
5
5
  "type": "module",
6
6
  "main": "./dist/transpile.js",
@@ -99,8 +99,8 @@
99
99
  "zod": "^3.24.0"
100
100
  },
101
101
  "peerDependencies": {
102
- "@typecad/ui": "1.0.0-alpha.8",
103
- "@typecad/safety": "1.0.0-alpha.8"
102
+ "@typecad/ui": "1.0.0-alpha.9",
103
+ "@typecad/safety": "1.0.0-alpha.9"
104
104
  },
105
105
  "peerDependenciesMeta": {
106
106
  "@typecad/ui": {
@@ -111,7 +111,7 @@
111
111
  }
112
112
  },
113
113
  "optionalDependencies": {
114
- "@typecad/framework-native": "1.0.0-alpha.8"
114
+ "@typecad/framework-native": "1.0.0-alpha.9"
115
115
  },
116
116
  "devDependencies": {
117
117
  "@types/node": "^22.10.7"