@bash0816/claude-code 2.1.222 → 2.1.223

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/README.md CHANGED
@@ -37,7 +37,7 @@ npm が `claude` bin link を管理する状態になれば、通常の `npm ins
37
37
  Latest audited version / 最新監査済み版:
38
38
 
39
39
  ```sh
40
- npm install -g @bash0816/claude-code@2.1.220-2
40
+ npm install -g @bash0816/claude-code@2.1.222
41
41
  ```
42
42
 
43
43
  ## Update / 更新
@@ -616,6 +616,24 @@
616
616
  "entry_end_offset": 279849039,
617
617
  "tarball_integrity": "sha512-EXSediF1ujcqQeElbXdCEe+uW3NUQAOjn1xHHAgvwzY08nzJeePjagn9+YS6bmhHxBgDKwlGu7pL8Kv7EpiFtg==",
618
618
  "tarball_sha256": "1bb3c8364d652dd08a15856ee27c6600ecd1e45360243154fa846f240ce7a1df",
619
+ "status": "termux_verified"
620
+ },
621
+ "2.1.222-1": {
622
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.222",
623
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.222",
624
+ "entry_js_offset": 256895476,
625
+ "entry_end_offset": 279849039,
626
+ "tarball_integrity": "sha512-EXSediF1ujcqQeElbXdCEe+uW3NUQAOjn1xHHAgvwzY08nzJeePjagn9+YS6bmhHxBgDKwlGu7pL8Kv7EpiFtg==",
627
+ "tarball_sha256": "1bb3c8364d652dd08a15856ee27c6600ecd1e45360243154fa846f240ce7a1df",
628
+ "status": "offset_discovered"
629
+ },
630
+ "2.1.223": {
631
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.223",
632
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.223",
633
+ "entry_js_offset": 257987828,
634
+ "entry_end_offset": 281109040,
635
+ "tarball_integrity": "sha512-gh0n3fvUgzsrjeTqZraOhDKOzS7afB9U/qFvRY0FBpccogbJCk8otTYavPfdhAA2xESAoA0BaoVdzO4k4VkphA==",
636
+ "tarball_sha256": "29c49ec62bfbe995e5b1354a4c32d17101065d2c7722d5d0285cfa6a08d8c441",
619
637
  "status": "offset_discovered"
620
638
  }
621
639
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "manifest_version": 1,
3
3
  "package_name": "@bash0816/claude-code",
4
- "latest_audited_version": "2.1.220-2",
5
- "latest_candidate_version": "2.1.222",
6
- "previous_stable_version": "2.1.220",
4
+ "latest_audited_version": "2.1.222",
5
+ "latest_candidate_version": "2.1.223",
6
+ "previous_stable_version": "2.1.220-2",
7
7
  "stable_pinned_version": "2.1.193",
8
8
  "manifest_url": "https://raw.githubusercontent.com/bash0816/ClaudeCode-Termux/main/config/claude-termux-release-manifest.json"
9
9
  }
@@ -599,6 +599,7 @@ function rewriteNativeChunkSource(source) {
599
599
  const _bunPropertyAccessExpected = (() => {
600
600
  const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
601
601
  const _m = _ver.match(/^(\d+)\.(\d+)\.(\d+)/);
602
+ if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 223)) return 43;
602
603
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
603
604
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 216)) return 40;
604
605
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 214)) return 39;
@@ -627,6 +628,13 @@ function rewriteNativeChunkSource(source) {
627
628
  'npmInstallDeprecated flag',
628
629
  _npmInstallDeprecatedExpected,
629
630
  );
631
+ patched = replaceRequired(
632
+ patched,
633
+ /function ([A-Za-z_$][\w$]*)\(\)\{(return\([A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*\)=>\{let\{cmd:([A-Za-z_$][\w$]*),prefixArgs:([A-Za-z_$][\w$]*)\}=[A-Za-z_$][\w$]*\(\{pinToCurrentBinary:!0\}\),[A-Za-z_$][\w$]*=\[\3,\.\.\.\4,"--bg-pty-host")/g,
634
+ 'function $1(){return undefined;$2',
635
+ 'bg-pty-host factory disable',
636
+ 1,
637
+ );
630
638
  return patched;
631
639
  }
632
640
 
@@ -795,9 +803,47 @@ async function main() {
795
803
  gte: (a, b) => _cmp(a, b) >= 0,
796
804
  lt: (a, b) => _cmp(a, b) < 0,
797
805
  lte: (a, b) => _cmp(a, b) <= 0,
798
- };
806
+ };
799
807
  })(),
800
808
  YAML: globalThis.__claudeYaml,
809
+ spawn: (cmd, options) => {
810
+ const opts = options || {};
811
+ const stdioArrayRaw = opts.stdio;
812
+ const cmdArray = Array.isArray(cmd) ? cmd : [cmd];
813
+ const normalizeStdio = (v) => {
814
+ if (typeof v === 'number' && Number.isInteger(v) && v >= 0) return v;
815
+ return (v === 'ignore' || v === 'pipe' || v === 'inherit') ? v : 'pipe';
816
+ };
817
+ const stdioMapped = Array.isArray(stdioArrayRaw)
818
+ ? stdioArrayRaw.map(normalizeStdio)
819
+ : [normalizeStdio(opts.stdin), normalizeStdio(opts.stdout), normalizeStdio(opts.stderr)];
820
+ const child = _realChild.spawn(cmdArray[0], cmdArray.slice(1), {
821
+ stdio: stdioMapped,
822
+ cwd: opts.cwd,
823
+ env: opts.env,
824
+ detached: !!opts.detached,
825
+ argv0: opts.argv0,
826
+ });
827
+ const stdoutChunks = [];
828
+ if (child.stdout) child.stdout.on('data', d => stdoutChunks.push(d));
829
+ let resolveExited;
830
+ const exited = new Promise(resolve => { resolveExited = resolve; });
831
+ child.on('exit', (code, signal) => resolveExited(code !== null ? code : (signal ? 128 : 0)));
832
+ child.on('error', () => resolveExited(1));
833
+ return {
834
+ pid: child.pid,
835
+ exited,
836
+ stdout: { text: async () => { await exited; return Buffer.concat(stdoutChunks).toString('utf8'); } },
837
+ unref: () => { try { child.unref(); } catch {} },
838
+ kill: (signal) => { try { child.kill(signal); } catch {} },
839
+ };
840
+ },
841
+ file: (path) => {
842
+ const err = new Error(`ENOENT: Bun.file(${String(path)}) is not supported by the Termux compatibility shim`);
843
+ err.code = 'ENOENT';
844
+ err.errno = -2;
845
+ throw err;
846
+ },
801
847
  };
802
848
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
803
849
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -1419,6 +1465,7 @@ function rewriteNativeChunkSource(source) {
1419
1465
  const _bunPropertyAccessExpected = (() => {
1420
1466
  const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
1421
1467
  const _m = _ver.match(/^(\d+)\.(\d+)\.(\d+)/);
1468
+ if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 223)) return 43;
1422
1469
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
1423
1470
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 216)) return 40;
1424
1471
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 214)) return 39;
@@ -1447,6 +1494,13 @@ function rewriteNativeChunkSource(source) {
1447
1494
  'npmInstallDeprecated flag',
1448
1495
  _npmInstallDeprecatedExpected,
1449
1496
  );
1497
+ patched = replaceRequired(
1498
+ patched,
1499
+ /function ([A-Za-z_$][\w$]*)\(\)\{(return\([A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*,[A-Za-z_$][\w$]*\)=>\{let\{cmd:([A-Za-z_$][\w$]*),prefixArgs:([A-Za-z_$][\w$]*)\}=[A-Za-z_$][\w$]*\(\{pinToCurrentBinary:!0\}\),[A-Za-z_$][\w$]*=\[\3,\.\.\.\4,"--bg-pty-host")/g,
1500
+ 'function $1(){return undefined;$2',
1501
+ 'bg-pty-host factory disable',
1502
+ 1,
1503
+ );
1450
1504
  return patched;
1451
1505
  }
1452
1506
 
@@ -1619,6 +1673,44 @@ async function main() {
1619
1673
  };
1620
1674
  })(),
1621
1675
  YAML: globalThis.__claudeYaml,
1676
+ spawn: (cmd, options) => {
1677
+ const opts = options || {};
1678
+ const stdioArrayRaw = opts.stdio;
1679
+ const cmdArray = Array.isArray(cmd) ? cmd : [cmd];
1680
+ const normalizeStdio = (v) => {
1681
+ if (typeof v === 'number' && Number.isInteger(v) && v >= 0) return v;
1682
+ return (v === 'ignore' || v === 'pipe' || v === 'inherit') ? v : 'pipe';
1683
+ };
1684
+ const stdioMapped = Array.isArray(stdioArrayRaw)
1685
+ ? stdioArrayRaw.map(normalizeStdio)
1686
+ : [normalizeStdio(opts.stdin), normalizeStdio(opts.stdout), normalizeStdio(opts.stderr)];
1687
+ const child = _realChild.spawn(cmdArray[0], cmdArray.slice(1), {
1688
+ stdio: stdioMapped,
1689
+ cwd: opts.cwd,
1690
+ env: opts.env,
1691
+ detached: !!opts.detached,
1692
+ argv0: opts.argv0,
1693
+ });
1694
+ const stdoutChunks = [];
1695
+ if (child.stdout) child.stdout.on('data', d => stdoutChunks.push(d));
1696
+ let resolveExited;
1697
+ const exited = new Promise(resolve => { resolveExited = resolve; });
1698
+ child.on('exit', (code, signal) => resolveExited(code !== null ? code : (signal ? 128 : 0)));
1699
+ child.on('error', () => resolveExited(1));
1700
+ return {
1701
+ pid: child.pid,
1702
+ exited,
1703
+ stdout: { text: async () => { await exited; return Buffer.concat(stdoutChunks).toString('utf8'); } },
1704
+ unref: () => { try { child.unref(); } catch {} },
1705
+ kill: (signal) => { try { child.kill(signal); } catch {} },
1706
+ };
1707
+ },
1708
+ file: (path) => {
1709
+ const err = new Error(`ENOENT: Bun.file(${String(path)}) is not supported by the Termux compatibility shim`);
1710
+ err.code = 'ENOENT';
1711
+ err.errno = -2;
1712
+ throw err;
1713
+ },
1622
1714
  };
1623
1715
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
1624
1716
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const test = require('node:test');
4
+ const { mock } = require('node:test');
4
5
  const assert = require('node:assert/strict');
5
6
  const crypto = require('crypto');
6
7
  const child_process = require('child_process');
@@ -300,9 +301,36 @@ test('cleanupStaleEntryFiles removes only stale extracted files for the same off
300
301
  function buildSyntheticBundleSource() {
301
302
  const typeofBun = Array.from({ length: 6 }, () => 'typeof Bun').join('; ');
302
303
  const bunProps = Array.from({ length: 37 }, (_, index) => `Bun.p${index}`).join('; ');
303
- return `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0 }`;
304
+ return `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
304
305
  }
