@bash0816/claude-code 2.1.228 → 2.1.232

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.227
40
+ npm install -g @bash0816/claude-code@2.1.231
41
41
  ```
42
42
 
43
43
  ## Update / 更新
@@ -679,7 +679,25 @@
679
679
  "entry_end_offset": 297826425,
680
680
  "tarball_integrity": "sha512-rWSzUqON6kyIXUVz9KDU+9R6FdO11IVCO94D7kkWWyRPzFqzaAB80RmfgP//QgTIVFApEUzEUH2tfAGsUhD6ug==",
681
681
  "tarball_sha256": "31295a318aef235b1b818a8b46982757467fb4d13030520ac66d16a58c0d7e27",
682
- "status": "offset_discovered"
682
+ "status": "termux_verified"
683
+ },
684
+ "2.1.231": {
685
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.231",
686
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.231",
687
+ "entry_js_offset": 273809585,
688
+ "entry_end_offset": 299210420,
689
+ "tarball_integrity": "sha512-a0YGXTjk6N5yRWE30dkbtS0tTZ5hOEXFCjTTX2slSa7XULMlJJLQ1X8oFJwpXmlvZu9FHx1YRLKJnni05uNIQQ==",
690
+ "tarball_sha256": "f50fa4b2270707208a3ae870deae8c562ec6b2f4d7bf778fca6275d13908b714",
691
+ "status": "termux_verified"
692
+ },
693
+ "2.1.232": {
694
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.232",
695
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.232",
696
+ "entry_js_offset": 284086193,
697
+ "entry_end_offset": 310581163,
698
+ "tarball_integrity": "sha512-5Aub8i5pjCVlDBP/tIpHwO/8owfNBu2+FP+w0U8Jmy9s6cEhg/HB7Nyp9KyADhN74w6t0TVGvzUdnFXVMANI4Q==",
699
+ "tarball_sha256": "97322189ff3c884e86d2ba2981d21c9874ca78261a8bff65a4ef6f673ef98fa6",
700
+ "status": "termux_verified"
683
701
  }
684
702
  }
685
703
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "manifest_version": 1,
3
3
  "package_name": "@bash0816/claude-code",
4
- "latest_audited_version": "2.1.227",
5
- "latest_candidate_version": "2.1.228",
6
- "previous_stable_version": "2.1.226",
4
+ "latest_audited_version": "2.1.232",
5
+ "latest_candidate_version": "2.1.232",
6
+ "previous_stable_version": "2.1.231",
7
7
  "stable_pinned_version": "2.1.220-2",
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]) >= 232)) return 45;
602
603
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 224)) return 44;
603
604
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 223)) return 43;
604
605
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
@@ -680,6 +681,58 @@ async function main() {
680
681
  }
681
682
  const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
682
683
 
684
+ function installPlainTextWriteWatcher() {
685
+ const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
686
+ const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
687
+ const originalWrite = process.stdout.write.bind(process.stdout);
688
+ let foundOutput = false;
689
+ let resultPromiseResolve = null;
690
+ let restored = false;
691
+
692
+ process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
693
+ let cb = callback;
694
+ let enc = encoding;
695
+ if (typeof encoding === 'function') {
696
+ cb = encoding;
697
+ enc = undefined;
698
+ }
699
+ const combinedCallback = (err) => {
700
+ if (!err && !foundOutput) {
701
+ const len = typeof chunk === 'string'
702
+ ? Buffer.byteLength(chunk, typeof enc === 'string' ? enc : 'utf8')
703
+ : (Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(String(chunk ?? ''), 'utf8'));
704
+ if (len > 0) {
705
+ foundOutput = true;
706
+ if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
707
+ }
708
+ }
709
+ if (typeof cb === 'function') cb(err);
710
+ };
711
+ return originalWrite(chunk, enc, combinedCallback);
712
+ };
713
+
714
+ return {
715
+ waitForResult() {
716
+ if (foundOutput) return Promise.resolve();
717
+ return new Promise((resolve) => {
718
+ resultPromiseResolve = resolve;
719
+ });
720
+ },
721
+ hasOutput() {
722
+ return foundOutput;
723
+ },
724
+ restore() {
725
+ if (restored) return;
726
+ restored = true;
727
+ if (hadOwnWrite) {
728
+ Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
729
+ } else {
730
+ delete process.stdout.write;
731
+ }
732
+ },
733
+ };
734
+ }
735
+
683
736
  function installStreamJsonTerminalWatcher() {
684
737
  const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
685
738
  const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
@@ -768,6 +821,25 @@ async function main() {
768
821
  }
769
822
  return;
770
823
  }
824
+ if (streamJsonWatcher && typeof streamJsonWatcher.hasOutput === 'function') {
825
+ if (streamJsonWatcher.hasOutput()) {
826
+ return;
827
+ }
828
+ const gatingExitCode = process.exitCode;
829
+ const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
830
+ const extendedTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
831
+ const noOutputTimeoutMs = (gatingExitCode !== undefined && gatingExitCode !== 0) ? printWaitMs : extendedTimeoutMs;
832
+ let timeoutHandle;
833
+ const timeoutPromise = new Promise(resolve => {
834
+ timeoutHandle = setTimeout(resolve, noOutputTimeoutMs);
835
+ });
836
+ try {
837
+ await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
838
+ } finally {
839
+ clearTimeout(timeoutHandle);
840
+ }
841
+ return;
842
+ }
771
843
  if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
772
844
  await new Promise(resolve => setTimeout(resolve, printWaitMs));
773
845
  }
@@ -882,6 +954,8 @@ async function main() {
882
954
 
883
955
  if (isStreamJsonPrintMode(argv)) {
884
956
  streamJsonWatcher = installStreamJsonTerminalWatcher();
957
+ } else {
958
+ streamJsonWatcher = installPlainTextWriteWatcher();
885
959
  }
886
960
 
887
961
  const moduleLike = { exports: {} };
@@ -1481,6 +1555,7 @@ function rewriteNativeChunkSource(source) {
1481
1555
  const _bunPropertyAccessExpected = (() => {
1482
1556
  const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
1483
1557
  const _m = _ver.match(/^(\d+)\.(\d+)\.(\d+)/);
1558
+ if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 232)) return 45;
1484
1559
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 224)) return 44;
1485
1560
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 223)) return 43;
1486
1561
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
@@ -1561,6 +1636,58 @@ async function main() {
1561
1636
  asyncErrors.push(error);
1562
1637
  }
1563
1638
 
1639
+ function installPlainTextWriteWatcher() {
1640
+ const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
1641
+ const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
1642
+ const originalWrite = process.stdout.write.bind(process.stdout);
1643
+ let foundOutput = false;
1644
+ let resultPromiseResolve = null;
1645
+ let restored = false;
1646
+
1647
+ process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
1648
+ let cb = callback;
1649
+ let enc = encoding;
1650
+ if (typeof encoding === 'function') {
1651
+ cb = encoding;
1652
+ enc = undefined;
1653
+ }
1654
+ const combinedCallback = (err) => {
1655
+ if (!err && !foundOutput) {
1656
+ const len = typeof chunk === 'string'
1657
+ ? Buffer.byteLength(chunk, typeof enc === 'string' ? enc : 'utf8')
1658
+ : (Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(String(chunk ?? ''), 'utf8'));
1659
+ if (len > 0) {
1660
+ foundOutput = true;
1661
+ if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
1662
+ }
1663
+ }
1664
+ if (typeof cb === 'function') cb(err);
1665
+ };
1666
+ return originalWrite(chunk, enc, combinedCallback);
1667
+ };
1668
+
1669
+ return {
1670
+ waitForResult() {
1671
+ if (foundOutput) return Promise.resolve();
1672
+ return new Promise((resolve) => {
1673
+ resultPromiseResolve = resolve;
1674
+ });
1675
+ },
1676
+ hasOutput() {
1677
+ return foundOutput;
1678
+ },
1679
+ restore() {
1680
+ if (restored) return;
1681
+ restored = true;
1682
+ if (hadOwnWrite) {
1683
+ Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
1684
+ } else {
1685
+ delete process.stdout.write;
1686
+ }
1687
+ },
1688
+ };
1689
+ }
1690
+
1564
1691
  function installStreamJsonTerminalWatcher() {
1565
1692
  const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
1566
1693
  const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
@@ -1650,6 +1777,26 @@ async function main() {
1650
1777
  }
1651
1778
  return;
1652
1779
  }
1780
+ if (streamJsonWatcher && typeof streamJsonWatcher.hasOutput === 'function') {
1781
+ if (streamJsonWatcher.hasOutput()) {
1782
+ return;
1783
+ }
1784
+ const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
1785
+ const gatingExitCode = process.exitCode;
1786
+ const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
1787
+ const extendedTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
1788
+ const noOutputTimeoutMs = (gatingExitCode !== undefined && gatingExitCode !== 0) ? printWaitMs : extendedTimeoutMs;
1789
+ let timeoutHandle;
1790
+ const timeoutPromise = new Promise(resolve => {
1791
+ timeoutHandle = setTimeout(resolve, noOutputTimeoutMs);
1792
+ });
1793
+ try {
1794
+ await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
1795
+ } finally {
1796
+ clearTimeout(timeoutHandle);
1797
+ }
1798
+ return;
1799
+ }
1653
1800
  const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
1654
1801
  if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
1655
1802
  await new Promise(resolve => setTimeout(resolve, printWaitMs));
@@ -1765,6 +1912,8 @@ async function main() {
1765
1912
 
1766
1913
  if (isStreamJsonPrintMode(argv)) {
1767
1914
  streamJsonWatcher = installStreamJsonTerminalWatcher();
1915
+ } else if (process.env.CLAUDE_TERMUX_PRINT_MODE === '1') {
1916
+ streamJsonWatcher = installPlainTextWriteWatcher();
1768
1917
  }
1769
1918
 
1770
1919
  const moduleLike = { exports: {} };
@@ -605,6 +605,43 @@ test('rewriteNativeChunkSource rejects stale Bun property access count for versi
605
605
  }
606
606
  });
607
607
 
608
+ test('rewriteNativeChunkSource rewrites the synthetic bundle slice (version 2.1.232)', () => {
609
+ process.env.CURRENT_CLAUDE_VERSION = '2.1.232';
610
+ try {
611
+ const { rewriteNativeChunkSource } = loadHelperApi();
612
+ const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
613
+ const bunProps = Array.from({ length: 45 }, (_, index) => `Bun.p${index}`).join('; ');
614
+ 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}} }`;
615
+ const patched = rewriteNativeChunkSource(source);
616
+
617
+ assert.match(patched, /var __claudeBun = globalThis\.__claudeBunShim;/);
618
+ assert.match(patched, /typeof __claudeBun/);
619
+ assert.match(patched, /typeof globalThis\.__claudeBun/);
620
+ assert.match(patched, /globalThis\.__claudeBun/);
621
+ assert.match(patched, /__claudeBun\./);
622
+ assert.equal((patched.match(/__claudeBun\./g) || []).length, 45);
623
+ } finally {
624
+ delete process.env.CURRENT_CLAUDE_VERSION;
625
+ }
626
+ });
627
+
628
+ test('rewriteNativeChunkSource rejects stale Bun property access count for version 2.1.232', () => {
629
+ process.env.CURRENT_CLAUDE_VERSION = '2.1.232';
630
+ try {
631
+ const { rewriteNativeChunkSource } = loadHelperApi();
632
+ const typeofBun = Array.from({ length: 7 }, () => 'typeof Bun').join('; ');
633
+ const bunProps = Array.from({ length: 44 }, (_, index) => `Bun.p${index}`).join('; ');
634
+ 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}} }`;
635
+
636
+ assert.throws(
637
+ () => rewriteNativeChunkSource(source),
638
+ /unexpected Bun property access count 44/,
639
+ );
640
+ } finally {
641
+ delete process.env.CURRENT_CLAUDE_VERSION;
642
+ }
643
+ });
644
+
608
645
  test('rewriteNativeChunkSource rejects unexpected replacement counts', () => {
609
646
  const { rewriteNativeChunkSource } = loadHelperApi();
610
647
  const source = buildSyntheticBundleSource().replace('Bun.p30;', '');
@@ -709,11 +746,22 @@ function buildScenarioFixtureSource() {
709
746
  process.exit(0);
710
747
  return;
711
748
  }
749
+ if (scenario === 'plain-late-write') {
750
+ setTimeout(() => { process.stdout.write('late-output'); }, 800);
751
+ return;
752
+ }
753
+ if (scenario === 'plain-no-output-error') {
754
+ process.exitCode = 1;
755
+ return;
756
+ }
757
+ if (scenario === 'plain-no-output-success') {
758
+ return;
759
+ }
712
760
  process.stdout.write('ok');
713
761
  }`;
