@typecad/cuttlefish 1.0.0-alpha.12 → 1.0.0-alpha.13

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.
Files changed (54) hide show
  1. package/dist/add-preset.d.ts +4 -0
  2. package/dist/add-preset.js +74 -0
  3. package/dist/api/config.d.ts +0 -4
  4. package/dist/api/shared/display-adapters/sdl.js +1 -1
  5. package/dist/api/shared/display-profile.d.ts +11 -0
  6. package/dist/api/shared/display-profile.js +3 -0
  7. package/dist/api/shared/hal-op-ir.d.ts +19 -0
  8. package/dist/api/shared/toolchain-types.d.ts +0 -1
  9. package/dist/cli.js +15 -4
  10. package/dist/config-loader.d.ts +0 -2
  11. package/dist/config-loader.js +10 -5
  12. package/dist/config-schema.d.ts +87 -94
  13. package/dist/config-schema.js +0 -3
  14. package/dist/create/debug-artifacts.d.ts +20 -0
  15. package/dist/create/debug-artifacts.js +69 -0
  16. package/dist/create/index.d.ts +2 -0
  17. package/dist/create/index.js +1 -0
  18. package/dist/create/init-scaffold.d.ts +1 -0
  19. package/dist/create/init-scaffold.js +5 -0
  20. package/dist/create/init-templates.js +0 -2
  21. package/dist/emit/compliance/rules.js +18 -4
  22. package/dist/emit/emitters/function-emitter-impl.js +7 -1
  23. package/dist/emit/emitters/line-appender.js +6 -0
  24. package/dist/emit/emitters/ui-emitter.js +40 -15
  25. package/dist/emit/route-hal-op.js +55 -1
  26. package/dist/emit/statement-renderer.js +5 -2
  27. package/dist/ir/build-ir.js +22 -1
  28. package/dist/ir/expression-to-ir.js +17 -0
  29. package/dist/ir/hal/hal-emitter.js +23 -5
  30. package/dist/ir/hal/hal-plugins.js +11 -0
  31. package/dist/ir/pin-mode-validation.js +32 -9
  32. package/dist/ir/pin-state-tracking.d.ts +58 -0
  33. package/dist/ir/pin-state-tracking.js +182 -0
  34. package/dist/ir/program-analysis.d.ts +6 -0
  35. package/dist/ir/program-analysis.js +38 -0
  36. package/dist/ir/statement-to-ir.js +14 -0
  37. package/dist/ir/transformers/control-flow.js +29 -0
  38. package/dist/ir/transformers/ui-call-resolver.js +105 -1
  39. package/dist/ir/ui-element-auto-wire.js +7 -4
  40. package/dist/orchestrator/graph-builder.d.ts +4 -1
  41. package/dist/orchestrator/graph-builder.js +7 -1
  42. package/dist/preview/api-shared-shim.d.ts +1 -0
  43. package/dist/preview/api-shared-shim.js +7 -0
  44. package/dist/preview/client.js +220 -1
  45. package/dist/preview/server.js +154 -62
  46. package/dist/theme-tokens.d.ts +22 -0
  47. package/dist/theme-tokens.js +172 -0
  48. package/dist/transpile.js +35 -5
  49. package/dist/types.d.ts +5 -0
  50. package/dist/ui-hook.d.ts +7 -0
  51. package/dist/utils/cli.js +9 -0
  52. package/dist/utils/ui.d.ts +5 -0
  53. package/dist/utils/ui.js +7 -0
  54. package/package.json +7 -6