305
306
 
307
+ test('rewriteNativeChunkSource disables the bg-pty-host factory', () => {
308
+ process.env.CURRENT_CLAUDE_VERSION = '2.1.198';
309
+ try {
310
+ const { rewriteNativeChunkSource } = loadHelperApi();
311
+ const patched = rewriteNativeChunkSource(buildSyntheticBundleSource());
312
+ const start = patched.indexOf('function dYs(){');
313
+ assert.notEqual(start, -1);
314
+ let depth = 0;
315
+ let end = -1;
316
+ for (let index = start; index < patched.length; index += 1) {
317
+ if (patched[index] === '{') depth += 1;
318
+ if (patched[index] === '}') {
319
+ depth -= 1;
320
+ if (depth === 0) {
321
+ end = index + 1;
322
+ break;
323
+ }
324
+ }
325
+ }
326
+ assert.notEqual(end, -1);
327
+ const rewrittenFactory = eval('(' + patched.slice(start, end) + ')');
328
+ assert.equal(rewrittenFactory(), undefined);
329
+ } finally {
330
+ delete process.env.CURRENT_CLAUDE_VERSION;
331
+ }
332
+ });
333
+
306
334
  test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.198)', () => {
307
335
  process.env.CURRENT_CLAUDE_VERSION = '2.1.198';
