@bash0816/claude-code 2.1.161 → 2.1.176

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.
@@ -11,6 +11,7 @@ TERMUX_TMPDIR="${TMPDIR:-/data/data/com.termux/files/usr/tmp}"
11
11
  SSL_CERT_DIR="${SSL_CERT_DIR:-/data/data/com.termux/files/usr/etc/tls}"
12
12
  SSL_CERT_FILE="${SSL_CERT_FILE:-/data/data/com.termux/files/usr/etc/tls/cert.pem}"
13
13
  DISABLE_AUTOUPDATER="${DISABLE_AUTOUPDATER:-1}"
14
+ NODE="${MAGI_NODE:-node}"
14
15
 
15
16
  need_cmd() {
16
17
  if ! command -v "$1" >/dev/null 2>&1; then
@@ -19,8 +20,16 @@ need_cmd() {
19
20
  fi
20
21
  }
21
22
 
22
- need_cmd node
23
- need_cmd termux-open-url
23
+ if ! "$NODE" --version >/dev/null 2>&1; then
24
+ echo "Missing required node: ${NODE}" >&2
25
+ exit 1
26
+ fi
27
+ if [ -z "${MAGI_ENV:-}" ]; then
28
+ need_cmd termux-open-url
29
+ else
30
+ command -v termux-open-url >/dev/null 2>&1 \
31
+ || echo "[claude-code] termux-open-url not found; URL opening unavailable" >&2
32
+ fi
24
33
 
25
34
  if [ ! -f "${SOURCE_BIN}" ]; then
26
35
  echo "Missing source binary: ${SOURCE_BIN}" >&2
@@ -48,8 +57,13 @@ for _a in "$@"; do
48
57
  esac
49
58
  done
50
59
 
60
+ _tui=0
61
+ if [ "$_pf" = "0" ] && [ -t 0 ]; then
62
+ _tui=1
63
+ fi
64
+
51
65
  if [ "$_pf" = "1" ] && [ "${CLAUDE_TERMUX_STDIN:-}" != "inherit" ]; then
52
- _helper=$(mktemp "${TMPDIR:-/tmp}/claude-helper.XXXXXX.js")
66
+ _helper=$(mktemp "${TERMUX_TMPDIR}/claude-helper.XXXXXX.js")
53
67
  trap 'rm -f "$_helper"' EXIT HUP INT TERM
54
68
  cat <<'NODE' > "$_helper"
55
69
  const fs = require('fs');
@@ -73,8 +87,39 @@ class RequestedExit extends Error {
73
87
  }
74
88
  }
75
89
 