@@ -0,0 +1,172 @@
1
+ // ---------------------------------------------------------------------------
2
+ // shadcn kit themes — the included token sets under assets/shadcn/themes/.
3
+ //
4
+ // A theme file is two CSS blocks (:root = light tokens, .dark = dark tokens)
5
+ // plus an optional header comment. Selecting a theme MERGES each block into
6
+ // the kit's stylesheet: declarations the theme defines override the kit's,
7
+ // and kit-specific extras the theme lacks (notably --destructive-background,
8
+ // which stock shadcn themes don't carry) keep their current values — so any
9
+ // stock theme from ui.shadcn.com or tweakcn pastes cleanly.
10
+ //
11
+ // Used by `cuttlefish add shadcn --theme <name>` (scaffold time) and
12
+ // `cuttlefish theme <name>` (swap an existing project's kit stylesheet).
13
+ // ---------------------------------------------------------------------------
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ const THEMES_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../assets/shadcn/themes");
18
+ /** The tokens the kit's recipes reference; every merged theme must cover them. */
19
+ const REQUIRED_TOKENS = [
20
+ "--background", "--foreground",
21
+ "--card", "--card-foreground",
22
+ "--primary", "--primary-foreground",
23
+ "--secondary", "--secondary-foreground",
24
+ "--muted", "--muted-foreground",
25
+ "--accent", "--accent-foreground",
26
+ "--destructive", "--destructive-foreground", "--destructive-background",
27
+ "--border", "--input", "--radius",
28
+ ];
29
+ /** Blank out /* … *​/ comment interiors (same length) so selector searches
30
+ * can't match inside a comment while byte offsets stay valid against the
31
+ * original text. The kit's header comment literally contains `.dark { ... }`
32
+ * as documentation — an unmasked search spliced tokens into the comment and
33
+ * left the real block untouched. */
34
+ function maskComments(css) {
35
+ return css.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length));
36
+ }
37
+ /** Locate `selector {` in css, skipping comment spans. Custom-property values
38
+ * contain no braces, so the block ends at the first `}` after the opening
39
+ * one. */
40
+ function blockRange(css, selector) {
41
+ const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
42
+ const m = new RegExp(escaped + "\\s*\\{").exec(maskComments(css));
43
+ if (!m)
44
+ return null;
45
+ const open = m.index + m[0].length;
46
+ const close = css.indexOf("}", open);
47
+ if (close < 0)
48
+ return null;
49
+ return { selStart: m.index, open, close };
50
+ }
51
+ /** Parse a token block's declarations (line-oriented; one decl per line, the
52
+ * format both the kit and stock shadcn themes use). */
53
+ function parseDecls(block) {
54
+ const out = [];
55
+ for (const line of block.split("\n")) {
56
+ const m = /^\s*(--[\w-]+)\s*:\s*([^;]+);/.exec(line);
57
+ if (m)
58
+ out.push([m[1], m[2].trim()]);
59
+ }
60
+ return out;
61
+ }
62
+ function emitBlock(selector, decls) {
63
+ const body = decls.map(([k, v]) => ` ${k}: ${v};`).join("\n");
64
+ return `${selector} {\n${body}\n}`;
65
+ }
66
+ /** Order-preserving override merge: base order, overrides in place, theme-only
67
+ * declarations appended. */
68
+ function mergeDecls(base, override) {
69
+ const out = base.map(([k, v]) => [k, v]);
70
+ const indexByName = new Map(out.map(([k], i) => [k, i]));
71
+ for (const [k, v] of override) {
72
+ const existing = indexByName.get(k);
73
+ if (existing !== undefined)
74
+ out[existing][1] = v;
75
+ else {
76
+ indexByName.set(k, out.length);
77
+ out.push([k, v]);
78
+ }
79
+ }
80
+ return out;
81
+ }
82
+ /** Where a project keeps its own themes: src/styles/themes/*.css next to
83
+ * the kit stylesheet. Project themes win over same-named package ones —
84
+ * pasting a theme is dropping a file into YOUR project, never node_modules. */
85
+ export function projectThemesDir(projectRoot) {
86
+ return path.resolve(projectRoot, "src/styles/themes");
87
+ }
88
+ function themeNamesIn(dir) {
89
+ if (!fs.existsSync(dir))
90
+ return [];
91
+ return fs.readdirSync(dir)
92
+ .filter((f) => f.endsWith(".css") && !f.startsWith("_"))
93
+ .map((f) => f.replace(/\.css$/, ""))
94
+ .sort();
95
+ }
96
+ /** Theme names, project-local (src/styles/themes/) first, then the ones
97
+ * shipped in the package (assets/shadcn/themes/). */
98
+ export function listShadcnThemes(projectRoot) {
99
+ const local = projectRoot ? themeNamesIn(projectThemesDir(projectRoot)) : [];
100
+ const included = themeNamesIn(THEMES_DIR);
101
+ return [...new Set([...local, ...included])].sort();
102
+ }
103
+ function formatThemeList(projectRoot) {
104
+ const local = projectRoot ? themeNamesIn(projectThemesDir(projectRoot)) : [];
105
+ const included = themeNamesIn(THEMES_DIR);
106
+ const lines = [];
107
+ if (local.length > 0) {
108
+ lines.push("project (src/styles/themes/):");
109
+ for (const n of local)
110
+ lines.push(` ${n}`);
111
+ }
112
+ lines.push("included with cuttlefish:");
113
+ for (const n of included)
114
+ lines.push(` ${n}`);
115
+ lines.push("(paste your own: src/styles/themes/<name>.css in this project)");
116
+ return lines.join("\n");
117
+ }
118
+ /** Load a theme by name — project-local directory first, then the package
119
+ * included set. Throws with the available names when missing. */
120
+ export function loadShadcnTheme(name, projectRoot) {
121
+ if (!/^[a-z0-9-]+$/.test(name)) {
122
+ throw new Error(`Invalid theme name "${name}" — use letters, digits, and dashes.`);
123
+ }
124
+ const candidates = projectRoot
125
+ ? [path.join(projectThemesDir(projectRoot), `${name}.css`), path.join(THEMES_DIR, `${name}.css`)]
126
+ : [path.join(THEMES_DIR, `${name}.css`)];
127
+ const file = candidates.find((c) => fs.existsSync(c));
128
+ if (!file) {
129
+ throw new Error(`Unknown theme "${name}". Available themes:\n${formatThemeList(projectRoot)}`);
130
+ }
131
+ const text = fs.readFileSync(file, "utf-8");
132
+ const rootRange = blockRange(text, ":root");
133
+ const darkRange = blockRange(text, ".dark");
134
+ if (!rootRange || !darkRange) {
135
+ throw new Error(`Theme "${name}" must define both a :root and a .dark token block.`);
136
+ }
137
+ const light = parseDecls(text.slice(rootRange.open, rootRange.close));
138
+ const dark = parseDecls(text.slice(darkRange.open, darkRange.close));
139
+ if (light.length === 0 || dark.length === 0) {
140
+ throw new Error(`Theme "${name}" has empty token blocks — paste the theme's :root and .dark declarations.`);
141
+ }
142
+ return { name, light, dark };
143
+ }
144
+ /** Merge a theme's tokens into a kit stylesheet's :root/.dark blocks and
145
+ * return the rewritten text. Throws when a merged block is missing any
146
+ * token the kit's recipes reference. */
147
+ export function applyShadcnTheme(cssText, theme) {
148
+ let out = cssText;
149
+ for (const [selector, themeDecls] of [[".dark", theme.dark], [":root", theme.light]]) {
150
+ const range = blockRange(out, selector);
151
+ if (!range) {
152
+ throw new Error(`The kit stylesheet has no ${selector} token block to replace.`);
153
+ }
154
+ const merged = mergeDecls(parseDecls(out.slice(range.open, range.close)), themeDecls);
155
+ out = out.slice(0, range.selStart) + emitBlock(selector, merged) + out.slice(range.close + 1);
156
+ }
157
+ // Validate AFTER both merges (a token can live in either block).
158
+ const rootRange = blockRange(out, ":root");
159
+ const darkRange = blockRange(out, ".dark");
160
+ const names = new Set();
161
+ if (rootRange)
162
+ for (const [k] of parseDecls(out.slice(rootRange.open, rootRange.close)))
163
+ names.add(k);
164
+ if (darkRange)
165
+ for (const [k] of parseDecls(out.slice(darkRange.open, darkRange.close)))
166
+ names.add(k);
167
+ const missing = REQUIRED_TOKENS.filter((t) => !names.has(t));
168
+ if (missing.length > 0) {
169
+ throw new Error(`Theme "${theme.name}" leaves required tokens unset: ${missing.join(", ")}`);
170
+ }
171
+ return out;
172
+ }
package/dist/transpile.js CHANGED
@@ -26,11 +26,12 @@ import { requireUIHook, hasUIHook } from "./ui-hook.js";
26
26
  import { loadUIEngine } from "./ui/ui-bridge.js";