308
336
  try {
@@ -328,7 +356,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
328
356
  const { rewriteNativeChunkSource } = loadHelperApi();
329
357
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
330
358
  const bunProps = Array.from({ length: 40 }, (_, index) => `Bun.p${index}`).join('; ');
331
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0 }`;
359
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
332
360
  const patched = rewriteNativeChunkSource(source);
333
361
 
334
362
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -349,7 +377,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
349
377
  const { rewriteNativeChunkSource } = loadHelperApi();
350
378
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
351
379
  const bunProps = Array.from({ length: 41 }, (_, index) => `Bun.p${index}`).join('; ');
352
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0 }`;
380
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
353
381
  const patched = rewriteNativeChunkSource(source);
354
382
 
355
383
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -370,7 +398,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
370
398
  const { rewriteNativeChunkSource } = loadHelperApi();
371
399
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
372
400
  const bunProps = Array.from({ length: 41 }, (_, index) => `Bun.p${index}`).join('; ');
373
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
401
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
374
402
  const patched = rewriteNativeChunkSource(source);
375
403
 
376
404
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -391,7 +419,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
391
419
  const { rewriteNativeChunkSource } = loadHelperApi();
392
420
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
393
421
  const bunProps = Array.from({ length: 38 }, (_, index) => `Bun.p${index}`).join('; ');
