@cascadetui/core 0.1.13 → 0.1.14

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/3d.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  __export,
7
7
  __require,
8
8
  __toESM
9
- } from "./index-kfh59ta6.js";
9
+ } from "./index-z2wm303h.js";
10
10
 
11
11
  // ../../node_modules/.bun/omggif@1.0.10/node_modules/omggif/omggif.js
12
12
  var require_omggif = __commonJS((exports) => {
@@ -10551,6 +10551,24 @@ registerEnvVar({
10551
10551
  type: "boolean",
10552
10552
  default: false
10553
10553
  });
10554
+ registerEnvVar({
10555
+ name: "CASCADE_FREEZE_THRESHOLD_MS",
10556
+ description: "Threshold in ms to detect a freeze (FFI call that blocks longer than this). Set to 0 to disable.",
10557
+ type: "number",
10558
+ default: 100
10559
+ });
10560
+ registerEnvVar({
10561
+ name: "CASCADE_FREEZE_STACK_DEPTH",
10562
+ description: "Number of stack frames to capture on freeze detection.",
10563
+ type: "number",
10564
+ default: 20
10565
+ });
10566
+ registerEnvVar({
10567
+ name: "CASCADE_FREEZE_MEMORY_SNAPSHOT",
10568
+ description: "Capture memory stats on freeze detection.",
10569
+ type: "boolean",
10570
+ default: true
10571
+ });
10554
10572
  registerEnvVar({
10555
10573
  name: "CASCADE_FORCE_WCWIDTH",
10556
10574
  description: "Use wcwidth for character width calculations",
@@ -10580,7 +10598,11 @@ var CURSOR_ID_TO_STYLE = ["block", "line", "underline"];
10580
10598
  var MOUSE_STYLE_TO_ID = { default: 0, pointer: 1, text: 2, crosshair: 3, move: 4, "not-allowed": 5 };
10581
10599
  var globalTraceSymbols = null;
10582
10600
  var globalFFILogWriter = null;
10601
+ var globalFreezeWriter = null;
10583
10602
  var exitHandlerRegistered = false;
10603
+ var freezeEvents = [];
10604
+ var recentCalls = [];
10605
+ var MAX_RECENT_CALLS = 50;
10584
10606
  function toPointer(value) {
10585
10607
  if (typeof value === "bigint") {
10586
10608
  if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
@@ -11621,6 +11643,92 @@ function convertToDebugSymbols(symbols) {
11621
11643
  `);
11622
11644
  slowWriter.write(buffer);
11623
11645
  };
11646
+ const freezeThresholdMs = typeof env.CASCADE_FREEZE_THRESHOLD_MS === "number" ? env.CASCADE_FREEZE_THRESHOLD_MS : 100;
11647
+ const freezeStackDepth = typeof env.CASCADE_FREEZE_STACK_DEPTH === "number" ? env.CASCADE_FREEZE_STACK_DEPTH : 20;
11648
+ const freezeMemorySnapshot = env.CASCADE_FREEZE_MEMORY_SNAPSHOT !== false;
11649
+ const captureStackTrace = () => {
11650
+ const stack = new Error().stack?.split(`
11651
+ `) || [];
11652
+ const frames = [];
11653
+ for (let i = 2;i < Math.min(stack.length, freezeStackDepth + 2); i++) {
11654
+ const line = stack[i]?.trim();
11655
+ if (line)
11656
+ frames.push(line);
11657
+ }
11658
+ return frames;
11659
+ };
11660
+ const captureFreezeEvent = (symbol, durationMs, args, result) => {
11661
+ const callChain = recentCalls.slice(-10).map((c) => `${c.symbol}(${c.duration.toFixed(2)}ms)`).reverse();
11662
+ return {
11663
+ timestamp: new Date().toISOString(),
11664
+ symbol,
11665
+ durationMs,
11666
+ thresholdMs: freezeThresholdMs,
11667
+ args,
11668
+ result,
11669
+ stackTrace: captureStackTrace(),
11670
+ memoryUsage: freezeMemorySnapshot ? process.memoryUsage() : null,
11671
+ cpuUsage: freezeMemorySnapshot ? process.cpuUsage() : null,
11672
+ callChain
11673
+ };
11674
+ };
11675
+ const writeFreezeEvent = (event) => {
11676
+ if (!globalFreezeWriter) {
11677
+ const now = new Date;
11678
+ const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
11679
+ const freezeFilePath = `ffi_cascade_freeze_${timestamp}.log`;
11680
+ globalFreezeWriter = Bun.file(freezeFilePath).writer();
11681
+ }
11682
+ const lines = [];
11683
+ lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
11684
+ lines.push("\u2551 FREEZE EVENT DETECTED \u2551");
11685
+ lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
11686
+ lines.push(``);
11687
+ lines.push(`Timestamp: ${event.timestamp}`);
11688
+ lines.push(`Symbol: ${event.symbol}`);
11689
+ lines.push(`Duration: ${event.durationMs.toFixed(3)}ms (threshold: ${event.thresholdMs}ms)`);
11690
+ lines.push(`Over threshold by: ${(event.durationMs - event.thresholdMs).toFixed(3)}ms`);
11691
+ lines.push(``);
11692
+ lines.push(`Arguments: ${event.args.slice(0, 500)}${event.args.length > 500 ? "..." : ""}`);
11693
+ lines.push(`Result: ${event.result.slice(0, 200)}${event.result.length > 200 ? "..." : ""}`);
11694
+ lines.push(``);
11695
+ lines.push(`--- CALL CHAIN (last 10 calls before freeze, most recent first) ---`);
11696
+ if (event.callChain.length > 0) {
11697
+ event.callChain.forEach((c, i) => lines.push(` ${i + 1}. ${c}`));
11698
+ } else {
11699
+ lines.push(` (no previous calls recorded)`);
11700
+ }
11701
+ lines.push(``);
11702
+ lines.push(`--- STACK TRACE (${event.stackTrace.length} frames) ---`);
11703
+ event.stackTrace.forEach((frame, i) => lines.push(` ${i + 1}. ${frame}`));
11704
+ lines.push(``);
11705
+ if (event.memoryUsage) {
11706
+ lines.push(`--- MEMORY SNAPSHOT ---`);
11707
+ lines.push(` RSS: ${(event.memoryUsage.rss / 1024 / 1024).toFixed(2)} MB`);
11708
+ lines.push(` Heap Total: ${(event.memoryUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
11709
+ lines.push(` Heap Used: ${(event.memoryUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
11710
+ lines.push(` External: ${(event.memoryUsage.external / 1024 / 1024).toFixed(2)} MB`);
11711
+ lines.push(` Array Buffers: ${(event.memoryUsage.arrayBuffers / 1024 / 1024).toFixed(2)} MB`);
11712
+ }
11713
+ if (event.cpuUsage) {
11714
+ lines.push(``);
11715
+ lines.push(`--- CPU USAGE ---`);
11716
+ lines.push(` User: ${(event.cpuUsage.user / 1000).toFixed(2)} ms`);
11717
+ lines.push(` System: ${(event.cpuUsage.system / 1000).toFixed(2)} ms`);
11718
+ }
11719
+ lines.push(``);
11720
+ lines.push(`================================================================================`);
11721
+ lines.push(``);
11722
+ const buffer = new TextEncoder().encode(lines.join(`
11723
+ `) + `
11724
+ `);
11725
+ globalFreezeWriter.write(buffer);
11726
+ globalFreezeWriter.flush();
11727
+ console.error(`
11728
+ [FREEZE DETECTED] ${event.symbol} blocked for ${event.durationMs.toFixed(2)}ms`);
11729
+ console.error(` See ffi_cascade_freeze_*.log for full details
11730
+ `);
11731
+ };
11624
11732
  const debugSymbols = {};
11625
11733
  let hasTracing = false;
11626
11734
  Object.entries(symbols).forEach(([key, value]) => {
@@ -11634,12 +11742,43 @@ function convertToDebugSymbols(symbols) {
11634
11742
  writer.write(buffer);
11635
11743
  writer.flush();
11636
11744
  };
11745
+ const getCallerInfo = () => {
11746
+ const stack = new Error().stack?.split(`
11747
+ `) || [];
11748
+ for (let i = 2;i < stack.length; i++) {
11749
+ const line = stack[i];
11750
+ if (line && !line.includes("zig.ts") && !line.includes("node:")) {
11751
+ const match = line.match(/at .+ \((.+):(\d+):(\d+)\)/) || line.match(/at (.+):(\d+):(\d+)/);
11752
+ if (match) {
11753
+ const [, file, lineNum] = match;
11754
+ const fileName = file?.split("/").pop() || file;
11755
+ return `${fileName}:${lineNum}`;
11756
+ }
11757
+ }
11758
+ }
11759
+ return "unknown";
11760
+ };
11637
11761
  Object.entries(symbols).forEach(([key, value]) => {
11638
11762
  if (typeof value === "function") {
11639
11763
  debugSymbols[key] = (...args) => {
11640
- writeSync(`${key}(${args.map((arg) => String(arg)).join(", ")})`);
11764
+ const timestamp = new Date().toISOString();
11765
+ const caller = getCallerInfo();
11766
+ const callId = Math.random().toString(36).slice(2, 8);
11767
+ const argStr = args.map(formatArg).join(", ");
11768
+ writeSync(`[${timestamp}] [CALL:${callId}] ${key}(${argStr}) <- ${caller}`);
11769
+ const start = performance.now();
11641
11770
  const result = value(...args);
11642
- writeSync(`${key} returned: ${String(result)}`);
11771
+ const duration = performance.now() - start;
11772
+ writeSync(`[${timestamp}] [RETN:${callId}] ${key} => ${formatArg(result)} | ${duration.toFixed(3)}ms`);
11773
+ recentCalls.push({ symbol: key, timestamp: start, duration });
11774
+ if (recentCalls.length > MAX_RECENT_CALLS) {
11775
+ recentCalls.shift();
11776
+ }
11777
+ if (freezeThresholdMs > 0 && duration >= freezeThresholdMs) {
11778
+ const event = captureFreezeEvent(key, duration, argStr, formatArg(result));
11779
+ freezeEvents.push(event);
11780
+ writeFreezeEvent(event);
11781
+ }
11643
11782
  return result;
11644
11783
  };
11645
11784
  }
@@ -11663,9 +11802,36 @@ function convertToDebugSymbols(symbols) {
11663
11802
  if (timings.length > maxSamples) {
11664
11803
  timings.splice(0, timings.length - maxSamples);
11665
11804
  }
11805
+ if (!env.CASCADE_DEBUG_FFI) {
11806
+ recentCalls.push({ symbol: key, timestamp: start, duration: dt });
11807
+ if (recentCalls.length > MAX_RECENT_CALLS) {
11808
+ recentCalls.shift();
11809
+ }
11810
+ }
11811
+ if (!env.CASCADE_DEBUG_FFI && freezeThresholdMs > 0 && dt >= freezeThresholdMs) {
11812
+ const argStr = args.map(formatArg).join(", ");
11813
+ const event = captureFreezeEvent(key, dt, argStr, formatArg(result));
11814
+ freezeEvents.push(event);
11815
+ writeFreezeEvent(event);
11816
+ }
11666
11817
  if (slowThresholdMs > 0 && dt >= slowThresholdMs) {
11667
11818
  const argStr = args.map(formatArg).join(", ");
11668
- writeSlow(`${new Date().toISOString()} ${key} ${dt.toFixed(2)}ms (${argStr})`);
11819
+ const callId = Math.random().toString(36).slice(2, 8);
11820
+ const stack = new Error().stack?.split(`
11821
+ `) || [];
11822
+ let caller = "unknown";
11823
+ for (let i = 2;i < stack.length; i++) {
11824
+ const line = stack[i];
11825
+ if (line && !line.includes("zig.ts") && !line.includes("node:")) {
11826
+ const match = line.match(/at .+ \((.+):(\d+):(\d+)\)/) || line.match(/at (.+):(\d+):(\d+)/);
11827
+ if (match) {
11828
+ const fileName = match[1]?.split("/").pop() || match[1];
11829
+ caller = `${fileName}:${match[2]}`;
11830
+ break;
11831
+ }
11832
+ }
11833
+ }
11834
+ writeSlow(`[${new Date().toISOString()}] [SLOW:${callId}] ${key}(${argStr}) <- ${caller} | ${dt.toFixed(3)}ms (threshold: ${slowThresholdMs}ms)`);
11669
11835
  }
11670
11836
  return result;
11671
11837
  };
@@ -11682,7 +11848,37 @@ function convertToDebugSymbols(symbols) {
11682
11848
  if (slowWriter) {
11683
11849
  slowWriter.end();
11684
11850
  }
11851
+ if (globalFreezeWriter) {
11852
+ globalFreezeWriter.end();
11853
+ }
11685
11854
  } catch (e) {}
11855
+ if (freezeEvents.length > 0) {
11856
+ const freezeSummary = [];
11857
+ freezeSummary.push("");
11858
+ freezeSummary.push("================================================================================");
11859
+ freezeSummary.push(" FREEZE EVENTS SUMMARY");
11860
+ freezeSummary.push("================================================================================");
11861
+ freezeSummary.push(`Total freezes detected: ${freezeEvents.length}`);
11862
+ freezeSummary.push(`Total time frozen: ${freezeEvents.reduce((sum, e) => sum + e.durationMs, 0).toFixed(2)}ms`);
11863
+ freezeSummary.push("");
11864
+ freezeSummary.push("Freezes by symbol:");
11865
+ const freezesBySymbol = {};
11866
+ for (const event of freezeEvents) {
11867
+ if (!freezesBySymbol[event.symbol]) {
11868
+ freezesBySymbol[event.symbol] = { count: 0, totalMs: 0 };
11869
+ }
11870
+ freezesBySymbol[event.symbol].count++;
11871
+ freezesBySymbol[event.symbol].totalMs += event.durationMs;
11872
+ }
11873
+ const sortedFreezes = Object.entries(freezesBySymbol).sort((a, b) => b[1].totalMs - a[1].totalMs);
11874
+ for (const [symbol, data] of sortedFreezes) {
11875
+ freezeSummary.push(` ${symbol.padEnd(30)} | ${String(data.count).padStart(3)} freezes | ${data.totalMs.toFixed(2).padStart(10)}ms`);
11876
+ }
11877
+ freezeSummary.push("--------------------------------------------------------------------------------");
11878
+ freezeSummary.push("");
11879
+ console.log(freezeSummary.join(`
11880
+ `));
11881
+ }
11686
11882
  if (globalTraceSymbols) {
11687
11883
  const allStats = [];
11688
11884
  for (const [key, timings] of Object.entries(globalTraceSymbols)) {
@@ -11715,10 +11911,20 @@ function convertToDebugSymbols(symbols) {
11715
11911
  }
11716
11912
  allStats.sort((a, b) => b.total - a.total);
11717
11913
  const lines = [];
11718
- lines.push(`
11719
- --- Cascade FFI Call Performance ---`);
11720
- lines.push("Sorted by total time spent (descending)");
11721
- lines.push("-------------------------------------------------------------------------------------------------------------------------");
11914
+ const now = new Date;
11915
+ const sessionStart = globalFFILogWriter ? "session start" : "unknown";
11916
+ lines.push("");
11917
+ lines.push("================================================================================");
11918
+ lines.push(" CASCADE FFI PERFORMANCE REPORT");
11919
+ lines.push("================================================================================");
11920
+ lines.push(`Generated: ${now.toISOString()}`);
11921
+ lines.push(`Session: ${sessionStart}`);
11922
+ lines.push(`Total symbols traced: ${allStats.length}`);
11923
+ lines.push(`Total calls recorded: ${allStats.reduce((sum, s) => sum + s.count, 0)}`);
11924
+ lines.push(`Total time in FFI: ${allStats.reduce((sum, s) => sum + s.total, 0).toFixed(2)}ms`);
11925
+ lines.push("");
11926
+ lines.push("Statistics sorted by total time (descending)");
11927
+ lines.push("--------------------------------------------------------------------------------");
11722
11928
  if (allStats.length === 0) {
11723
11929
  lines.push("No trace data collected or all symbols had zero calls.");
11724
11930
  } else {
@@ -11746,12 +11952,29 @@ function convertToDebugSymbols(symbols) {
11746
11952
  lines.push(`${stat.name.padEnd(nameWidth)} | ${String(stat.count).padStart(countWidth)} | ${stat.total.toFixed(2).padStart(totalWidth)} | ${stat.average.toFixed(2).padStart(avgWidth)} | ${stat.min.toFixed(2).padStart(minWidth)} | ${stat.max.toFixed(2).padStart(maxWidth)} | ${stat.median.toFixed(2).padStart(medianWidth)} | ${stat.p90.toFixed(2).padStart(p90Width)} | ${stat.p99.toFixed(2).padStart(p99Width)}`);
11747
11953
  });
11748
11954
  }
11749
- lines.push("-------------------------------------------------------------------------------------------------------------------------");
11955
+ lines.push("--------------------------------------------------------------------------------");
11956
+ lines.push("");
11957
+ lines.push("SUMMARY BY CATEGORY:");
11958
+ lines.push("--------------------------------------------------------------------------------");
11959
+ const categories = {};
11960
+ for (const stat of allStats) {
11961
+ const category = stat.name.includes("Buffer") ? "Buffer Operations" : stat.name.includes("Renderer") || stat.name.includes("render") ? "Renderer" : stat.name.includes("Text") || stat.name.includes("text") ? "Text Operations" : stat.name.includes("Cursor") || stat.name.includes("cursor") ? "Cursor" : stat.name.includes("Edit") || stat.name.includes("edit") ? "Edit Operations" : stat.name.includes("Editor") || stat.name.includes("editor") ? "Editor View" : stat.name.includes("stream") || stat.name.includes("Stream") ? "Stream/IO" : stat.name.includes("link") || stat.name.includes("Link") ? "Link Management" : "Other";
11962
+ if (!categories[category]) {
11963
+ categories[category] = { count: 0, total: 0, symbols: [] };
11964
+ }
11965
+ categories[category].count += stat.count;
11966
+ categories[category].total += stat.total;
11967
+ categories[category].symbols.push(stat.name);
11968
+ }
11969
+ const sortedCategories = Object.entries(categories).sort((a, b) => b[1].total - a[1].total);
11970
+ for (const [cat, data] of sortedCategories) {
11971
+ lines.push(` ${cat.padEnd(20)} | ${String(data.count).padStart(6)} calls | ${data.total.toFixed(2).padStart(12)}ms`);
11972
+ }
11973
+ lines.push("--------------------------------------------------------------------------------");
11750
11974
  const output = lines.join(`
11751
11975
  `);
11752
11976
  console.log(output);
11753
11977
  try {
11754
- const now = new Date;
11755
11978
  const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
11756
11979
  const traceFilePath = `ffi_cascade_trace_${timestamp}.log`;
11757
11980
  Bun.write(traceFilePath, output);
@@ -18546,5 +18769,5 @@ Captured output:
18546
18769
 
18547
18770
  export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, exports_src, isValidBorderStyle, parseBorderStyle, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, ATTRIBUTE_BASE_BITS, ATTRIBUTE_BASE_MASK, getBaseAttributes, DebugOverlayCorner, createTextAttributes, attributesWithLink, getLinkId, visualizeRenderableTree, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, link, t, hastToStyledText, LinearScrollAccel, MacOSScrollAccel, StdinBuffer, parseAlign, parseAlignItems, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, clearEnvCache, generateEnvMarkdown, generateEnvColored, env, treeSitterToTextChunks, treeSitterToStyledText, addDefaultParsers, TreeSitterClient, DataPathsManager, getDataPaths, extToFiletype, pathToFiletype, main, getTreeSitterClient, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, TextBuffer, SpanInfoStruct, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, ANSI, defaultKeyAliases, mergeKeyAliases, mergeKeyBindings, getKeyBindingKey, buildKeyBindingsMap, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, buildKittyKeyboardFlags, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, RendererControlState, CliRenderer };
18548
18771
 
18549
- //# debugId=16C825532B5F27E664756E2164756E21
18550
- //# sourceMappingURL=index-kfh59ta6.js.map
18772
+ //# debugId=56AB7BEC6F0515B564756E2164756E21
18773
+ //# sourceMappingURL=index-z2wm303h.js.map