claude-highlight 1.0.0 → 1.0.2

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.
@@ -1,78 +1,16 @@
1
- #!/usr/bin/env bun
2
- // @bun
1
+ #!/bin/sh
2
+ ':' //; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import {
4
+ configFile,
5
+ decodeIgnore,
6
+ environ
7
+ } from "./claude-highlight-egzaxzbg.js";
8
+ import { createRequire } from "node:module";
9
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
10
 
4
11
  // src/claude-highlight.ts
5
- import { existsSync, mkdirSync, openSync, readFileSync, statSync, writeFileSync, writeSync } from "fs";
6
- import { basename, dirname, resolve } from "path";
7
-
8
- // src/util.ts
9
- import { homedir } from "os";
10
- import { join } from "path";
11
- function configFile(app) {
12
- const base = process.env["XDG_CONFIG_HOME"] || join(process.env["HOME"] || homedir(), ".config");
13
- return join(base, app, "config.json");
14
- }
15
- function decodeIgnore(buf) {
16
- let out = "";
17
- const n = buf.length;
18
- let i = 0;
19
- while (i < n) {
20
- const b = buf[i] ?? 0;
21
- if (b < 128) {
22
- out += String.fromCharCode(b);
23
- i++;
24
- continue;
25
- }
26
- let len, cp;
27
- if (b >= 194 && b <= 223) {
28
- len = 2;
29
- cp = b & 31;
30
- } else if (b >= 224 && b <= 239) {
31
- len = 3;
32
- cp = b & 15;
33
- } else if (b >= 240 && b <= 244) {
34
- len = 4;
35
- cp = b & 7;
36
- } else {
37
- i++;
38
- continue;
39
- }
40
- if (i + len > n)
41
- break;
42
- let ok = true;
43
- for (let k = 1;k < len; k++) {
44
- const c = buf[i + k] ?? 128;
45
- if ((c & 192) !== 128) {
46
- ok = false;
47
- break;
48
- }
49
- cp = cp << 6 | c & 63;
50
- }
51
- if (!ok) {
52
- i++;
53
- continue;
54
- }
55
- if (len === 3 && (cp < 2048 || cp >= 55296 && cp <= 57343))
56
- ok = false;
57
- if (len === 4 && (cp < 65536 || cp > 1114111))
58
- ok = false;
59
- if (!ok) {
60
- i++;
61
- continue;
62
- }
63
- out += String.fromCodePoint(cp);
64
- i += len;
65
- }
66
- return out;
67
- }
68
- function environ() {
69
- const out = {};
70
- for (const [key, value] of Object.entries(process.env)) {
71
- if (value !== undefined)
72
- out[key] = value;
73
- }
74
- return out;
75
- }
12
+ import { existsSync as existsSync2, mkdirSync, openSync, readFileSync, statSync as statSync2, writeFileSync, writeSync as writeSync2 } from "node:fs";
13
+ import { basename, dirname, resolve } from "node:path";
76
14
 
77
15
  // src/highlight_filter.ts