394
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
422
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
395
423
  const patched = rewriteNativeChunkSource(source);
396
424
 
397
425
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -412,7 +440,7 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
412
440
  const { rewriteNativeChunkSource } = loadHelperApi();
413
441
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
414
442
  const bunProps = Array.from({ length: 41 }, (_, index) => `Bun.p${index}`).join('; ');
415
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
443
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
416
444
 
417
445
  assert.throws(
418
446
  () => rewriteNativeChunkSource(source),
@@ -429,7 +457,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
429
457
  const { rewriteNativeChunkSource } = loadHelperApi();
430
458
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
431
459
  const bunProps = Array.from({ length: 39 }, (_, index) => `Bun.p${index}`).join('; ');
432
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
460
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
433
461
  const patched = rewriteNativeChunkSource(source);
434
462
 
435
463
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -450,7 +478,7 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
450
478
  const { rewriteNativeChunkSource } = loadHelperApi();
451
479
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
452
480
  const bunProps = Array.from({ length: 38 }, (_, index) => `Bun.p${index}`).join('; ');
453
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
481
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
454
482
 
455
483
  assert.throws(
456
484
  () => rewriteNativeChunkSource(source),
@@ -467,7 +495,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
467
495
  const { rewriteNativeChunkSource } = loadHelperApi();
468
496
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
469
497
  const bunProps = Array.from({ length: 40 }, (_, index) => `Bun.p${index}`).join('; ');
470
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
498
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
471
499
  const patched = rewriteNativeChunkSource(source);
472
500
 
473
501
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -487,7 +515,7 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
487
515
  const { rewriteNativeChunkSource } = loadHelperApi();
488
516
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
489
517
  const bunProps = Array.from({ length: 39 }, (_, index) => `Bun.p${index}`).join('; ');
490
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
518
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
491
519
 
492
520
  assert.throws(
493
521
  () => rewriteNativeChunkSource(source),
@@ -504,7 +532,7 @@ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.
504
532
  const { rewriteNativeChunkSource } = loadHelperApi();
505
533
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
506
534
  const bunProps = Array.from({ length: 42 }, (_, index) => `Bun.p${index}`).join('; ');
507
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
535
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
508
536
  const patched = rewriteNativeChunkSource(source);
509
537
 
510
538
  assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
@@ -524,7 +552,7 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
524
552
  const { rewriteNativeChunkSource } = loadHelperApi();
525
553
  const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
526
554
  const bunProps = Array.from({ length: 41 }, (_, index) => `Bun.p${index}`).join('; ');
527
- const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0 }`;
555
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
528
556
 
529
557
  assert.throws(
530
558
  () => rewriteNativeChunkSource(source),
@@ -535,6 +563,43 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
535
563
  }
536
564
  });
537
565
 
566
+ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.223)', () => {
567
+ process.env.CURRENT_CLAUDE_VERSION = '2.1.223';
568
+ try {
569
+ const { rewriteNativeChunkSource } = loadHelperApi();
570
+ const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
571
+ const bunProps = Array.from({ length: 43 }, (_, index) => `Bun.p${index}`).join('; ');
572
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
573
+ const patched = rewriteNativeChunkSource(source);
574
+
575
+ assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
576
+ assert.match(patched, /typeof __claudeBun/);
577
+ assert.match(patched, /typeof globalThis\.__claudeBun/);
578
+ assert.match(patched, /globalThis\.__claudeBun/);
579
+ assert.match(patched, /__claudeBun\./);
580
+ assert.equal((patched.match(/__claudeBun\./g) || []).length, 43);
581
+ } finally {
582
+ delete process.env.CURRENT_CLAUDE_VERSION;
583
+ }
584
+ });
585
+
586
+ test('rewriteNativeChunkSource rejects stale Bun property access count for version 2.1.223', () => {
587
+ process.env.CURRENT_CLAUDE_VERSION = '2.1.223';
588
+ try {
589
+ const { rewriteNativeChunkSource } = loadHelperApi();
590
+ const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
591
+ const bunProps = Array.from({ length: 42 }, (_, index) => `Bun.p${index}`).join('; ');
592
+ const source = `function(exports, require, module, __filename, __dirname) { ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps}; npmInstallDeprecated:!0; npmInstallDeprecated:!0; function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}} }`;
593
+
594
+ assert.throws(
595
+ () => rewriteNativeChunkSource(source),
596
+ /unexpected Bun property access count 42/,
597
+ );
598
+ } finally {
599
+ delete process.env.CURRENT_CLAUDE_VERSION;
600
+ }
601
+ });
602
+
538
603
  test('rewriteNativeChunkSource rejects unexpected replacement counts', () => {
539
604
  const { rewriteNativeChunkSource } = loadHelperApi();
540
605
  const source = buildSyntheticBundleSource().replace('Bun.p30;', '');
@@ -571,6 +636,7 @@ function buildScenarioFixtureSource() {
571
636
  return `function(exports, require, module, __filename, __dirname) {
572
637
  ${typeofBun}; typeof globalThis.Bun; globalThis.Bun; ${bunProps};
573
638
  npmInstallDeprecated:!0; npmInstallDeprecated:!0;
639
+ function dYs(){return(e,t,r)=>{let{cmd:n,prefixArgs:o}=ox({pinToCurrentBinary:!0}),i=[n,...o,"--bg-pty-host",r.ptySock];return i}}
574
640
  const scenario = process.env.TEST_SCENARIO;
575
641
  if (scenario === 'sync-exit') { process.stdout.write('ok'); process.exit(0); return; }
576
642
  if (scenario === 'async-exit') {
@@ -1338,3 +1404,145 @@ test('installStreamJsonTerminalWatcher waits for write callback before completin
1338
1404
 
1339
1405
  watcher.restore();
1340
1406
  });
1407
+
1408
+ function extractShimSource(block) {
1409
+ const startMarker = 'const _realChild = require(\'child_process\');';
1410
+ const endMarker = 'Object.assign(globalThis.__claudeBunShim, globalThis.Bun);';
1411
+ const start = block.indexOf(startMarker);
1412
+ assert.notEqual(start, -1, 'missing Bun shim start');
1413
+ const end = block.indexOf(endMarker, start);
1414
+ assert.notEqual(end, -1, 'missing Bun shim end');
1415
+ return block.slice(start, end + endMarker.length);
1416
+ }
1417
+
1418
+ function loadBunShim(source) {
1419
+ const context = vm.createContext({
1420
+ stringWidth: () => 0,
1421
+ wrapAnsi: value => value,
1422
+ stripANSI: value => value,
1423
+ stableHash: () => 0,
1424
+ __claudeYaml: {},
1425
+ Buffer,
1426
+ require,
1427
+ });
1428
+ context.__claudeBunShim = {};
1429
+ context.__claudeYaml = {};
1430
+ context.Bun = {};
1431
+ context.module = { exports: {} };
1432
+ vm.runInContext(`${source}\nmodule.exports = globalThis.__claudeBunShim;`, context);
1433
+ return context.module.exports;
1434
+ }
1435
+
1436
+ test('helper and bootstrap Bun shim source is identical', () => {
1437
+ const helperBlock = extractBlock('cat <<\'NODE\' > "$_helper"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1438
+ const bootstrapBlock = extractBlock('cat <<\'NODE\' > "$_bootstrap"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1439
+ assert.equal(extractShimSource(helperBlock), extractShimSource(bootstrapBlock));
1440
+ });
1441
+
1442
+ test('Bun.file always throws ENOENT', () => {
1443
+ for (const blockMarker of ['cat <<\'NODE\' > "$_helper"', 'cat <<\'NODE\' > "$_bootstrap"']) {
1444
+ const block = extractBlock(blockMarker, '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1445
+ const Bun = loadBunShim(extractShimSource(block));
1446
+ assert.throws(() => Bun.file('/some/path'), error =>
1447
+ error.code === 'ENOENT' && error.errno === -2);
1448
+ }
1449
+ });
1450
+
1451
+ test('Bun.spawn supports top-level and array stdio forms', async () => {
1452
+ const block = extractBlock('cat <<\'NODE\' > "$_helper"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1453
+ const Bun = loadBunShim(extractShimSource(block));
1454
+ const topLevel = Bun.spawn(['echo', 'hello'], { stdout: 'pipe', stderr: 'ignore' });
1455
+ assert.equal(await topLevel.stdout.text(), 'hello\n');
1456
+ assert.equal(await topLevel.exited, 0);
1457
+ const arrayForm = Bun.spawn(['echo', 'hello'], { stdio: ['ignore', 'pipe', 'ignore'] });
1458
+ assert.equal(await arrayForm.stdout.text(), 'hello\n');
1459
+ assert.equal(await arrayForm.exited, 0);
1460
+ });
1461
+
1462
+ test('Bun.spawn forwards options, preserves numeric fds, and delegates child controls', () => {
1463
+ const block = extractBlock('cat <<\'NODE\' > "$_helper"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1464
+ const calls = [];
1465
+ const handlers = {};
1466
+ const child = {
1467
+ pid: 123,
1468
+ stdout: null,
1469
+ on(event, handler) { handlers[event] = handler; return this; },
1470
+ unref() { calls.push(['unref']); },
1471
+ kill(signal) { calls.push(['kill', signal]); },
1472
+ };
1473
+ mock.method(child_process, 'spawn', (...args) => {
1474
+ calls.push(args);
1475
+ return child;
1476
+ });
1477
+ try {
1478
+ const Bun = loadBunShim(extractShimSource(block));
1479
+ const result = Bun.spawn(['cmd', 'arg'], {
1480
+ detached: true,
1481
+ argv0: 'argv0-value',
1482
+ cwd: '/tmp/work',
1483
+ env: { TEST: 'yes' },
1484
+ stdio: [0, 1, 2],
1485
+ });
1486
+ assert.deepEqual(JSON.parse(JSON.stringify(calls[0])), [
1487
+ 'cmd',
1488
+ ['arg'],
1489
+ {
1490
+ stdio: [0, 1, 2],
1491
+ cwd: '/tmp/work',
1492
+ env: { TEST: 'yes' },
1493
+ detached: true,
1494
+ argv0: 'argv0-value',
1495
+ },
1496
+ ]);
1497
+ result.unref();
1498
+ result.kill('SIGTERM');
1499
+ assert.deepEqual(JSON.parse(JSON.stringify(calls.slice(1))), [['unref'], ['kill', 'SIGTERM']]);
1500
+ } finally {
1501
+ mock.restoreAll();
1502
+ }
1503
+ });
1504
+
1505
+ test('Bun.spawn prefers stdio array over top-level stdio options', () => {
1506
+ for (const blockMarker of ['cat <<\'NODE\' > "$_helper"', 'cat <<\'NODE\' > "$_bootstrap"']) {
1507
+ const block = extractBlock(blockMarker, '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1508
+ const calls = [];
1509
+ mock.method(child_process, 'spawn', (...args) => {
1510
+ calls.push(args);
1511
+ return { pid: 123, stdout: null, on() { return this; } };
1512
+ });
1513
+ try {
1514
+ const Bun = loadBunShim(extractShimSource(block));
1515
+ Bun.spawn(['cmd'], {
1516
+ stdio: [0, 1, 2],
1517
+ stdin: 'pipe',
1518
+ stdout: 'pipe',
1519
+ stderr: 'pipe',
1520
+ });
1521
+ assert.deepEqual(JSON.parse(JSON.stringify(calls[0][2])), {
1522
+ stdio: [0, 1, 2],
1523
+ detached: false,
1524
+ });
1525
+ } finally {
1526
+ mock.restoreAll();
1527
+ }
1528
+ }
1529
+ });
1530
+
1531
+ test('Bun.spawn forwards top-level stdin in the first stdio position', () => {
1532
+ for (const blockMarker of ['cat <<\'NODE\' > "$_helper"', 'cat <<\'NODE\' > "$_bootstrap"']) {
1533
+ const block = extractBlock(blockMarker, '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1534
+ const calls = [];
1535
+ mock.method(child_process, 'spawn', (...args) => {
1536
+ calls.push(args);
1537
+ return { pid: 123, stdout: null, on() { return this; } };
1538
+ });
1539
+ try {
1540
+ const Bun = loadBunShim(extractShimSource(block));
1541
+ Bun.spawn(['cmd'], { stdin: 'inherit', stdout: 'pipe', stderr: 'ignore' });
1542
+ assert.equal(calls[0][2].stdio[0], 'inherit');
1543
+ assert.deepEqual(JSON.parse(JSON.stringify(calls[0][2].stdio)), ['inherit', 'pipe', 'ignore']);
1544
+ } finally {
1545
+ mock.restoreAll();
1546
+ }
1547
+ }
1548
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash0816/claude-code",
3
- "version": "2.1.222",
3
+ "version": "2.1.223",
4
4
  "description": "Unofficial Termux-native Claude Code wrapper with audited native replay",
5
5
  "license": "GPL-3.0-only",
6
6
  "bin": {