90
+ function cleanupStaleEntryFiles(currentWorkdir = workdir, currentEntryJsOffset = entryJsOffset, currentEntryEndOffset = entryEndOffset, now = Date.now()) {
91
+ const prefix = `cli.${currentEntryJsOffset}.${currentEntryEndOffset}.`;
92
+ const suffix = '.bare-path.js';
93
+ const maxAgeMs = 24 * 60 * 60 * 1000;
94
+ let entries;
95
+ try {
96
+ entries = fs.readdirSync(currentWorkdir, { withFileTypes: true });
97
+ } catch {
98
+ return;
99
+ }
100
+ for (const entry of entries) {
101
+ if (!entry.isFile() && !entry.isSymbolicLink()) continue;
102
+ if (!entry.name.startsWith(prefix) || !entry.name.endsWith(suffix)) continue;
103
+ const filePath = path.join(currentWorkdir, entry.name);
104
+ let stats;
105
+ try {
106
+ stats = fs.statSync(filePath);
107
+ } catch {
108
+ continue;
109
+ }
110
+ if (Number.isFinite(stats.mtimeMs) && now - stats.mtimeMs < maxAgeMs) continue;
111
+ try {
112
+ fs.rmSync(filePath, { force: true });
113
+ } catch {}
114
+ }
115
+ }
116
+
76
117
  function ensureEntryFile() {
77
- const extractedFile = path.join(workdir, `cli.${entryJsOffset}.${entryEndOffset}.bare-path.js`);
118
+ cleanupStaleEntryFiles();
119
+ const extractedFile = path.join(
120
+ workdir,
121
+ `cli.${entryJsOffset}.${entryEndOffset}.${process.pid}.${Date.now().toString(36)}.${Math.random().toString(36).slice(2)}.bare-path.js`,
122
+ );
78
123
  const len = entryEndOffset - entryJsOffset;
79
124
  if (!(len > 0)) throw new Error('invalid replay offsets');
80
125
 
@@ -87,15 +132,165 @@ function ensureEntryFile() {
87
132
  return extractedFile;
88
133
  }
89
134
 
135
+ function isFullWidthCodePoint(codePoint) {
136
+ return Number.isFinite(codePoint) && (
137
+ codePoint >= 0x1100 && (
138
+ codePoint <= 0x115f ||
139
+ codePoint === 0x2329 ||
140
+ codePoint === 0x232a ||
141
+ (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
142
+ (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
143
+ (codePoint >= 0xf900 && codePoint <= 0xfaff) ||
144
+ (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
145
+ (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
146
+ (codePoint >= 0xff00 && codePoint <= 0xff60) ||
147
+ (codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
148
+ (codePoint >= 0x1f300 && codePoint <= 0x1f6ff) ||
149
+ (codePoint >= 0x1fa70 && codePoint <= 0x1faff) ||
150
+ (codePoint >= 0x1f900 && codePoint <= 0x1f9ff) ||
151
+ (codePoint >= 0x20000 && codePoint <= 0x3fffd)
152
+ )
153
+ );
154
+ }
155
+
156
+ function graphemeWidth(grapheme) {
157
+ let width = 0;
158
+ const symbols = Array.from(String(grapheme ?? ''));
159
+ const codePoints = symbols.map(symbol => symbol.codePointAt(0)).filter(codePoint => Number.isFinite(codePoint));
160
+ if (codePoints.length === 0) return 0;
161
+ if (codePoints.length > 1 && codePoints.every(codePoint => codePoint >= 0x1f1e6 && codePoint <= 0x1f1ff)) {
162
+ return 2;
163
+ }
164
+ if (codePoints.includes(0x20e3) || codePoints.includes(0x200d)) {
165
+ return 2;
166
+ }
167
+ if (codePoints.includes(0xfe0f) || codePoints.some(codePoint => codePoint >= 0x2600 && codePoint <= 0x27bf)) {
168
+ return 2;
169
+ }
170
+ for (const symbol of symbols) {
171
+ const codePoint = symbol.codePointAt(0);
172
+ if (codePoint === undefined || codePoint === 0) continue;
173
+ if (codePoint < 32 || (codePoint >= 0x7f && codePoint < 0xa0)) continue;
174
+ if (codePoint === 0x200d || codePoint === 0xfe0f) continue;
175
+ if (/\p{M}/u.test(symbol)) continue;
176
+ if (isFullWidthCodePoint(codePoint)) return 2;
177
+ width = 1;
178
+ }
179
+ return width;
180
+ }
181
+
90
182
  function stringWidth(value) {
91
- const text = String(value ?? '');
183
+ const text = stripANSI(value);
92
184
  if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
93
185
  const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
94
186
  let width = 0;
95
- for (const _segment of segmenter.segment(text)) width += 1;
187
+ for (const segment of segmenter.segment(text)) width += graphemeWidth(segment.segment);
96
188
  return width;
97
189
  }
98
- return Array.from(text).length;
190
+ return Array.from(text).reduce((width, symbol) => width + graphemeWidth(symbol), 0);
191
+ }
192
+
193
+ function stripANSI(value) {
194
+ return String(value ?? '')
195
+ .replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '')
196
+ .replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '');
197
+ }
198
+
199
+ function wrapAnsi(value, columns, options = {}) {
200
+ const text = String(value ?? '');
201
+ const width = Number(columns);
202
+ const hard = options.hard !== false;
203
+ const trim = options.trim === true;
204
+ const wordWrap = options.wordWrap !== false;
205
+ if (!Number.isFinite(width) || width <= 0) return trim ? text.trimEnd() : text;
206
+
207
+ const ansiPattern = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
208
+ const segmenter = typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'
209
+ ? new Intl.Segmenter('en', { granularity: 'grapheme' })
210
+ : null;
211
+ const splitVisible = (chunk) => {
212
+ if (chunk === '') return [];
213
+ if (!segmenter) return Array.from(chunk);
214
+ return Array.from(segmenter.segment(chunk), part => part.segment);
215
+ };
216
+ const splitByGrapheme = hard || !wordWrap;
217
+ let result = '';
218
+ let currentWidth = 0;
219
+ let lastIndex = 0;
220
+ const appendVisible = (chunk) => {
221
+ const tokens = splitByGrapheme ? splitVisible(chunk) : (chunk.match(/\s+|[^\s]+/gu) || []);
222
+ for (const token of tokens) {
223
+ if (token === '\n') {
224
+ if (trim) result = result.replace(/[ \t]+$/g, '');
225
+ result += token;
226
+ currentWidth = 0;
227
+ continue;
228
+ }
229
+ const tokenWidth = stringWidth(token);
230
+ const isWhitespace = /^\s+$/u.test(token);
231
+ if (trim && isWhitespace && currentWidth === 0) continue;
232
+ if (currentWidth > 0 && currentWidth + tokenWidth > width) {
233
+ if (!splitByGrapheme && !isWhitespace) {
234
+ result = result.replace(/[ \t]+$/g, '');
235
+ result += '\n';
236
+ currentWidth = 0;
237
+ } else {
238
+ for (const piece of splitVisible(token)) {
239
+ const pieceWidth = stringWidth(piece);
240
+ if (currentWidth > 0 && currentWidth + pieceWidth > width) {
241
+ if (trim) result = result.replace(/[ \t]+$/g, '');
242
+ result += '\n';
243
+ currentWidth = 0;
244
+ }
245
+ if (trim && /^\s+$/u.test(piece) && currentWidth === 0) continue;
246
+ result += piece;
247
+ currentWidth += pieceWidth;
248
+ }
249
+ continue;
250
+ }
251
+ }
252
+ result += token;
253
+ currentWidth += tokenWidth;
254
+ }
255
+ };
256
+ for (const match of text.matchAll(ansiPattern)) {
257
+ appendVisible(text.slice(lastIndex, match.index ?? 0));
258
+ result += match[0];
259
+ lastIndex = (match.index ?? 0) + match[0].length;
260
+ }
261
+ appendVisible(text.slice(lastIndex));
262
+ return trim ? result.replace(/[ \t]+$/gm, '') : result;
263
+ }
264
+
265
+ function stableHash(value, seed) {
266
+ const text = String(value ?? '');
267
+ let hash = 2166136261;
268
+ if (seed !== undefined) {
269
+ const seedText = String(seed ?? '');
270
+ for (let i = 0; i < seedText.length; i += 1) {
271
+ hash ^= seedText.charCodeAt(i);
272
+ hash = Math.imul(hash, 16777619);
273
+ }
274
+ hash ^= 0x9e3779b9;
275
+ hash = Math.imul(hash, 16777619);
276
+ }
277
+ for (let i = 0; i < text.length; i += 1) {
278
+ hash ^= text.charCodeAt(i);
279
+ hash = Math.imul(hash, 16777619);
280
+ }
281
+ return hash >>> 0;
282
+ }
283
+
284
+ function replaceRequired(source, pattern, replacement, label, expectedCount) {
285
+ const text = String(source);
286
+ const matches = text.match(pattern);
287
+ if (!matches || matches.length === 0) {
288
+ throw new Error(`rewriteNativeChunkSource: missing ${label}`);
289
+ }
290
+ if (expectedCount !== undefined && matches.length !== expectedCount) {
291
+ throw new Error(`rewriteNativeChunkSource: unexpected ${label} count ${matches.length}`);
292
+ }
293
+ return text.replace(pattern, replacement);
99
294
  }
100
295
 
101
296
  function parseScalar(value) {
@@ -244,6 +439,9 @@ function createFakeRequire(realRequire) {
244
439
  writable: true,
245
440
  });
246
441
  }
442
+ if (context.Bun && globalThis.__claudeYaml) {
443
+ context.Bun.YAML = globalThis.__claudeYaml;
444
+ }
247
445
  } catch {}
248
446
  return context;
249
447
  }