78
16
  var WORD_TAIL = /[A-Za-z0-9'_-]+$/;
@@ -93,7 +31,7 @@ function finditer(pat, s) {
93
31
  return out;
94
32
  }
95
33
  function asciiReplace(b) {
96
- return b.toString("latin1").replace(/[\u0080-\u00ff]/g, "\uFFFD");
34
+ return b.toString("latin1").replace(/[\u0080-\u00ff]/g, "�");
97
35
  }
98
36
  var isDigits = (s) => /^[0-9]+$/.test(s);
99
37
 
@@ -576,7 +514,7 @@ var FRAME_END = /\x1b\[\?2026l/g;
576
514
  var PARTIAL_CSI = /^\x1b\[[\x30-\x3f]*[\x20-\x2f]*$/;
577
515
  var MAX_FIX = 4096;
578
516
  var MAX_PENDING = 4096;
579
- var RULE_CHARS = new Set("\u2500\u2501\u254C\u254D\u2504\u2505\u2508\u2509\u2502\u2503\u256D\u256E\u2570\u256F\u250C\u2510\u2514\u2518\u251C\u2524\u252C\u2534\u253C");
517
+ var RULE_CHARS = new Set("─━╌╍┄┅┈┉│┃╭╮╰╯┌┐└┘├┤┬┴┼");
580
518
  var BOTTOM_CHROME = 10;
581
519
  var MAX_COMPOSER = 24;
582
520
  var WIDE = [
@@ -880,11 +818,13 @@ class ScreenModel {
880
818
  cols;
881
819
  chars;
882
820
  fg;
821
+ bg;
883
822
  ours;
884
823
  rule;
885
824
  x;
886
825
  y;
887
826
  curFg;
827
+ curBg;
888
828
  curOurs;
889
829
  saved;
890
830
  top;
@@ -906,12 +846,14 @@ class ScreenModel {
906
846
  invalidate() {
907
847
  this.chars = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
908
848
  this.fg = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
849
+ this.bg = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
909
850
  this.ours = Array.from({ length: this.rows }, () => new Array(this.cols).fill(false));
910
851
  this.rule = new Array(this.rows).fill(null);
911
852
  this.x = this.y = 0;
912
853
  this.curFg = null;
854
+ this.curBg = null;
913
855
  this.curOurs = false;
914
- this.saved = [0, 0, null];
856
+ this.saved = [0, 0, null, null];
915
857
  this.top = 0;
916
858
  this.bot = this.rows - 1;
917
859
  this.alt = false;
@@ -922,6 +864,7 @@ class ScreenModel {
922
864
  }
923
865
  blankRow() {
924
866
  return [
867
+ new Array(this.cols).fill(null),
925
868
  new Array(this.cols).fill(null),
926
869
  new Array(this.cols).fill(null),
927
870
  new Array(this.cols).fill(false)
@@ -930,6 +873,7 @@ class ScreenModel {
930
873
  set(x, ch) {
931
874
  this.chars[this.y][x] = ch;
932
875
  this.fg[this.y][x] = this.curFg;
876
+ this.bg[this.y][x] = this.curBg;
933
877
  this.ours[this.y][x] = this.curOurs;
934
878
  this.dirty.add(this.y);
935
879
  this.rule[this.y] = null;
@@ -962,12 +906,14 @@ class ScreenModel {
962
906
  }
963
907
  scroll(n, up = true) {
964
908
  for (let k = 0;k < Math.max(n, 1); k++) {
965
- const [c, f, o] = this.blankRow();
909
+ const [c, f, bg, o] = this.blankRow();
966
910
  if (up) {
967
911
  this.chars.splice(this.top, 1);
968
912
  this.chars.splice(this.bot, 0, c);
969
913
  this.fg.splice(this.top, 1);
970
914
  this.fg.splice(this.bot, 0, f);
915
+ this.bg.splice(this.top, 1);
916
+ this.bg.splice(this.bot, 0, bg);
971
917
  this.ours.splice(this.top, 1);
972
918
  this.ours.splice(this.bot, 0, o);
973
919
  } else {
@@ -975,6 +921,8 @@ class ScreenModel {
975
921
  this.chars.splice(this.top, 0, c);
976
922
  this.fg.splice(this.bot, 1);
977
923
  this.fg.splice(this.top, 0, f);
924
+ this.bg.splice(this.bot, 1);
925
+ this.bg.splice(this.top, 0, bg);
978
926
  this.ours.splice(this.bot, 1);
979
927
  this.ours.splice(this.top, 0, o);
980
928
  }
@@ -989,10 +937,17 @@ class ScreenModel {
989
937
  while (i < toks.length) {
990
938
  const t = toks[i] || "0";
991
939
  const n = /^[0-9]+$/.test(t) ? parseInt(t, 10) : -1;
992
- if (n === 0 || n === 39) {
940
+ if (n === 0) {
993
941
  this.curFg = null;
942
+ this.curBg = null;
943
+ } else if (n === 39) {
944
+ this.curFg = null;
945
+ } else if (n === 49) {
946
+ this.curBg = null;
994
947
  } else if (n >= 30 && n <= 37 || n >= 90 && n <= 97) {
995
948
  this.curFg = t;
949
+ } else if (n >= 40 && n <= 47 || n >= 100 && n <= 107) {
950
+ this.curBg = t;
996
951
  } else if (n === 38) {
997
952
  if (toks[i + 1] === "5") {
998
953
  this.curFg = toks.slice(i, i + 3).join(";");
@@ -1001,6 +956,14 @@ class ScreenModel {
1001
956
  this.curFg = toks.slice(i, i + 5).join(";");
1002
957
  i += 4;
1003
958
  }
959
+ } else if (n === 48) {
960
+ if (toks[i + 1] === "5") {
961
+ this.curBg = toks.slice(i, i + 3).join(";");
962
+ i += 2;
963
+ } else if (toks[i + 1] === "2") {
964
+ this.curBg = toks.slice(i, i + 5).join(";");
965
+ i += 4;
966
+ }
1004
967
  }
1005
968
  i += 1;
1006
969
  }
@@ -1010,6 +973,7 @@ class ScreenModel {
1010
973
  for (const x of cells) {
1011
974
  this.chars[this.y][x] = " ";
1012
975
  this.fg[this.y][x] = null;
976
+ this.bg[this.y][x] = null;
1013
977
  this.ours[this.y][x] = false;
1014
978
  }
1015
979
  this.dirty.add(this.y);
@@ -1087,13 +1051,15 @@ class ScreenModel {
1087
1051
  } else if (fin === "L" || fin === "M") {
1088
1052
  const n = Math.max(a, 1);
1089
1053
  for (let k = 0;k < n; k++) {
1090
- const [c, f, o] = this.blankRow();
1054
+ const [c, f, bg, o] = this.blankRow();
1091
1055
  const at = fin === "L" ? this.y : this.bot;
1092
1056
  const from = fin === "L" ? this.bot : this.y;
1093
1057
  this.chars.splice(from, 1);
1094
1058
  this.chars.splice(at, 0, c);
1095
1059
  this.fg.splice(from, 1);
1096
1060
  this.fg.splice(at, 0, f);
1061
+ this.bg.splice(from, 1);
1062
+ this.bg.splice(at, 0, bg);
1097
1063
  this.ours.splice(from, 1);
1098
1064
  this.ours.splice(at, 0, o);
1099
1065
  }
@@ -1102,7 +1068,7 @@ class ScreenModel {
1102
1068
  this.rule = new Array(this.rows).fill(null);
1103
1069
  } else if (fin === "P" || fin === "@") {
1104
1070
  const n = Math.max(a, 1);
1105
- const chars = this.chars[this.y], fg = this.fg[this.y], ours = this.ours[this.y];
1071
+ const chars = this.chars[this.y], fg = this.fg[this.y], bg = this.bg[this.y], ours = this.ours[this.y];
1106
1072
  if (fin === "P") {
1107
1073
  chars.splice(this.x, n);
1108
1074
  while (chars.length < this.cols)
@@ -1110,6 +1076,9 @@ class ScreenModel {
1110
1076
  fg.splice(this.x, n);
1111
1077
  while (fg.length < this.cols)
1112
1078
  fg.push(null);
1079
+ bg.splice(this.x, n);
1080
+ while (bg.length < this.cols)
1081
+ bg.push(null);
1113
1082
  ours.splice(this.x, n);
1114
1083
  while (ours.length < this.cols)
1115
1084
  ours.push(false);
@@ -1119,6 +1088,8 @@ class ScreenModel {
1119
1088
  chars.pop();
1120
1089
  fg.splice(this.x, 0, null);
1121
1090
  fg.pop();
1091
+ bg.splice(this.x, 0, null);
1092
+ bg.pop();
1122
1093
  ours.splice(this.x, 0, false);
1123
1094
  ours.pop();
1124
1095
  }
@@ -1193,9 +1164,9 @@ class ScreenModel {
1193
1164
  continue;
1194
1165
  }
1195
1166
  if (nxt === 55) {
1196
- this.saved = [this.x, this.y, this.curFg];
1167
+ this.saved = [this.x, this.y, this.curFg, this.curBg];
1197
1168
  } else if (nxt === 56) {
1198
- [this.x, this.y, this.curFg] = this.saved;
1169
+ [this.x, this.y, this.curFg, this.curBg] = this.saved;
1199
1170
  this.curOurs = this.curFg !== null && this.palette.has(this.curFg);
1200
1171
  } else if (nxt === 77) {
1201
1172
  if (this.y === this.top)
@@ -1322,7 +1293,7 @@ class ScreenModel {
1322
1293
  const cells = span(idx[start], idx[end - 1] + 1);
1323
1294
  if (cells.some((c) => want[c] !== null))
1324
1295
  continue;
1325
- if (onlyUnstyled && cells.some((c) => this.fg[y][c] !== null && !this.ours[y][c])) {
1296
+ if (onlyUnstyled && cells.some((c) => this.fg[y][c] !== null && !this.ours[y][c] || this.bg[y][c] !== null)) {
1326
1297
  continue;
1327
1298
  }
1328
1299
  for (const c of cells)
@@ -1332,30 +1303,40 @@ class ScreenModel {
1332
1303
  return want;
1333
1304
  }
1334
1305
  corrections(rules, onlyUnstyled = true) {
1335
- if (!this.alt || this.dirty.size === 0)
1306
+ if (!this.alt)
1336
1307
  return Buffer.alloc(0);
1337
- const rows = [...this.dirty].sort((p, q) => p - q);
1338
- this.dirty = new Set;
1339
1308
  const offLimits = this.composerRows();
1309
+ const todo = new Set(this.dirty);
1310
+ for (const y of offLimits)
1311
+ todo.add(y);
1312
+ if (todo.size === 0)
1313
+ return Buffer.alloc(0);
1314
+ const rows = [...todo].sort((p, q) => p - q);
1315
+ this.dirty = new Set;
1340
1316
  const out = [];
1341
1317
  let len = 0, spent = false;
1318
+ const needsFix = (y, x, want) => {
1319
+ if (this.fg[y][x] === want[x])
1320
+ return false;
1321
+ return this.ours[y][x] || want[x] !== null && this.fg[y][x] === null;
1322
+ };
1342
1323
  for (const y of rows) {
1343
1324
  if (spent) {
1344
1325
  this.dirty.add(y);
1345
1326
  continue;
1346
1327
  }
1347
- if (!this.ours[y].some((v) => v))
1348
- continue;
1349
1328
  const want = this.desired(y, rules, onlyUnstyled, offLimits);
1329
+ if (!this.ours[y].some((v) => v) && !want.some((v) => v !== null))
1330
+ continue;
1350
1331
  let x = 0;
1351
1332
  while (x < this.cols) {
1352
- if (!(this.ours[y][x] && this.fg[y][x] !== want[x])) {
1333
+ if (!needsFix(y, x, want)) {
1353
1334
  x += 1;
1354
1335
  continue;
1355
1336
  }
1356
1337
  let start = x;
1357
1338
  const target = want[x];
1358
- while (x < this.cols && this.ours[y][x] && this.fg[y][x] !== want[x] && want[x] === target)
1339
+ while (x < this.cols && needsFix(y, x, want) && want[x] === target)
1359
1340
  x += 1;
1360
1341
  if (this.chars[y][start] === "" && start)
1361
1342
  start -= 1;
@@ -1420,186 +1401,66 @@ function span(a, b) {
1420
1401
  }
1421
1402
 
1422
1403
  // src/pty.ts
1423
- import { closeSync } from "fs";
1424
-
1425
- // src/sysffi.ts
1426
- import { dlopen, FFIType } from "bun:ffi";
1427
- var APPLE_VARARGS = process.platform === "darwin" && process.arch === "arm64";
1428
- var IOCTL_PAD = [
1429
- FFIType.u64,
1430
- FFIType.u64,
1431
- FFIType.u64,
1432
- FFIType.u64,
1433
- FFIType.u64,
1434
- FFIType.u64
1435
- ];
1436
- var IOCTL = {
1437
- ioctl: {
1438
- args: APPLE_VARARGS ? [FFIType.i32, FFIType.u64, ...IOCTL_PAD, FFIType.ptr] : [FFIType.i32, FFIType.u64, FFIType.ptr],
1439
- returns: FFIType.i32
1440
- }
1441
- };
1442
- var CORE = {
1443
- read: { args: [FFIType.i32, FFIType.ptr, FFIType.u64], returns: FFIType.i64 },
1444
- write: { args: [FFIType.i32, FFIType.ptr, FFIType.u64], returns: FFIType.i64 },
1445
- close: { args: [FFIType.i32], returns: FFIType.i32 },
1446
- kill: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
1447
- tcgetattr: { args: [FFIType.i32, FFIType.ptr], returns: FFIType.i32 },
1448
- tcsetattr: { args: [FFIType.i32, FFIType.i32, FFIType.ptr], returns: FFIType.i32 },
1449
- cfmakeraw: { args: [FFIType.ptr], returns: FFIType.i32 }
1450
- };
1451
- var OPENPTY = {
1452
- openpty: {
1453
- args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr],
1454
- returns: FFIType.i32
1455
- }
1456
- };
1457
- function bind(symbols) {
1458
- return symbols;
1404
+ var IS_BUN = typeof globalThis.Bun !== "undefined";
1405
+ async function ptySpawn(file, args, opts) {
1406
+ if (IS_BUN) {
1407
+ const { ptySpawnBun } = await import("./pty-bun-2y4wmvve.js");
1408
+ return ptySpawnBun(file, args, opts);
1409
+ }
1410
+ const { ptySpawnNode } = await import("./pty-node-6j2dj9ta.js");
1411
+ return ptySpawnNode(file, args, opts);
1459
1412
  }
1460
- function load() {
1461
- if (process.platform === "darwin") {
1462
- const lib = dlopen("/usr/lib/libSystem.dylib", { ...CORE, ...IOCTL, ...OPENPTY });
1463
- const syms = bind(lib.symbols);
1464
- return { core: syms, openpty: syms };
1465
- }
1466
- const core = bind(dlopen("libc.so.6", { ...CORE, ...IOCTL }).symbols);
1467
- for (const name of ["libc.so.6", "libutil.so.1", "libutil.so"]) {
1413
+
1414
+ // src/sys.ts
1415
+ import { existsSync, statSync, writeSync } from "node:fs";
1416
+ import { join } from "node:path";
1417
+ import { isatty } from "node:tty";
1418
+ function setRawStdin() {
1419
+ if (!isatty(0) || typeof process.stdin.setRawMode !== "function")
1420
+ return null;
1421
+ process.stdin.setRawMode(true);
1422
+ return () => {
1468
1423
  try {
1469
- return { core, openpty: bind(dlopen(name, OPENPTY).symbols) };
1424
+ process.stdin.setRawMode(false);
1470
1425
  } catch {}
1471
- }
1472
- throw new Error("openpty not found in libc.so.6, libutil.so.1 or libutil.so");
1473
- }
1474
- var ffi = load();
1475
- var TCSANOW = 0;
1476
- var TIOCGWINSZ = process.platform === "darwin" ? 1074295912 : 21523;
1477
- var TIOCSWINSZ = process.platform === "darwin" ? 2148037735 : 21524;
1478
- var SIGWINCH = 28;
1479
- var SIGHUP = 1;
1480
- var SIGTERM = 15;
1481
- function saveAndSetRawStdin() {
1482
- const cur = Buffer.alloc(128);
1483
- if (ffi.core.tcgetattr(0, cur) !== 0)
1484
- return null;
1485
- const saved = Buffer.from(cur);
1486
- ffi.core.cfmakeraw(cur);
1487
- ffi.core.tcsetattr(0, TCSANOW, cur);
1488
- return saved;
1489
- }
1490
- function restoreStdin(saved) {
1491
- ffi.core.tcsetattr(0, TCSANOW, saved);
1492
- }
1493
- function setWinsize(master, rows, cols) {
1494
- const ws = Buffer.alloc(8);
1495
- ws.writeUInt16LE(Math.max(rows, 1) & 65535, 0);
1496
- ws.writeUInt16LE(Math.max(cols, 1) & 65535, 2);
1497
- return ioctlPtr(master, TIOCSWINSZ, ws);
1426
+ };
1498
1427
  }
1499
- function ioctlPtr(fd, request, arg) {
1500
- return APPLE_VARARGS ? ffi.core.ioctl(fd, BigInt(request), 0n, 0n, 0n, 0n, 0n, 0n, arg) : ffi.core.ioctl(fd, BigInt(request), arg);
1501
- }
1502
- function getWinsize(fd) {
1503
- const ws = Buffer.alloc(8);
1504
- if (ioctlPtr(fd, TIOCGWINSZ, ws) !== 0)
1505
- return null;
1506
- return [ws.readUInt16LE(0), ws.readUInt16LE(2)];
1428
+ function winsize() {
1429
+ const rows = process.stdout.rows, cols = process.stdout.columns;
1430
+ if (rows && cols)
1431
+ return [rows, cols];
1432
+ return [24, Number(process.env["COLUMNS"]) || 80];
1507
1433
  }
1508
1434
  function writeAll(fd, data) {
1509
1435
  let off = 0;
1510
1436
  while (off < data.length) {
1511
- const n = Number(ffi.core.write(fd, data.subarray(off), data.length - off));
1512
- if (n <= 0)
1437
+ try {
1438
+ off += writeSync(fd, data, off);
1439
+ } catch (e) {
1440
+ const code = e.code;
1441
+ if (code === "EAGAIN")
1442
+ continue;
1513
1443
  return;
1514
- off += n;
1444
+ }
1515
1445
  }
1516
1446
  }
1517
1447
  var SLEEPER = new Int32Array(new SharedArrayBuffer(4));
1518
1448
  function sleepSync(ms) {
1519
1449
  Atomics.wait(SLEEPER, 0, 0, ms);
1520
1450
  }
1521
-
1522
- // src/pty.ts
1523
- function workerUrl(name) {
1524
- return new URL(`./${name}${import.meta.url.endsWith(".ts") ? ".ts" : ".js"}`, import.meta.url);
1525
- }
1526
- function ptySpawn(file, args, opts) {
1527
- const m = Buffer.alloc(4);
1528
- const s = Buffer.alloc(4);
1529
- const name = Buffer.alloc(128);
1530
- const ws = Buffer.alloc(8);
1531
- ws.writeUInt16LE(Math.max(opts.rows, 1) & 65535, 0);
1532
- ws.writeUInt16LE(Math.max(opts.cols, 1) & 65535, 2);
1533
- const rc = ffi.openpty.openpty(m, s, name, null, ws);
1534
- if (rc !== 0)
1535
- throw new Error(`openpty failed (${rc})`);
1536
- const master = m.readInt32LE(0);
1537
- const slave = s.readInt32LE(0);
1538
- const proc = Bun.spawn([file, ...args], {
1539
- stdin: slave,
1540
- stdout: slave,
1541
- stderr: slave,
1542
- env: opts.env ?? environ(),
1543
- ...opts.cwd === undefined ? {} : { cwd: opts.cwd }
1544
- });
1545
- closeSync(slave);
1546
- const reader = new Worker(workerUrl("pty-read-worker"));
1547
- const writer = new Worker(workerUrl("pty-write-worker"));
1548
- let dataCb = null;
1549
- let markDrained = () => {};
1550
- const drained = new Promise((res) => {
1551
- markDrained = res;
1552
- });
1553
- reader.addEventListener("message", (event) => {
1554
- const chunk = event.data;
1555
- if (chunk === null)
1556
- markDrained();
1557
- else
1558
- dataCb?.(Buffer.from(chunk));
1559
- });
1560
- const exited = (async () => Number(await proc.exited))();
1561
- let reading = false;
1562
- return {
1563
- pid: proc.pid,
1564
- get exited() {
1565
- return exited;
1566
- },
1567
- get drained() {
1568
- return drained;
1569
- },
1570
- write(data) {
1571
- writer.postMessage({ fd: master, data: new Uint8Array(data) });
1572
- },
1573
- onData(cb) {
1574
- dataCb = cb;
1575
- if (!reading) {
1576
- reading = true;
1577
- reader.postMessage({ fd: master });
1578
- }
1579
- },
1580
- resize(rows, cols) {
1581
- setWinsize(master, rows, cols);
1582
- try {
1583
- proc.kill(SIGWINCH);
1584
- } catch {}
1585
- },
1586
- kill(signal = SIGTERM) {
1587
- try {
1588
- proc.kill(signal);
1589
- } catch {}
1590
- },
1591
- destroy() {
1592
- try {
1593
- proc.kill(SIGHUP);
1594
- } catch {}
1595
- try {
1596
- closeSync(master);
1597
- } catch {}
1598
- markDrained();
1599
- reader.terminate();
1600
- writer.terminate();
1601
- }
1602
- };
1451
+ function which(name) {
1452
+ if (name.includes("/"))
1453
+ return null;
1454
+ for (const dir of (process.env["PATH"] ?? "").split(":")) {
1455
+ if (!dir)
1456
+ continue;
1457
+ const candidate = join(dir, name);
1458
+ try {
1459
+ if (existsSync(candidate) && statSync(candidate).isFile())
1460
+ return candidate;
1461
+ } catch {}
1462
+ }
1463
+ return null;
1603
1464
  }
1604
1465
 
1605
1466
  // src/json.ts
@@ -1628,15 +1489,16 @@ function truthy(v) {
1628
1489
  }
1629
1490
 
1630
1491
  // src/claude-highlight.ts
1631
- var DOC = `claude-highlight \u2014 run Claude Code behind a PTY that colors epistemic markers.
1492
+ ":";
1493
+ var DOC = `claude-highlight — run Claude Code behind a PTY that colors epistemic markers.
1632
1494
 
1633
1495
  claude-highlight [any claude args...]
1634
1496
 
1635
1497
  Spawns the real \`claude\` on a pseudo-terminal and forwards bytes both ways,
1636
1498
  injecting SGR color around matched words on the way out. Because SGR is
1637
- zero-width, the child's layout math is untouched \u2014 see highlight_filter.ts.
1499
+ zero-width, the child's layout math is untouched — see highlight_filter.ts.
1638
1500
 
1639
- Hotkey (default F9, or bind cmd+/ in Ghostty \u2014 see README) opens a plugin
1501
+ Hotkey (default F9, or bind cmd+/ in Ghostty — see README) opens a plugin
1640
1502
  menu to toggle categories live. Config lives at
1641
1503
  ~/.config/claude-highlight/config.json and is re-read whenever it changes.
1642
1504
  `;
@@ -1667,7 +1529,7 @@ function text(v, fallback) {
1667
1529
  return v === undefined ? fallback : String(v);
1668
1530
  }
1669
1531
  function loadConfig() {
1670
- const parsed = existsSync(CONFIG) ? parseJson(readFileSync(CONFIG, "utf8")) : null;
1532
+ const parsed = existsSync2(CONFIG) ? parseJson(readFileSync(CONFIG, "utf8")) : null;
1671
1533
  const user = isObject(parsed) ? parsed : {};
1672
1534
  const catsRaw = user["categories"];
1673
1535
  const cats = isObject(catsRaw) ? catsRaw : {};
@@ -1709,7 +1571,7 @@ function loadConfig() {
1709
1571
  prose_only: truthy(user["prose_only"] ?? true),
1710
1572
  idle_repaint: truthy(user["idle_repaint"] ?? false)
1711
1573
  };
1712
- if (!existsSync(CONFIG)) {
1574
+ if (!existsSync2(CONFIG)) {
1713
1575
  mkdirSync(dirname(CONFIG), { recursive: true });
1714
1576
  writeFileSync(CONFIG, JSON.stringify(cfgAll, null, 2));
1715
1577
  }
@@ -1725,11 +1587,11 @@ function selfName() {
1725
1587
  base.replace(/\.[jt]s$/, "")
1726
1588
  ];
1727
1589
  for (const name of candidates) {
1728
- const found = Bun.which(name);
1590
+ const found = which(name);
1729
1591
  if (!found)
1730
1592
  continue;
1731
1593
  try {
1732
- const a = statSync(found), b = statSync(resolve(argv0));
1594
+ const a = statSync2(found), b = statSync2(resolve(argv0));
1733
1595
  if (a.ino === b.ino && a.dev === b.dev)
1734
1596
  return name;
1735
1597
  } catch {}
@@ -1819,17 +1681,17 @@ var SEL_BG = c_("48;2;64;74;112", "48;5;238");
1819
1681
  var SEL_FG = c_("38;2;255;255;255", "38;5;255");
1820
1682
  var SEL_BAR = c_("38;2;255;214;102", "38;5;221");
1821
1683
  var G = UNICODE ? {
1822
- tl: "\u256D",
1823
- tr: "\u256E",
1824
- bl: "\u2570",
1825
- br: "\u256F",
1826
- h: "\u2500",
1827
- v: "\u2502",
1828
- vsel: "\u2503",
1829
- mark: " \u25B8 ",
1830
- swatch: "\u2588\u2588",
1831
- up: "\u2191\u2193",
1832
- dot: "\xB7"
1684
+ tl: "╭",
1685
+ tr: "╮",
1686
+ bl: "╰",
1687
+ br: "╯",
1688
+ h: "─",
1689
+ v: "│",
1690
+ vsel: "┃",
1691
+ mark: " ▸ ",
1692
+ swatch: "██",
1693
+ up: "↑↓",
1694
+ dot: "·"
1833
1695
  } : {
1834
1696
  tl: "+",
1835
1697
  tr: "+",
@@ -1902,37 +1764,37 @@ function drawMenu(cfg, rows, cols, sel) {
1902
1764
  }
1903
1765
  var PALETTE = [
1904
1766
  [
1905
- "reds \u2014 loudest, for the claim you most want to catch",
1767
+ "reds — loudest, for the claim you most want to catch",
1906
1768
  "inference",
1907
1769
  [203, 196, 202, 209, 167, 174, 210, 168]
1908
1770
  ],
1909
1771
  [
1910
- "pinks and magentas \u2014 loud but not alarming",
1772
+ "pinks and magentas — loud but not alarming",
1911
1773
  "unknown",
1912
1774
  [170, 176, 177, 183, 213, 205, 141, 218]
1913
1775
  ],
1914
1776
  [
1915
- "ambers and yellows \u2014 warm, reads as 'check this'",
1777
+ "ambers and yellows — warm, reads as 'check this'",
1916
1778
  "assumption",
1917
1779
  [214, 215, 220, 221, 222, 178, 136, 223]
1918
1780
  ],
1919
1781
  [
1920
- "golds and tans \u2014 quieter warmth, good for a busy category",
1782
+ "golds and tans — quieter warmth, good for a busy category",
1921
1783
  "appearance",
1922
1784
  [179, 180, 187, 144, 137, 173, 143, 229]
1923
1785
  ],
1924
1786
  [
1925
- "cyans and teals \u2014 cold, opposite end from the reds",
1787
+ "cyans and teals — cold, opposite end from the reds",
1926
1788
  "overclaim",
1927
1789
  [51, 45, 44, 80, 87, 116, 73, 37]
1928
1790
  ],
1929
1791
  [
1930
1792
  "greens",
1931
- "unused \u2014 free for a category of your own",
1793
+ "unused — free for a category of your own",
1932
1794
  [71, 78, 108, 114, 150, 84, 42, 155]
1933
1795
  ],
1934
1796
  [
1935
- "blues and violets \u2014 cool, and nothing in warm prose competes with them",
1797
+ "blues and violets — cool, and nothing in warm prose competes with them",
1936
1798
  "modal, vagueness, softener",
1937
1799
  [33, 39, 99, 105, 27, 63, 93, 135]
1938
1800
  ]
@@ -1959,7 +1821,7 @@ function paletteLines(cfg, cols, full = false) {
1959
1821
  for (let base = 16;base < 256; base += 12) {
1960
1822
  let line = "";
1961
1823
  for (let n = base;n < Math.min(base + 12, 256); n++) {
1962
- line += `\x1B[38;5;${n}m\u2588\u2588\x1B[39m${String(n).padEnd(4)}`;
1824
+ line += `\x1B[38;5;${n}m██\x1B[39m${String(n).padEnd(4)}`;
1963
1825
  }
1964
1826
  out.push(" " + line);
1965
1827
  }
@@ -2072,10 +1934,7 @@ function parseArgs(argv) {
2072
1934
  return a;
2073
1935
  }
2074
1936
  function stdoutCols() {
2075
- const sz = getWinsize(1);
2076
- if (sz && sz[1])
2077
- return sz[1];
2078
- return Number(process.env["COLUMNS"]) || 100;
1937
+ return process.stdout.columns || Number(process.env["COLUMNS"]) || 100;
2079
1938
  }
2080
1939
  async function main(argv) {
2081
1940
  const known = parseArgs(argv);
@@ -2100,7 +1959,7 @@ async function main(argv) {
2100
1959
  `, "utf8"));
2101
1960
  return 0;
2102
1961
  }
2103
- let mtime = existsSync(CONFIG) ? statSync(CONFIG).mtimeMs : 0;
1962
+ let mtime = existsSync2(CONFIG) ? statSync2(CONFIG).mtimeMs : 0;
2104
1963
  const hl = new AnsiHighlighter(buildRules(cfg), cfg.prose_only);
2105
1964
  hl.rewrites = buildRewrites();
2106
1965
  hl.holdPrefixes = growablePrefixes(userFragments(cfg));
@@ -2108,13 +1967,12 @@ async function main(argv) {
2108
1967
  const child = process.env["CLAUDE_HIGHLIGHT_CMD"] ?? "claude";
2109
1968
  const recRaw = known.hlRecord === null ? null : openSync(known.hlRecord + ".raw", "w");
2110
1969
  const recOut = known.hlRecord === null ? null : openSync(known.hlRecord + ".out", "w");
2111
- let [rows, cols] = getWinsize(1) ?? [24, 80];
2112
- const pty = ptySpawn(child, known.rest, { rows, cols, env: environ() });
1970
+ let [rows, cols] = winsize();
1971
+ const pty = await ptySpawn(child, known.rest, { rows, cols, env: environ() });
2113
1972
  screen.resize(rows, cols);
2114
- const old = saveAndSetRawStdin();
1973
+ const restoreStdin = setRawStdin();
2115
1974
  process.on("SIGWINCH", () => {
2116
- const sz = getWinsize(1);
2117
- [rows, cols] = sz ?? [24, 80];
1975
+ [rows, cols] = winsize();
2118
1976
  pty.resize(rows, cols);
2119
1977
  screen.resize(rows, cols);
2120
1978
  });
@@ -2128,14 +1986,14 @@ async function main(argv) {
2128
1986
  return;
2129
1987
  writeAll(1, out);
2130
1988
  if (recOut !== null)
2131
- writeSync(recOut, out);
1989
+ writeSync2(recOut, out);
2132
1990
  };
2133
1991
  const closeMenu = () => {
2134
1992
  menu = false;
2135
1993
  screen.invalidate();
2136
1994
  writeAll(1, Buffer.from("\x1B[?25h", "latin1"));
2137
1995
  writeFileSync(CONFIG, JSON.stringify(cfg, null, 2));
2138
- mtime = statSync(CONFIG).mtimeMs;
1996
+ mtime = statSync2(CONFIG).mtimeMs;
2139
1997
  forceRepaint(pty, rows, cols);
2140
1998
  };
2141
1999
  pty.onData((data) => {
@@ -2143,7 +2001,7 @@ async function main(argv) {
2143
2001
  lastData = performance.now();
2144
2002
  repainted = false;
2145
2003
  if (recRaw !== null)
2146
- writeSync(recRaw, data);
2004
+ writeSync2(recRaw, data);
2147
2005
  if (!menu) {
2148
2006
  emit(screen.reconcile(hl.feed(data), hl.rules, hl.onlyUnstyled));
2149
2007
  } else {
@@ -2216,15 +2074,14 @@ async function main(argv) {
2216
2074
  if (toChild.length)
2217
2075
  pty.write(Buffer.from(toChild.join(""), "latin1"));
2218
2076
  };
2219
- const stdinReader = new Worker(workerUrl("pty-read-worker"));
2220
- stdinReader.addEventListener("message", (event) => {
2221
- const chunk = event.data;
2222
- if (chunk === null)
2223
- stdinOpen = false;
2224
- else if (stdinOpen)
2225
- onStdin(Buffer.from(chunk));
2077
+ process.stdin.on("data", (chunk) => {
2078
+ if (stdinOpen)
2079
+ onStdin(chunk);
2080
+ });
2081
+ process.stdin.on("end", () => {
2082
+ stdinOpen = false;
2226
2083
  });
2227
- stdinReader.postMessage({ fd: 0 });
2084
+ process.stdin.resume();
2228
2085
  const tick = () => {
2229
2086
  if (sawData) {
2230
2087
  sawData = false;
@@ -2236,8 +2093,8 @@ async function main(argv) {
2236
2093
  repainted = true;
2237
2094
  forceRepaint(pty, rows, cols);
2238
2095
  }
2239
- if (existsSync(CONFIG) && statSync(CONFIG).mtimeMs !== mtime) {
2240
- mtime = statSync(CONFIG).mtimeMs;
2096
+ if (existsSync2(CONFIG) && statSync2(CONFIG).mtimeMs !== mtime) {
2097
+ mtime = statSync2(CONFIG).mtimeMs;
2241
2098
  cfg = loadConfig();
2242
2099
  hl.rules = buildRules(cfg);
2243
2100
  hl.onlyUnstyled = cfg.prose_only;
@@ -2249,9 +2106,8 @@ async function main(argv) {
2249
2106
  const timer = setInterval(tick, IDLE);
2250
2107
  await pty.drained;
2251
2108
  clearInterval(timer);
2252
- stdinReader.terminate();
2253
- if (old !== null)
2254
- restoreStdin(old);
2109
+ process.stdin.pause();
2110
+ restoreStdin?.();
2255
2111
  try {
2256
2112
  emit(hl.drain(true));
2257
2113
  } catch {}
@@ -2259,7 +2115,7 @@ async function main(argv) {
2259
2115
  pty.destroy();
2260
2116
  return code;
2261
2117
  }
2262
- if (import.meta.main) {
2118
+ if (__require.main == __require.module) {
2263
2119
  process.exit(await main(process.argv.slice(2)));
2264
2120
  }
2265
2121
  export {