714
762
  }
715
763
 
716
- function runScenario({ printMode, stdinInherit, scenario, extraArgs }) {
764
+ function runScenario({ printMode, stdinInherit, scenario, extraArgs, extraEnv }) {
717
765
  const tmpBase = fs.mkdtempSync(path.join(os.tmpdir(), 'claude-stdin-test-'));
718
766
  const sourceBin = path.join(tmpBase, 'fake-source.js');
719
767
  const fixtureSource = buildScenarioFixtureSource();
@@ -735,6 +783,7 @@ function runScenario({ printMode, stdinInherit, scenario, extraArgs }) {
735
783
  CLAUDE_TERMUX_PRINT_WAIT_MS: '300',
736
784
  TMPDIR: tmpBase,
737
785
  TEST_SCENARIO: scenario,
786
+ ...(extraEnv || {}),
738
787
  };
739
788
  if (stdinInherit) env.CLAUDE_TERMUX_STDIN = 'inherit';
740
789
  else delete env.CLAUDE_TERMUX_STDIN;
@@ -808,15 +857,82 @@ test('bootstrap branch (-p + CLAUDE_TERMUX_STDIN=inherit): normal/sync-exit/asyn
808
857
  try {
809
858
  assert.ok((r.stdout || '').includes('ok'), `scenario=${scenario} stdout=${r.stdout} stderr=${r.stderr}`);
810
859
  assert.equal(r.status, 0, `scenario=${scenario} status=${r.status} stderr=${r.stderr}`);
811
- if (scenario === 'async-exit') {
812
- assert.ok(r.elapsedMs >= 250, `expected wait >= 250ms, got ${r.elapsedMs}ms`);
813
- }
814
860
  } finally {
815
861
  fs.rmSync(r.tmpBase, { recursive: true, force: true });
816
862
  }
817
863
  }
818
864
  });