@@ -344,25 +542,60 @@ function createFakeRequire(realRequire) {
344
542
  };
345
543
  }
346
544
 
347
- async function main() {
348
- const extractedFile = ensureEntryFile();
349
- const code = fs.readFileSync(extractedFile, 'utf8');
350
- const patchedCode = code.replace(
351
- /^function\(exports, require, module, __filename, __dirname\) \{/,
352
- 'function(exports, require, module, __filename, __dirname) {var __claudeBun = globalThis.__claudeBunShim;',
353
- ).replace(
545
+ function rewriteNativeChunkSource(source) {
546
+ const rawPrefix = 'function(exports, require, module, __filename, __dirname) {';
547
+ const injectedPrefix = rawPrefix + 'var __claudeBun = globalThis.__claudeBunShim;';
548
+ let patched = String(source);
549
+ patched = replaceRequired(
550
+ patched,
551
+ /^function\(exports, require, module, __filename, __dirname\) \{(?:var __claudeBun = globalThis\.__claudeBunShim;)?/,
552
+ injectedPrefix,
553
+ 'module wrapper prefix',
554
+ 1,
555
+ );
556
+ patched = replaceRequired(
557
+ patched,
354
558
  /\btypeof Bun\b/g,
355
559
  'typeof __claudeBun',
356
- ).replace(
560
+ 'typeof Bun',
561
+ 3,
562
+ );
563
+ patched = replaceRequired(
564
+ patched,
565
+ /\btypeof globalThis\.Bun\b/g,
566
+ 'typeof globalThis.__claudeBun',
567
+ 'typeof globalThis.Bun',
568
+ 1,
569
+ );
570
+ patched = replaceRequired(
571
+ patched,
572
+ /\bglobalThis\.Bun\b/g,
573
+ 'globalThis.__claudeBun',
574
+ 'globalThis.Bun',
575
+ 1,
576
+ );
577
+ patched = replaceRequired(
578
+ patched,
357
579
  /\bBun\./g,
358
580
  '__claudeBun.',
359
- ).replace(
360
- /function t5q\(q\)\{return Bun\.YAML\.parse\(q\)\}/g,
361
- 'function t5q(q){return globalThis.__claudeYaml.parse(q)}',
362
- ).replace(
363
- /function VK6\(q\)\{return Bun\.YAML\.stringify\(q,null,2\)\+`/g,
364
- 'function VK6(q){return globalThis.__claudeYaml.stringify(q,null,2)+`',
581
+ 'Bun property access',
582
+ 33,
365
583
  );
584
+ patched = replaceRequired(
585
+ patched,
586
+ /\bnpmInstallDeprecated:!0\b/g,
587
+ 'npmInstallDeprecated:!1',
588
+ 'npmInstallDeprecated flag',
589
+ 1,
590
+ );
591
+ return patched;
592
+ }
593
+
594
+ async function main() {
595
+ let extractedFile;
596
+ extractedFile = ensureEntryFile();
597
+ const code = fs.readFileSync(extractedFile, 'utf8');
598
+ const patchedCode = rewriteNativeChunkSource(code);
366
599
  const fn = eval('(' + patchedCode.replace(/\)\s*$/, '') + ')');
367
600
 
368
601
  const originalArgv = process.argv.slice();
@@ -389,6 +622,9 @@ async function main() {
389
622
  globalThis.Bun = {
390
623
  version: '1.1.8',
391
624
  stringWidth,
625
+ wrapAnsi,
626
+ stripANSI,
627
+ hash: stableHash,
392
628
  which: (cmd) => {
393
629
  try {
394
630
  return _realChild.execFileSync('which', [String(cmd)], { encoding: 'utf8' }).trim() || null;
@@ -424,9 +660,9 @@ async function main() {
424
660
  gte: (a, b) => _cmp(a, b) >= 0,
425
661
  lt: (a, b) => _cmp(a, b) < 0,
426
662
  lte: (a, b) => _cmp(a, b) <= 0,
427
- };
428
- })(),
429
- YAML: globalThis.__claudeYaml,
663
+ };
664
+ })(),
665
+ YAML: globalThis.__claudeYaml,
430
666
  };
431
667
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
432
668
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -439,10 +675,13 @@ async function main() {
439
675
  throw new RequestedExit(code);
440
676
  };
441
677
 
678
+ const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
442
679
  const moduleLike = { exports: {} };
443
680
  const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
444
681
  if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
445
- await new Promise(resolve => setTimeout(resolve, 5000));
682
+ if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
683
+ await new Promise(resolve => setTimeout(resolve, printWaitMs));
684
+ }
446
685
  if (asyncErrors.length > 0) throw asyncErrors[0];
447
686
  } catch (error) {
448
687
  if (error instanceof RequestedExit) {
@@ -453,6 +692,11 @@ async function main() {
453
692
  } finally {
454
693
  process.removeListener('uncaughtException', onAsyncError);
455
694
  process.removeListener('unhandledRejection', onAsyncError);
695
+ if (extractedFile) {
696
+ try {
697
+ fs.rmSync(extractedFile, { force: true });
698
+ } catch {}
699
+ }
456
700
  process.argv = originalArgv;
457
701
  process.exit = originalExit;
458
702
  try {
@@ -482,14 +726,16 @@ NODE
482
726
  export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="${CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:-1}"
483
727
  export ENABLE_CLAUDEAI_MCP_SERVERS="${ENABLE_CLAUDEAI_MCP_SERVERS:-0}"
484
728
  export CLAUDE_CODE_SIMPLE="${CLAUDE_CODE_SIMPLE:-0}"
485
- node "$_helper" "$@" </dev/null
729
+ export DISABLE_INSTALLATION_CHECKS="${DISABLE_INSTALLATION_CHECKS:-true}"
730
+ "$NODE" "$_helper" "$@" </dev/null
486
731
  _status=$?
487
732
  rm -f "$_helper"
488
733
  trap - EXIT HUP INT TERM
489
734
  exit "$_status"
490
735
  else
491
- _bootstrap=$(mktemp "${TMPDIR:-/tmp}/claude-bootstrap.XXXXXX.js")
736
+ _bootstrap=$(mktemp "${TERMUX_TMPDIR}/claude-bootstrap.XXXXXX.js")
492
737
  trap 'rm -f "$_bootstrap"' EXIT HUP INT TERM
738
+ export CLAUDE_TERMUX_TUI="${_tui}"
493
739
  cat <<'NODE' > "$_bootstrap"
494
740
  const fs = require('fs');
495
741
  const path = require('path');
@@ -512,8 +758,39 @@ class RequestedExit extends Error {
512
758
  }
513
759
  }
514
760
 
761
+ function cleanupStaleEntryFiles(currentWorkdir = workdir, currentEntryJsOffset = entryJsOffset, currentEntryEndOffset = entryEndOffset, now = Date.now()) {
762
+ const prefix = `cli.${currentEntryJsOffset}.${currentEntryEndOffset}.`;
763
+ const suffix = '.bare-path.js';
764
+ const maxAgeMs = 24 * 60 * 60 * 1000;
765
+ let entries;
766
+ try {
767
+ entries = fs.readdirSync(currentWorkdir, { withFileTypes: true });
768
+ } catch {
769
+ return;
770
+ }
771
+ for (const entry of entries) {
772
+ if (!entry.isFile() && !entry.isSymbolicLink()) continue;
773
+ if (!entry.name.startsWith(prefix) || !entry.name.endsWith(suffix)) continue;
774
+ const filePath = path.join(currentWorkdir, entry.name);
775
+ let stats;
776
+ try {
777
+ stats = fs.statSync(filePath);
778
+ } catch {
779
+ continue;
780
+ }
781
+ if (Number.isFinite(stats.mtimeMs) && now - stats.mtimeMs < maxAgeMs) continue;
782
+ try {
783
+ fs.rmSync(filePath, { force: true });
784
+ } catch {}
785
+ }
786
+ }
787
+
515
788
  function ensureEntryFile() {
516
- const extractedFile = path.join(workdir, `cli.${entryJsOffset}.${entryEndOffset}.bare-path.js`);
789
+ cleanupStaleEntryFiles();
790
+ const extractedFile = path.join(
791
+ workdir,
792
+ `cli.${entryJsOffset}.${entryEndOffset}.${process.pid}.${Date.now().toString(36)}.${Math.random().toString(36).slice(2)}.bare-path.js`,
793
+ );
517
794
  const len = entryEndOffset - entryJsOffset;
518
795
  if (!(len > 0)) throw new Error('invalid replay offsets');
519
796
 
@@ -526,15 +803,165 @@ function ensureEntryFile() {
526
803
  return extractedFile;
527
804
  }
528
805
 
806
+ function isFullWidthCodePoint(codePoint) {
807
+ return Number.isFinite(codePoint) && (
808
+ codePoint >= 0x1100 && (
809
+ codePoint <= 0x115f ||
810
+ codePoint === 0x2329 ||
811
+ codePoint === 0x232a ||
812
+ (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
813
+ (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
814
+ (codePoint >= 0xf900 && codePoint <= 0xfaff) ||
815
+ (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
816
+ (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
817
+ (codePoint >= 0xff00 && codePoint <= 0xff60) ||
818
+ (codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
819
+ (codePoint >= 0x1f300 && codePoint <= 0x1f6ff) ||
820
+ (codePoint >= 0x1fa70 && codePoint <= 0x1faff) ||
821
+ (codePoint >= 0x1f900 && codePoint <= 0x1f9ff) ||
822
+ (codePoint >= 0x20000 && codePoint <= 0x3fffd)
823
+ )
824
+ );
825
+ }
826
+
827
+ function graphemeWidth(grapheme) {
828
+ let width = 0;
829
+ const symbols = Array.from(String(grapheme ?? ''));
830
+ const codePoints = symbols.map(symbol => symbol.codePointAt(0)).filter(codePoint => Number.isFinite(codePoint));
831
+ if (codePoints.length === 0) return 0;
832
+ if (codePoints.length > 1 && codePoints.every(codePoint => codePoint >= 0x1f1e6 && codePoint <= 0x1f1ff)) {
833
+ return 2;
834
+ }
835
+ if (codePoints.includes(0x20e3) || codePoints.includes(0x200d)) {
836
+ return 2;
837
+ }
838
+ if (codePoints.includes(0xfe0f) || codePoints.some(codePoint => codePoint >= 0x2600 && codePoint <= 0x27bf)) {
839
+ return 2;
840
+ }
841
+ for (const symbol of symbols) {
842
+ const codePoint = symbol.codePointAt(0);
843
+ if (codePoint === undefined || codePoint === 0) continue;
844
+ if (codePoint < 32 || (codePoint >= 0x7f && codePoint < 0xa0)) continue;
845
+ if (codePoint === 0x200d || codePoint === 0xfe0f) continue;
846
+ if (/\p{M}/u.test(symbol)) continue;
847
+ if (isFullWidthCodePoint(codePoint)) return 2;
848
+ width = 1;
849
+ }
850
+ return width;
851
+ }
852
+
529
853
  function stringWidth(value) {
530
- const text = String(value ?? '');
854
+ const text = stripANSI(value);
531
855
  if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
532
856
  const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
533
857
  let width = 0;
534
- for (const _segment of segmenter.segment(text)) width += 1;
858
+ for (const segment of segmenter.segment(text)) width += graphemeWidth(segment.segment);
535
859
  return width;
536
860
  }
537
- return Array.from(text).length;
861
+ return Array.from(text).reduce((width, symbol) => width + graphemeWidth(symbol), 0);
862
+ }
863
+
864
+ function stripANSI(value) {
865
+ return String(value ?? '')
866
+ .replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '')
867
+ .replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '');
868
+ }
869
+
870
+ function wrapAnsi(value, columns, options = {}) {
871
+ const text = String(value ?? '');
872
+ const width = Number(columns);
873
+ const hard = options.hard !== false;
874
+ const trim = options.trim === true;
875
+ const wordWrap = options.wordWrap !== false;
876
+ if (!Number.isFinite(width) || width <= 0) return trim ? text.trimEnd() : text;
877
+
878
+ const ansiPattern = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\][^\x07]*(?:\x07|\x1B\\)/g;
879
+ const segmenter = typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'
880
+ ? new Intl.Segmenter('en', { granularity: 'grapheme' })
881
+ : null;
882
+ const splitVisible = (chunk) => {
883
+ if (chunk === '') return [];
884
+ if (!segmenter) return Array.from(chunk);
885
+ return Array.from(segmenter.segment(chunk), part => part.segment);
886
+ };
887
+ const splitByGrapheme = hard || !wordWrap;
888
+ let result = '';
889
+ let currentWidth = 0;
890
+ let lastIndex = 0;
891
+ const appendVisible = (chunk) => {
892
+ const tokens = splitByGrapheme ? splitVisible(chunk) : (chunk.match(/\s+|[^\s]+/gu) || []);
893
+ for (const token of tokens) {
894
+ if (token === '\n') {
895
+ if (trim) result = result.replace(/[ \t]+$/g, '');
896
+ result += token;
897
+ currentWidth = 0;
898
+ continue;
899
+ }
900
+ const tokenWidth = stringWidth(token);
901
+ const isWhitespace = /^\s+$/u.test(token);
902
+ if (trim && isWhitespace && currentWidth === 0) continue;
903
+ if (currentWidth > 0 && currentWidth + tokenWidth > width) {
904
+ if (!splitByGrapheme && !isWhitespace) {
905
+ result = result.replace(/[ \t]+$/g, '');
906
+ result += '\n';
907
+ currentWidth = 0;
908
+ } else {
909
+ for (const piece of splitVisible(token)) {
910
+ const pieceWidth = stringWidth(piece);
911
+ if (currentWidth > 0 && currentWidth + pieceWidth > width) {
912
+ if (trim) result = result.replace(/[ \t]+$/g, '');
913
+ result += '\n';
914
+ currentWidth = 0;
915
+ }
916
+ if (trim && /^\s+$/u.test(piece) && currentWidth === 0) continue;
917
+ result += piece;
918
+ currentWidth += pieceWidth;
919
+ }
920
+ continue;
921
+ }
922
+ }
923
+ result += token;
924
+ currentWidth += tokenWidth;
925
+ }
926
+ };
927
+ for (const match of text.matchAll(ansiPattern)) {
928
+ appendVisible(text.slice(lastIndex, match.index ?? 0));
929
+ result += match[0];
930
+ lastIndex = (match.index ?? 0) + match[0].length;
931
+ }
932
+ appendVisible(text.slice(lastIndex));
933
+ return trim ? result.replace(/[ \t]+$/gm, '') : result;
934
+ }
935
+
936
+ function stableHash(value, seed) {
937
+ const text = String(value ?? '');
938
+ let hash = 2166136261;
939
+ if (seed !== undefined) {
940
+ const seedText = String(seed ?? '');
941
+ for (let i = 0; i < seedText.length; i += 1) {
942
+ hash ^= seedText.charCodeAt(i);
943
+ hash = Math.imul(hash, 16777619);
944
+ }
945
+ hash ^= 0x9e3779b9;
946
+ hash = Math.imul(hash, 16777619);
947
+ }
948
+ for (let i = 0; i < text.length; i += 1) {
949
+ hash ^= text.charCodeAt(i);
950
+ hash = Math.imul(hash, 16777619);
951
+ }
952
+ return hash >>> 0;
953
+ }
954
+
955
+ function replaceRequired(source, pattern, replacement, label, expectedCount) {
956
+ const text = String(source);
957
+ const matches = text.match(pattern);
958
+ if (!matches || matches.length === 0) {
959
+ throw new Error(`rewriteNativeChunkSource: missing ${label}`);
960
+ }
961
+ if (expectedCount !== undefined && matches.length !== expectedCount) {
962
+ throw new Error(`rewriteNativeChunkSource: unexpected ${label} count ${matches.length}`);
963
+ }
964
+ return text.replace(pattern, replacement);
538
965
  }
539
966
 
540
967
  function parseScalar(value) {
@@ -633,6 +1060,63 @@ function createFakeRequire(realRequire) {
633
1060
  const realChild = realRequire('child_process');
634
1061
  const realVm = realRequire('vm');
635
1062
 
1063
+ function injectBunIntoContext(context) {
1064
+ if (!context || typeof context !== 'object') return context;
1065
+ try {
1066
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeYaml')) {
1067
+ Object.defineProperty(context, '__claudeYaml', {
1068
+ value: globalThis.__claudeYaml,
1069
+ configurable: true,
1070
+ writable: true,
1071
+ });
1072
+ }
1073
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeBunShim')) {
1074
+ Object.defineProperty(context, '__claudeBunShim', {
1075
+ value: globalThis.__claudeBunShim,
1076
+ configurable: true,
1077
+ writable: true,
1078
+ });
1079
+ }
1080
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeBun')) {
1081
+ Object.defineProperty(context, '__claudeBun', {
1082
+ value: globalThis.__claudeBunShim,
1083
+ configurable: true,
1084
+ writable: true,
1085
+ });
1086
+ }
1087
+ if (Object.prototype.hasOwnProperty.call(context, 'Bun')) {
1088
+ if (context.Bun && typeof context.Bun === 'object' && context.Bun !== globalThis.Bun) {
1089
+ try {
1090
+ context.Bun = globalThis.Bun;
1091
+ } catch {
1092
+ Object.defineProperty(context, 'Bun', {
1093
+ value: globalThis.Bun,
1094
+ configurable: true,
1095
+ writable: true,
1096
+ });
1097
+ }
1098
+ }
1099
+ if (!context.Bun || typeof context.Bun !== 'object') {
1100
+ Object.defineProperty(context, 'Bun', {
1101
+ value: globalThis.Bun,
1102
+ configurable: true,
1103
+ writable: true,
1104
+ });
1105
+ }
1106
+ } else {
1107
+ Object.defineProperty(context, 'Bun', {
1108
+ value: globalThis.Bun,
1109
+ configurable: true,
1110
+ writable: true,
1111
+ });
1112
+ }
1113
+ if (context.Bun && globalThis.__claudeYaml) {
1114
+ context.Bun.YAML = globalThis.__claudeYaml;
1115
+ }
1116
+ } catch {}
1117
+ return context;
1118
+ }
1119
+
636
1120
  function rewriteArgs(args) {
637
1121
  if (
638
1122
  Array.isArray(args) &&
@@ -729,25 +1213,60 @@ function createFakeRequire(realRequire) {
729
1213
  };
730
1214
  }
731
1215
 
732
- async function main() {
733
- const extractedFile = ensureEntryFile();
734
- const code = fs.readFileSync(extractedFile, 'utf8');
735
- const patchedCode = code.replace(
736
- /^function\(exports, require, module, __filename, __dirname\) \{/,
737
- 'function(exports, require, module, __filename, __dirname) {var __claudeBun = globalThis.__claudeBunShim;',
738
- ).replace(
1216
+ function rewriteNativeChunkSource(source) {
1217
+ const rawPrefix = 'function(exports, require, module, __filename, __dirname) {';
1218
+ const injectedPrefix = rawPrefix + 'var __claudeBun = globalThis.__claudeBunShim;';
1219
+ let patched = String(source);
1220
+ patched = replaceRequired(
1221
+ patched,
1222
+ /^function\(exports, require, module, __filename, __dirname\) \{(?:var __claudeBun = globalThis\.__claudeBunShim;)?/,
1223
+ injectedPrefix,
1224
+ 'module wrapper prefix',
1225
+ 1,
1226
+ );
1227
+ patched = replaceRequired(
1228
+ patched,
739
1229
  /\btypeof Bun\b/g,
740
1230
  'typeof __claudeBun',
741
- ).replace(
1231
+ 'typeof Bun',
1232
+ 3,
1233
+ );
1234
+ patched = replaceRequired(
1235
+ patched,
1236
+ /\btypeof globalThis\.Bun\b/g,
1237
+ 'typeof globalThis.__claudeBun',
1238
+ 'typeof globalThis.Bun',
1239
+ 1,
1240
+ );
1241
+ patched = replaceRequired(
1242
+ patched,
1243
+ /\bglobalThis\.Bun\b/g,
1244
+ 'globalThis.__claudeBun',
1245
+ 'globalThis.Bun',
1246
+ 1,
1247
+ );
1248
+ patched = replaceRequired(
1249
+ patched,
742
1250
  /\bBun\./g,
743
1251
  '__claudeBun.',
744
- ).replace(
745
- /function t5q\(q\)\{return Bun\.YAML\.parse\(q\)\}/g,
746
- 'function t5q(q){return globalThis.__claudeYaml.parse(q)}',
747
- ).replace(
748
- /function VK6\(q\)\{return Bun\.YAML\.stringify\(q,null,2\)\+`/g,
749
- 'function VK6(q){return globalThis.__claudeYaml.stringify(q,null,2)+`',
1252
+ 'Bun property access',
1253
+ 33,
1254
+ );
1255
+ patched = replaceRequired(
1256
+ patched,
1257
+ /\bnpmInstallDeprecated:!0\b/g,
1258
+ 'npmInstallDeprecated:!1',
1259
+ 'npmInstallDeprecated flag',
1260
+ 1,
750
1261
  );
1262
+ return patched;
1263
+ }
1264
+
1265
+ async function main() {
1266
+ let extractedFile;
1267
+ extractedFile = ensureEntryFile();
1268
+ const code = fs.readFileSync(extractedFile, 'utf8');
1269
+ const patchedCode = rewriteNativeChunkSource(code);
751
1270
  const fn = eval('(' + patchedCode.replace(/\)\s*$/, '') + ')');
752
1271
 
753
1272
  const originalArgv = process.argv.slice();
@@ -774,6 +1293,9 @@ async function main() {
774
1293
  globalThis.Bun = {
775
1294
  version: '1.1.8',
776
1295
  stringWidth,
1296
+ wrapAnsi,
1297
+ stripANSI,
1298
+ hash: stableHash,
777
1299
  which: (cmd) => {
778
1300
  try {
779
1301
  return _realChild.execFileSync('which', [String(cmd)], { encoding: 'utf8' }).trim() || null;
@@ -810,8 +1332,8 @@ async function main() {
810
1332
  lt: (a, b) => _cmp(a, b) < 0,
811
1333
  lte: (a, b) => _cmp(a, b) <= 0,
812
1334
  };
813
- })(),
814
- YAML: globalThis.__claudeYaml,
1335
+ })(),
1336
+ YAML: globalThis.__claudeYaml,
815
1337
  };
816
1338
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
817
1339
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -827,8 +1349,6 @@ async function main() {
827
1349
  const moduleLike = { exports: {} };
828
1350
  const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
829
1351
  if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
830
- const _waitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 200);
831
- await new Promise(resolve => setTimeout(resolve, _waitMs));
832
1352
  if (asyncErrors.length > 0) throw asyncErrors[0];
833
1353
  } catch (error) {
834
1354
  if (error instanceof RequestedExit) {
@@ -841,32 +1361,49 @@ async function main() {
841
1361
  process.removeListener('unhandledRejection', onAsyncError);
842
1362
  process.argv = originalArgv;
843
1363
  process.exit = originalExit;
844
- try {
845
- if (originalBun === undefined) {
846
- delete process.versions.bun;
847
- } else {
848
- Object.defineProperty(process.versions, 'bun', { value: originalBun, configurable: true });
1364
+ process.once('exit', () => {
1365
+ if (extractedFile) {
1366
+ try {
1367
+ fs.rmSync(extractedFile, { force: true });
1368
+ } catch {}
849
1369
  }
850
- } catch {}
851
- delete globalThis.__claudeYaml;
852
- delete globalThis.__claudeBunShim;
853
- delete globalThis.__claudeBun;
854
- if (hadGlobalBun) globalThis.Bun = originalGlobalBun;
1370
+ try {
1371
+ if (originalBun === undefined) {
1372
+ delete process.versions.bun;
1373
+ } else {
1374
+ Object.defineProperty(process.versions, 'bun', { value: originalBun, configurable: true });
1375
+ }
1376
+ } catch {}
1377
+ delete globalThis.__claudeYaml;
1378
+ delete globalThis.__claudeBunShim;
1379
+ delete globalThis.__claudeBun;
1380
+ if (hadGlobalBun) globalThis.Bun = originalGlobalBun;
1381
+ else delete globalThis.Bun;
1382
+ });
855
1383
  }
856
1384
  }
857
1385
 
858
- main().catch(error => {
859
- if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
860
- console.error(BLOCK_MESSAGE);
861
- process.exit(error.status || 1);
862
- }
863
- console.error(error && error.stack ? error.stack : String(error));
864
- process.exit(1);
865
- });
1386
+ main()
1387
+ .then(() => {
1388
+ if (process.env.CLAUDE_TERMUX_TUI === '1' && process.exitCode === undefined) {
1389
+ return;
1390
+ }
1391
+ process.exit(process.exitCode ?? 0);
1392
+ })
1393
+ .catch(error => {
1394
+ if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
1395
+ console.error(BLOCK_MESSAGE);
1396
+ process.exit(error.status || 1);
1397
+ return;
1398
+ }
1399
+ console.error(error && error.stack ? error.stack : String(error));
1400
+ process.exit(1);
1401
+ });
866
1402
  NODE
867
1403
  export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="${CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:-1}"
868
1404
  export ENABLE_CLAUDEAI_MCP_SERVERS="${ENABLE_CLAUDEAI_MCP_SERVERS:-0}"
869
- node "$_bootstrap" "$@"
1405
+ export DISABLE_INSTALLATION_CHECKS="${DISABLE_INSTALLATION_CHECKS:-true}"
1406
+ "$NODE" "$_bootstrap" "$@"
870
1407
  _status=$?
871
1408
  rm -f "$_bootstrap"
872
1409
  trap - EXIT HUP INT TERM