27
27
  import { hasSafetyHook, requireSafetyHook } from "./safety-hook.js";
28
28
  import { loadSafetyEngine } from "./safety/safety-bridge.js";
29
- import { setDisplayProfile, resetDisplayProfile } from "./stores/display-profile-store.js";
29
+ import { setDisplayProfile, resetDisplayProfile, getDisplayProfile } from "./stores/display-profile-store.js";
30
30
  import { setThemeCss, resetThemeCss, setThemeClass } from "./stores/theme-store.js";
31
31
  import { emitCpp, registerAllEnumNames } from "./emit/cpp-emitter.js";
32
32
  import { readText, writeText, resetWrittenFiles, wasWrittenThisRun } from "./utils/fs.js";
33
33
  import { debug as logDebug, info } from "./utils/logger.js";
34
+ import { printDebugStrategy } from "./utils/ui.js";
34
35
  import { loadLibraryDefinitions, generateLibdefStubs } from "./libdef/registry.js";
35
36
  import { buildCallGraph } from "./ir/call-graph.js";
36
37
  import { clearCaches, } from "./cache.js";
@@ -201,6 +202,15 @@ import { loadFrameworkPackage } from "./framework-package.js";
201
202
  export { loadFrameworkPackage };
202
203
  export { getLoadedFramework, hasLoadedFramework } from "./framework-registry.js";