819
865
 
866
+ test('helper branch plain mode waits for late write beyond default printWaitMs', () => {
867
+ const r = runScenario({ printMode: true, stdinInherit: false, scenario: 'plain-late-write' });
868
+ try {
869
+ assert.ok((r.stdout || '').includes('late-output'), `stdout=${r.stdout} stderr=${r.stderr}`);
870
+ assert.equal(r.status, 0, `status=${r.status} stderr=${r.stderr}`);
871
+ } finally {
872
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
873
+ }
874
+ });
875
+
876
+ test('bootstrap branch plain mode waits for late write beyond default printWaitMs', () => {
877
+ const r = runScenario({ printMode: true, stdinInherit: true, scenario: 'plain-late-write' });
878
+ try {
879
+ assert.ok((r.stdout || '').includes('late-output'), `stdout=${r.stdout} stderr=${r.stderr}`);
880
+ assert.equal(r.status, 0, `status=${r.status} stderr=${r.stderr}`);
881
+ } finally {
882
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
883
+ }
884
+ });
885
+
886
+ test('helper branch plain mode with no output and non-zero exitCode exits promptly (no extended wait)', () => {
887
+ const r = runScenario({ printMode: true, stdinInherit: false, scenario: 'plain-no-output-error' });
888
+ try {
889
+ assert.equal(r.status, 1, `status=${r.status} stderr=${r.stderr}`);
890
+ assert.ok(r.elapsedMs < 5000, `expected prompt exit, got elapsedMs=${r.elapsedMs}`);
891
+ } finally {
892
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
893
+ }
894
+ });
895
+
896
+ test('bootstrap branch plain mode with no output and non-zero exitCode exits promptly (no extended wait)', () => {
897
+ const r = runScenario({ printMode: true, stdinInherit: true, scenario: 'plain-no-output-error' });
898
+ try {
899
+ assert.equal(r.status, 1, `status=${r.status} stderr=${r.stderr}`);
900
+ assert.ok(r.elapsedMs < 5000, `expected prompt exit, got elapsedMs=${r.elapsedMs}`);
901
+ } finally {
902
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
903
+ }
904
+ });
905
+
906
+ test('helper branch plain mode with no output and successful exit waits up to configured ceiling', () => {
907
+ const r = runScenario({
908
+ printMode: true,
909
+ stdinInherit: false,
910
+ scenario: 'plain-no-output-success',
911
+ extraEnv: { CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS: '400' },
912
+ });
913
+ try {
914
+ assert.equal(r.status, 0, `status=${r.status} stderr=${r.stderr}`);
915
+ assert.ok(r.elapsedMs >= 350, `expected extended wait close to 400ms ceiling, got elapsedMs=${r.elapsedMs}`);
916
+ } finally {
917
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
918
+ }
919
+ });
920
+
921
+ test('bootstrap branch plain mode with no output and successful exit waits up to configured ceiling', () => {
922
+ const r = runScenario({
923
+ printMode: true,
924
+ stdinInherit: true,
925
+ scenario: 'plain-no-output-success',
926
+ extraEnv: { CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS: '400' },
927
+ });
928
+ try {
929
+ assert.equal(r.status, 0, `status=${r.status} stderr=${r.stderr}`);
930
+ assert.ok(r.elapsedMs >= 350, `expected extended wait close to 400ms ceiling, got elapsedMs=${r.elapsedMs}`);
931
+ } finally {
932
+ fs.rmSync(r.tmpBase, { recursive: true, force: true });
933
+ }
934
+ });
935
+
820
936
  test('helper branch intercepts self-directed SIGKILL (string signal) and exits with proper code', () => {
821
937
  const r = runScenario({ printMode: true, stdinInherit: false, scenario: 'self-sigkill-fallback-string' });
822
938
  try {
@@ -1075,6 +1191,31 @@ test('helper and bootstrap installStreamJsonTerminalWatcher helpers stay identic
1075
1191
  assert.equal(helperWatcher, bootstrapWatcher, 'installStreamJsonTerminalWatcher must be identical in both heredocs');
1076
1192
  });
1077
1193
 
1194
+ test('helper and bootstrap installPlainTextWriteWatcher helpers stay identical', () => {
1195
+ const helperBlock = extractBlock('cat <<\'NODE\' > "$_helper"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1196
+ const bootstrapBlock = extractBlock('cat <<\'NODE\' > "$_bootstrap"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1197
+
1198
+ const extractFn = (block) => {
1199
+ const startMarker = 'function installPlainTextWriteWatcher() {';
1200
+ const start = block.indexOf(startMarker);
1201
+ assert.ok(start > -1, 'installPlainTextWriteWatcher function not found');
1202
+ let depth = 0;
1203
+ let i = start + startMarker.length - 1;
1204
+ for (; i < block.length; i++) {
1205
+ if (block[i] === '{') depth++;
1206
+ if (block[i] === '}') {
1207
+ depth--;
1208
+ if (depth === 0) break;
1209
+ }
1210
+ }
1211
+ return block.slice(start, i + 1);
1212
+ };
1213
+
1214
+ const helperFn = extractFn(helperBlock);
1215
+ const bootstrapFn = extractFn(bootstrapBlock);
1216
+ assert.equal(helperFn, bootstrapFn, 'installPlainTextWriteWatcher must be identical in helper and bootstrap');
1217
+ });
1218
+
1078
1219
  test('helper and bootstrap forceTimeoutExit helpers stay identical', () => {
1079
1220
  const helperBlock = extractBlock('cat <<\'NODE\' > "$_helper"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
1080
1221
  const bootstrapBlock = extractBlock('cat <<\'NODE\' > "$_bootstrap"', '\n export ENABLE_CLAUDEAI_MCP_SERVERS=');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash0816/claude-code",
3
- "version": "2.1.228",
3
+ "version": "2.1.232",
4
4
  "description": "Unofficial Termux-native Claude Code wrapper with audited native replay",
5
5
  "license": "GPL-3.0-only",
6
6
  "bin": {