sigrank 0.17.3 → 0.17.4

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 (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/tui.mjs +49 -1
package/README.md CHANGED
@@ -147,7 +147,7 @@ smithery tool call sigrank rank_paste '{"text": "1000000 500000 50000 800000"}'
147
147
  ## Commands
148
148
 
149
149
  ```
150
- ⊙ SigRank CLI v0.17.3
150
+ ⊙ SigRank CLI v0.17.4
151
151
 
152
152
  Default (no args)
153
153
  sigrank unified dashboard: cascade + token pillars + board
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigrank",
3
- "version": "0.17.3",
3
+ "version": "0.17.4",
4
4
  "author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
5
5
  "description": "SigRank MCP server — the yield cascade + live leaderboard as MCP tools any agent can call",
6
6
  "mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
package/tui.mjs CHANGED
@@ -2136,8 +2136,17 @@ export async function runTui({
2136
2136
  process.stdin.resume();
2137
2137
  process.stdin.setEncoding("utf8");
2138
2138
 
2139
+ // Esc-sequence buffer: some terminals (SSH, tmux, certain emulators) split an
2140
+ // arrow key (\x1b[C) into two data events: \x1b then [C. Without buffering, the
2141
+ // lone \x1b triggers the Esc handler (clearing the code buffer / leaving the tab)
2142
+ // before the [C arrives. We hold \x1b for 25ms; if more bytes follow, we
2143
+ // reassemble and deliver the full sequence. If nothing follows, it's a real Esc.
2144
+ let escBuf = null;
2145
+ let escTimer = null;
2146
+ const ESC_HOLD_MS = 25;
2147
+
2139
2148
  await new Promise((resolve) => {
2140
- process.stdin.on("data", async (key) => {
2149
+ const handleKey = async (key) => {
2141
2150
  const k = key.toLowerCase();
2142
2151
 
2143
2152
  if (k === "q" || k === "\x03") {
@@ -2589,6 +2598,45 @@ export async function runTui({
2589
2598
 
2590
2599
  if (switched) submitMsg = ""; // submit result is tied to the tab it was sent from
2591
2600
  if (switched || k === "w") await redraw();
2601
+ };
2602
+
2603
+ // Buffered stdin listener: reassembles split Esc sequences before dispatch.
2604
+ process.stdin.on("data", (chunk) => {
2605
+ // If we have a pending \x1b held from a previous chunk, combine it with
2606
+ // this chunk to reassemble the full escape sequence (\x1b + [C = \x1b[C).
2607
+ if (escBuf) {
2608
+ clearTimeout(escTimer);
2609
+ const combined = escBuf + chunk;
2610
+ escBuf = null;
2611
+ escTimer = null;
2612
+ // If the combined result is \x1b followed by more \x1b (rare), just
2613
+ // deliver the first as Esc and re-buffer the second. Otherwise deliver
2614
+ // the combined sequence.
2615
+ if (combined.length > 1) {
2616
+ handleKey(combined);
2617
+ return;
2618
+ }
2619
+ // combined is still just \x1b (chunk was empty?) → fall through to hold
2620
+ }
2621
+
2622
+ // Fast path: chunk doesn't start with \x1b → deliver immediately.
2623
+ if (chunk[0] !== "\x1b") {
2624
+ handleKey(chunk);
2625
+ return;
2626
+ }
2627
+ // Chunk starts with \x1b and is longer than 1 byte → complete escape
2628
+ // sequence → deliver immediately.
2629
+ if (chunk.length > 1) {
2630
+ handleKey(chunk);
2631
+ return;
2632
+ }
2633
+ // Chunk is exactly \x1b → hold for ESC_HOLD_MS to see if more bytes follow.
2634
+ escBuf = chunk;
2635
+ escTimer = setTimeout(() => {
2636
+ handleKey(escBuf);
2637
+ escBuf = null;
2638
+ escTimer = null;
2639
+ }, ESC_HOLD_MS);
2592
2640
  });
2593
2641
  });
2594
2642