203
204
  import { getLoadedFramework, hasLoadedFramework } from "./framework-registry.js";
205
+ /** Under --strict-css, UI CSS-compatibility warnings (code css-*: ignored
206
+ * alpha, quantized font sizes, unsupported display/position values, ...) are
207
+ * upgraded to errors so the build fails instead of approximating silently. */
208
+ function upgradeStrictCss(d, strict) {
209
+ if (strict && d.severity === "warning" && typeof d.code === "string" && d.code.startsWith("css-")) {
210
+ return { ...d, severity: "error" };
211
+ }
212
+ return d;
213
+ }
204
214
  function formatFatalDiagnostics(entries) {
205
215
  const errors = entries.filter(({ diagnostic }) => diagnostic.severity === "error");
206
216
  const lines = [
@@ -260,7 +270,11 @@ function loadPlatformStrategy(frameworkPackage, _boardPackage, fromDir, debug) {
260
270
  if (hasLoadedFramework()) {
261
271
  const { strategy } = getLoadedFramework();
262
272
  if (debug) {
263
- logDebug(`Loaded FrameworkStrategy from ${frameworkPackage}`, true);
273
+ // Styled like the other step lines (cyan ⇉) says what the debug
274
+ // build is actually doing, in user terms. Falls back to the package
275
+ // name when the strategy carries no id.
276
+ const frameworkName = strategy.id || frameworkPackage.replace(/^@typecad\/framework-/, "");
277
+ printDebugStrategy(frameworkName);
264
278
  }
265
279
  return strategy;
266
280
  }
@@ -351,7 +365,19 @@ export async function transpileFile(options) {
351
365
  // see incremental-cache.ts — so we always transpile the full graph.)
352
366
  cleanOutput(entryDir, outDir);
353
367
  profiler.startTimer("graph:collect");
354
- const graphResult = collectTranspileGraph(entryFile, options.boardPackage);
368
+ // Image-conversion cap: never decode larger than the physical panel —
369
+ // converted <img> assets downscale to fit (no 24MB C arrays from photos).
370
+ const imageDecodeMax = await (async () => {
371
+ try {
372
+ const { effectiveDisplaySize } = await import("./api/shared/display-profile.js");
373
+ const size = effectiveDisplaySize(getDisplayProfile());
374
+ return { maxW: size.width, maxH: size.height };
375
+ }
376
+ catch {
377
+ return {};
378
+ }
379
+ })();
380
+ const graphResult = await collectTranspileGraph(entryFile, options.boardPackage, imageDecodeMax);
355
381
  profiler.endTimer("graph:collect");
356
382
  const transpileFiles = graphResult.files;
357
383
  // ── Type-check all files before transpiling ────────────────────────────────
@@ -449,10 +475,12 @@ export async function transpileFile(options) {
449
475
  // parser warnings (unknown CSS properties, unknown HTML tags) here so the
450
476
  // author sees typos and unsupported features instead of silent drops.
451
477
  // Guarded: @typecad/ui is optional, so there may be no UI engine loaded.
478
+ // --strict-css upgrades the css-* compatibility warnings to errors.
452
479
  if (hasUIHook()) {
453
480
  for (const mod of requireUIHook().allUIModules()) {
454
481
  for (const d of mod.diagnostics) {
455
- diagnostics.push({ ...d, filePath: d.filePath ?? path.basename(mod.htmlPath) });
482
+ const upgraded = upgradeStrictCss(d, options.strictCss);
483
+ diagnostics.push({ ...upgraded, filePath: d.filePath ?? path.basename(mod.htmlPath) });
456
484
  }
457
485
  }
458
486
  }
@@ -582,10 +610,12 @@ export async function transpileFile(options) {
582
610
  profiler.endTimer("ir:build-all");
583
611
  // ── UI mount-time warnings (scroll memory budget, etc.) ─────────────────
584
612
  // Guarded: @typecad/ui is optional; no engine means no UI modules.
613
+ // --strict-css upgrades the css-* compatibility warnings to errors.
585
614
  if (hasUIHook()) {
586
615
  for (const mod of requireUIHook().allUIModules()) {
587
616
  for (const d of mod.mountDiagnostics) {
588
- diagnostics.push({ ...d, filePath: d.filePath ?? path.basename(mod.htmlPath) });
617
+ const upgraded = upgradeStrictCss(d, options.strictCss);
618
+ diagnostics.push({ ...upgraded, filePath: d.filePath ?? path.basename(mod.htmlPath) });
589
619
  }
590
620
  }
591
621
  }
package/dist/types.d.ts CHANGED
@@ -100,6 +100,8 @@ export interface TranspileOptions {
100
100
  autosar?: ComplianceMode;
101
101
  /** When true (and autosar is warn/strict), also emit the .autosar-deviations.arxml sidecar. */
102
102
  autosarArxml?: boolean;
103
+ /** Upgrade UI CSS-compatibility warnings (css-* diagnostics) to errors. */
104
+ strictCss?: boolean;
103
105
  }
104
106
  export interface LibraryDefinitionCondition {
105
107
  target?: TargetProfile;
@@ -179,6 +181,8 @@ export interface CommandLineOptions {
179
181
  autosar?: ComplianceMode;
180
182
  /** When true (and autosar is warn/strict), also emit the .autosar-deviations.arxml sidecar. */
181
183
  autosarArxml?: boolean;
184
+ /** Upgrade UI CSS-compatibility warnings (css-* diagnostics) to errors. */
185
+ strictCss?: boolean;
182
186
  /** Config file for preview command */
183
187
  configPath?: string;
184
188
  /** Project root (dir of cuttlefish.config.ts); passed to transpileFile for the ESLint gate. */
@@ -188,6 +192,7 @@ export interface GenerateLibdefOptions {
188
192
  inputFile: string;
189
193
  outDir: string;
190
194
  }
195
+ /** `cuttlefish add <preset>` — scaffold a copy-and-own asset into the project. */
191
196
  export interface GeneratedOutputs {
192
197
  headerPath?: string;
193
198
  sourcePath: string;
package/dist/ui-hook.d.ts CHANGED
@@ -75,6 +75,13 @@ export interface TranspilerUIHook {
75
75
  nativeDisplayActive?: boolean;
76
76
  }): string;
77
77
  splitUiFile(src: string): UiFileParts;
78
+ /** Pre-decode src="…" image references (png/jpg/ico/…) into the RGB565
79
+ * asset cache. Must be awaited BEFORE loadUIModule/loadUIModuleFromText —
80
+ * the synchronous asset reader and natural-size layout read the cache. */
81
+ warmUpImageDecoding(sourceText: string, baseDir: string, opts?: {
82
+ maxW?: number;
83
+ maxH?: number;
84
+ }): Promise<void>;
78
85
  generateProjectUITypeDeclarations(projectRoot: string): {
79
86
  written: string[];
80
87
  errors: Array<{
package/dist/utils/cli.js CHANGED
@@ -49,6 +49,10 @@ export function printHelp() {
49
49
  console.log(` --autosar-arxml Also write <name>.autosar-deviations.arxml (Artop/DaVinci).`);
50
50
  console.log(` No-op unless --autosar is warn or strict.`);
51
51
  console.log();
52
+ console.log(` --strict-css Treat UI CSS-compatibility warnings as errors (css-*`);
53
+ console.log(` diagnostics: ignored alpha, quantized font sizes,`);
54
+ console.log(` unsupported display/position values, viewport-hogging sizes).`);
55
+ console.log();
52
56
  console.log(chalk.cyan(`BUILD COMMANDS`) + chalk.gray(` (chain in order: --compile → --upload → --monitor)`));
53
57
  console.log();
54
58
  console.log(` --compile Compile the generated output using the framework toolchain.`);
@@ -277,6 +281,10 @@ function parsePipelineCommand(argv, command, inputFile) {
277
281
  // --autosar-arxml: also write the .autosar-deviations.arxml sidecar
278
282
  // (Artop/DaVinci tooling). No-op unless --autosar is warn or strict.
279
283
  const autosarArxml = readBooleanFlag(argv, ["--autosar-arxml"]);
284
+ // --strict-css: upgrade UI CSS-compatibility warnings (css-* diagnostics,
285
+ // e.g. ignored alpha, quantized font sizes, unsupported display values) to
286
+ // errors so builds fail instead of silently approximating.
287
+ const strictCss = readBooleanFlag(argv, ["--strict-css"]);
280
288
  const emitMode = emitFlag === "cpp" || emitFlag === "split" ? emitFlag : "split";
281
289
  const emitMaps = emitMapsFlag === undefined ? true : emitMapsFlag !== "false";
282
290
  // Accept any target string — the framework package registers its own strategy id.
@@ -329,6 +337,7 @@ function parsePipelineCommand(argv, command, inputFile) {
329
337
  frameworkPackage: frameworkFlag,
330
338
  autosar,
331
339
  autosarArxml,
340
+ strictCss,
332
341
  };
333
342
  }
334
343
  export function parseCommandLine(argv) {
@@ -27,6 +27,11 @@ export declare function printTranspiling(): void;
27
27
  * Print compiling step
28
28
  */
29
29
  export declare function printCompiling(target: string): void;
30
+ /**
31
+ * Print the debug-session strategy notice (debug builds only): which
32
+ * framework's code-generation strategy is preparing the debug build.
33
+ */
34
+ export declare function printDebugStrategy(framework: string): void;
30
35
  /**
31
36
  * Print uploading step
32
37
  */
package/dist/utils/ui.js CHANGED
@@ -69,6 +69,13 @@ export function printTranspiling() {
69
69
  export function printCompiling(target) {
70
70
  console.log(chalk.cyan(`${ICON_COMPILE} Compiling for `) + chalk.white(target));
71
71
  }
72
+ /**
73
+ * Print the debug-session strategy notice (debug builds only): which
74
+ * framework's code-generation strategy is preparing the debug build.
75
+ */
76
+ export function printDebugStrategy(framework) {
77
+ console.log(chalk.cyan(`${ICON_COMPILE} Preparing to debug using `) + chalk.white(framework));
78
+ }
72
79
  /**
73
80
  * Print uploading step
74
81
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/cuttlefish",
3
- "version": "1.0.0-alpha.12",
3
+ "version": "1.0.0-alpha.13",
4
4
  "description": "TypeScript to C++ transpiler — native, Arduino, and bare-metal targets",
5
5
  "type": "module",
6
6
  "main": "./dist/transpile.js",
@@ -83,7 +83,8 @@
83
83
  }
84
84
  },
85
85
  "files": [
86
- "dist"
86
+ "dist",
87
+ "assets"
87
88
  ],
88
89
  "publishConfig": {
89
90
  "access": "public"
@@ -99,8 +100,8 @@
99
100
  "zod": "^3.24.0"
100
101
  },
101
102
  "peerDependencies": {
102
- "@typecad/ui": "1.0.0-alpha.12",
103
- "@typecad/safety": "1.0.0-alpha.12"
103
+ "@typecad/ui": "1.0.0-alpha.13",
104
+ "@typecad/safety": "1.0.0-alpha.13"
104
105
  },
105
106
  "peerDependenciesMeta": {
106
107
  "@typecad/ui": {
@@ -111,8 +112,8 @@
111
112
  }
112
113
  },
113
114
  "optionalDependencies": {
114
- "@typecad/expect": "1.0.0-alpha.12",
115
- "@typecad/framework-native": "1.0.0-alpha.12"
115
+ "@typecad/expect": "1.0.0-alpha.13",
116
+ "@typecad/framework-native": "1.0.0-alpha.13"
116
117
  },
117
118
  "devDependencies": {
118
119
  "@types/node": "^22.10.7"