@bash0816/claude-code 2.1.220 → 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.219
40
+ npm install -g @bash0816/claude-code@2.1.222
41
41
  ```
42
42
 
43
43
  ## Update / 更新
@@ -580,6 +580,60 @@
580
580
  "entry_end_offset": 265457701,
581
581
  "tarball_integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
582
582
  "tarball_sha256": "e38454d73576a08a2e707f26539d73fc9ef33e890228ca5c58a2bbe810ac884d",
583
+ "status": "termux_verified"
584
+ },
585
+ "2.1.220-1": {
586
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.220",
587
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.220",
588
+ "entry_js_offset": 243831156,
589
+ "entry_end_offset": 265457701,
590
+ "tarball_integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
591
+ "tarball_sha256": "e38454d73576a08a2e707f26539d73fc9ef33e890228ca5c58a2bbe810ac884d",
592
+ "status": "offset_discovered"
593
+ },
594
+ "2.1.220-2": {
595
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.220",
596
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.220",
597
+ "entry_js_offset": 243831156,
598
+ "entry_end_offset": 265457701,
599
+ "tarball_integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
600
+ "tarball_sha256": "e38454d73576a08a2e707f26539d73fc9ef33e890228ca5c58a2bbe810ac884d",
601
+ "status": "termux_verified"
602
+ },
603
+ "2.1.220-3": {
604
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.220",
605
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.220",
606
+ "entry_js_offset": 243831156,
607
+ "entry_end_offset": 265457701,
608
+ "tarball_integrity": "sha512-VHFI8mKruIntKn7eq81sbyS19/KWmQcmJQsS/C+j9M/E+w0s4UytgsL7DADPjBE/GByNiKoRtLYDMntCjRlOdA==",
609
+ "tarball_sha256": "e38454d73576a08a2e707f26539d73fc9ef33e890228ca5c58a2bbe810ac884d",
610
+ "status": "offset_discovered"
611
+ },
612
+ "2.1.222": {
613
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.222",
614
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.222",
615
+ "entry_js_offset": 256895476,
616
+ "entry_end_offset": 279849039,
617
+ "tarball_integrity": "sha512-EXSediF1ujcqQeElbXdCEe+uW3NUQAOjn1xHHAgvwzY08nzJeePjagn9+YS6bmhHxBgDKwlGu7pL8Kv7EpiFtg==",
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",
583
637
  "status": "offset_discovered"
584
638
  }
585
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.219",
5
- "latest_candidate_version": "2.1.220",
6
- "previous_stable_version": "2.1.218",
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
  }
@@ -79,6 +79,22 @@ const entryJsOffset = Number(process.env.ENTRY_JS_OFFSET);
79
79
  const entryEndOffset = Number(process.env.ENTRY_END_OFFSET);
80
80
  const argv = process.argv.slice(2);
81
81
 
82
+ function isStreamJsonPrintMode(argv) {
83
+ const dashDashIndex = argv.indexOf('--');
84
+ const ownArgs = dashDashIndex === -1 ? argv : argv.slice(0, dashDashIndex);
85
+ const hasPrintFlag = ownArgs.includes('-p') || ownArgs.includes('--print');
86
+ let hasStreamJsonFormat = false;
87
+ for (let i = 0; i < ownArgs.length; i++) {
88
+ const tok = ownArgs[i];
89
+ if (tok === '--output-format=stream-json') { hasStreamJsonFormat = true; break; }
90
+ if (tok === '--output-format' && ownArgs[i + 1] === 'stream-json') {
91
+ hasStreamJsonFormat = true;
92
+ break;
93
+ }
94
+ }
95
+ return hasPrintFlag && hasStreamJsonFormat;
96
+ }
97
+
82
98
  class RequestedExit extends Error {
83
99
  constructor(code) {
84
100
  super(`process.exit ${code}`);
@@ -583,6 +599,7 @@ function rewriteNativeChunkSource(source) {
583
599
  const _bunPropertyAccessExpected = (() => {
584
600
  const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
585
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;
586
603
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
587
604
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 216)) return 40;
588
605
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 214)) return 39;
@@ -611,6 +628,13 @@ function rewriteNativeChunkSource(source) {
611
628
  'npmInstallDeprecated flag',
612
629
  _npmInstallDeprecatedExpected,
613
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
+ );
614
638
  return patched;
615
639
  }
616
640
 
@@ -623,10 +647,12 @@ async function main() {
623
647
 
624
648
  const originalArgv = process.argv.slice();
625
649
  const originalExit = process.exit;
650
+ const originalKill = process.kill;
626
651
  const originalBun = process.versions.bun;
627
652
  const hadGlobalBun = Object.prototype.hasOwnProperty.call(globalThis, 'Bun');
628
653
  const originalGlobalBun = globalThis.Bun;
629
654
  const asyncErrors = [];
655
+ let streamJsonWatcher = null;
630
656
 
631
657
  globalThis.__claudeYaml = createYamlShim();
632
658
  if (!globalThis.__claudeBunShim || typeof globalThis.__claudeBunShim !== 'object') {
@@ -636,6 +662,100 @@ async function main() {
636
662
  function onAsyncError(error) {
637
663
  asyncErrors.push(error);
638
664
  }
665
+ const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
666
+
667
+ function installStreamJsonTerminalWatcher() {
668
+ const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
669
+ const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
670
+ const originalWrite = process.stdout.write.bind(process.stdout);
671
+ const { StringDecoder } = require('string_decoder');
672
+ const decoder = new StringDecoder('utf8');
673
+ let lineBuffer = '';
674
+ let resultPromiseResolve = null;
675
+ let foundResult = false;
676
+ let restored = false;
677
+
678
+ process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
679
+ let cb = callback;
680
+ let enc = encoding;
681
+ if (typeof encoding === 'function') {
682
+ cb = encoding;
683
+ enc = undefined;
684
+ }
685
+ const combinedCallback = (err) => {
686
+ if (!err && !foundResult) {
687
+ const chunkStr = typeof chunk === 'string'
688
+ ? decoder.write(Buffer.from(chunk, typeof enc === 'string' ? enc : 'utf8'))
689
+ : decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
690
+ lineBuffer += chunkStr;
691
+ const lines = lineBuffer.split('\n');
692
+ lineBuffer = lines[lines.length - 1];
693
+ for (let i = 0; i < lines.length - 1; i++) {
694
+ try {
695
+ const parsed = JSON.parse(lines[i]);
696
+ if (parsed && parsed.type === 'result') {
697
+ foundResult = true;
698
+ if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
699
+ }
700
+ } catch {}
701
+ }
702
+ }
703
+ if (typeof cb === 'function') cb(err);
704
+ };
705
+ return originalWrite(chunk, enc, combinedCallback);
706
+ };
707
+
708
+ return {
709
+ waitForResult() {
710
+ if (foundResult) return Promise.resolve();
711
+ return new Promise((resolve, reject) => {
712
+ resultPromiseResolve = resolve;
713
+ });
714
+ },
715
+ restore() {
716
+ if (restored) return;
717
+ restored = true;
718
+ if (hadOwnWrite) {
719
+ Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
720
+ } else {
721
+ delete process.stdout.write;
722
+ }
723
+ },
724
+ };
725
+ }
726
+
727
+ function forceTimeoutExit(exitCode) {
728
+ try { if (streamJsonWatcher) streamJsonWatcher.restore(); } catch {}
729
+ if (extractedFile) {
730
+ try { fs.rmSync(extractedFile, { force: true }); } catch {}
731
+ }
732
+ originalExit(exitCode);
733
+ }
734
+
735
+ async function waitForPrintFlush() {
736
+ if (isStreamJsonPrintMode(argv) && streamJsonWatcher) {
737
+ let timedOut = false;
738
+ const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
739
+ const resultTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
740
+ let timeoutHandle;
741
+ const timeoutPromise = new Promise(resolve => {
742
+ timeoutHandle = setTimeout(() => { timedOut = true; resolve(); }, resultTimeoutMs);
743
+ });
744
+ try {
745
+ await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
746
+ } finally {
747
+ clearTimeout(timeoutHandle);
748
+ }
749
+ if (timedOut) {
750
+ forceTimeoutExit(1);
751
+ return;
752
+ }
753
+ return;
754
+ }
755
+ if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
756
+ await new Promise(resolve => setTimeout(resolve, printWaitMs));
757
+ }
758
+ }
639
759
 
640
760
  try {
641
761
  process.once('uncaughtException', onAsyncError);
@@ -683,9 +803,47 @@ async function main() {
683
803
  gte: (a, b) => _cmp(a, b) >= 0,
684
804
  lt: (a, b) => _cmp(a, b) < 0,
685
805
  lte: (a, b) => _cmp(a, b) <= 0,
686
- };
806
+ };
687
807
  })(),
688
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
+ },
689
847
  };
690
848
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
691
849
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -694,21 +852,31 @@ async function main() {
694
852
  globalThis.__claudeBun = globalThis.__claudeBunShim;
695
853
  globalThis.Bun = globalThis.__claudeBunShim;
696
854
  process.argv = ['node', extractedFile, ...argv];
855
+ let lastExitAttemptCode = 0;
697
856
  process.exit = code => {
698
- throw new RequestedExit(code);
857
+ lastExitAttemptCode = code ?? 0;
858
+ throw new RequestedExit(lastExitAttemptCode);
859
+ };
860
+ process.kill = (pid, signal) => {
861
+ if (pid === process.pid && (signal === 'SIGKILL' || signal === 9)) {
862
+ throw new RequestedExit(lastExitAttemptCode);
863
+ }
864
+ return originalKill.call(process, pid, signal);
699
865
  };
700
866
 
701
- const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
867
+ if (isStreamJsonPrintMode(argv)) {
868
+ streamJsonWatcher = installStreamJsonTerminalWatcher();
869
+ }
870
+
702
871
  const moduleLike = { exports: {} };
703
872
  const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
704
873
  if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
705
- if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
706
- await new Promise(resolve => setTimeout(resolve, printWaitMs));
707
- }
874
+ await waitForPrintFlush();
708
875
  if (asyncErrors.length > 0) throw asyncErrors[0];
709
876
  } catch (error) {
710
877
  if (error instanceof RequestedExit) {
711
878
  process.exitCode = error.code;
879
+ await waitForPrintFlush();
712
880
  return;
713
881
  }
714
882
  throw error;
@@ -722,6 +890,10 @@ async function main() {
722
890
  }
723
891
  process.argv = originalArgv;
724
892
  process.exit = originalExit;
893
+ process.kill = originalKill;
894
+ if (streamJsonWatcher) {
895
+ try { streamJsonWatcher.restore(); } catch {}
896
+ }
725
897
  try {
726
898
  if (originalBun === undefined) {
727
899
  delete process.versions.bun;
@@ -758,6 +930,7 @@ else
758
930
  _bootstrap=$(mktemp "${TERMUX_TMPDIR}/claude-bootstrap.XXXXXX.js")
759
931
  trap 'rm -f "$_bootstrap"' EXIT HUP INT TERM
760
932
  export CLAUDE_TERMUX_TUI="${_tui}"
933
+ export CLAUDE_TERMUX_PRINT_MODE="${_pf}"
761
934
  cat <<'NODE' > "$_bootstrap"
762
935
  const fs = require('fs');
763
936
  const path = require('path');
@@ -772,6 +945,22 @@ const entryJsOffset = Number(process.env.ENTRY_JS_OFFSET);
772
945
  const entryEndOffset = Number(process.env.ENTRY_END_OFFSET);
773
946
  const argv = process.argv.slice(2);
774
947
 
948
+ function isStreamJsonPrintMode(argv) {
949
+ const dashDashIndex = argv.indexOf('--');
950
+ const ownArgs = dashDashIndex === -1 ? argv : argv.slice(0, dashDashIndex);
951
+ const hasPrintFlag = ownArgs.includes('-p') || ownArgs.includes('--print');
952
+ let hasStreamJsonFormat = false;
953
+ for (let i = 0; i < ownArgs.length; i++) {
954
+ const tok = ownArgs[i];
955
+ if (tok === '--output-format=stream-json') { hasStreamJsonFormat = true; break; }
956
+ if (tok === '--output-format' && ownArgs[i + 1] === 'stream-json') {
957
+ hasStreamJsonFormat = true;
958
+ break;
959
+ }
960
+ }
961
+ return hasPrintFlag && hasStreamJsonFormat;
962
+ }
963
+
775
964
  class RequestedExit extends Error {
776
965
  constructor(code) {
777
966
  super(`process.exit ${code}`);
@@ -1276,6 +1465,7 @@ function rewriteNativeChunkSource(source) {
1276
1465
  const _bunPropertyAccessExpected = (() => {
1277
1466
  const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
1278
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;
1279
1469
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
1280
1470
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 216)) return 40;
1281
1471
  if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 214)) return 39;
@@ -1304,6 +1494,13 @@ function rewriteNativeChunkSource(source) {
1304
1494
  'npmInstallDeprecated flag',
1305
1495
  _npmInstallDeprecatedExpected,
1306
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
+ );
1307
1504
  return patched;
1308
1505
  }
1309
1506
 
@@ -1316,10 +1513,12 @@ async function main() {
1316
1513
 
1317
1514
  const originalArgv = process.argv.slice();
1318
1515
  const originalExit = process.exit;
1516
+ const originalKill = process.kill;
1319
1517
  const originalBun = process.versions.bun;
1320
1518
  const hadGlobalBun = Object.prototype.hasOwnProperty.call(globalThis, 'Bun');
1321
1519
  const originalGlobalBun = globalThis.Bun;
1322
1520
  const asyncErrors = [];
1521
+ let streamJsonWatcher = null;
1323
1522
 
1324
1523
  globalThis.__claudeYaml = createYamlShim();
1325
1524
  if (!globalThis.__claudeBunShim || typeof globalThis.__claudeBunShim !== 'object') {
@@ -1330,6 +1529,101 @@ async function main() {
1330
1529
  asyncErrors.push(error);
1331
1530
  }
1332
1531
 
1532
+ function installStreamJsonTerminalWatcher() {
1533
+ const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
1534
+ const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
1535
+ const originalWrite = process.stdout.write.bind(process.stdout);
1536
+ const { StringDecoder } = require('string_decoder');
1537
+ const decoder = new StringDecoder('utf8');
1538
+ let lineBuffer = '';
1539
+ let resultPromiseResolve = null;
1540
+ let foundResult = false;
1541
+ let restored = false;
1542
+
1543
+ process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
1544
+ let cb = callback;
1545
+ let enc = encoding;
1546
+ if (typeof encoding === 'function') {
1547
+ cb = encoding;
1548
+ enc = undefined;
1549
+ }
1550
+ const combinedCallback = (err) => {
1551
+ if (!err && !foundResult) {
1552
+ const chunkStr = typeof chunk === 'string'
1553
+ ? decoder.write(Buffer.from(chunk, typeof enc === 'string' ? enc : 'utf8'))
1554
+ : decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1555
+ lineBuffer += chunkStr;
1556
+ const lines = lineBuffer.split('\n');
1557
+ lineBuffer = lines[lines.length - 1];
1558
+ for (let i = 0; i < lines.length - 1; i++) {
1559
+ try {
1560
+ const parsed = JSON.parse(lines[i]);
1561
+ if (parsed && parsed.type === 'result') {
1562
+ foundResult = true;
1563
+ if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
1564
+ }
1565
+ } catch {}
1566
+ }
1567
+ }
1568
+ if (typeof cb === 'function') cb(err);
1569
+ };
1570
+ return originalWrite(chunk, enc, combinedCallback);
1571
+ };
1572
+
1573
+ return {
1574
+ waitForResult() {
1575
+ if (foundResult) return Promise.resolve();
1576
+ return new Promise((resolve, reject) => {
1577
+ resultPromiseResolve = resolve;
1578
+ });
1579
+ },
1580
+ restore() {
1581
+ if (restored) return;
1582
+ restored = true;
1583
+ if (hadOwnWrite) {
1584
+ Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
1585
+ } else {
1586
+ delete process.stdout.write;
1587
+ }
1588
+ },
1589
+ };
1590
+ }
1591
+
1592
+ function forceTimeoutExit(exitCode) {
1593
+ try { if (streamJsonWatcher) streamJsonWatcher.restore(); } catch {}
1594
+ if (extractedFile) {
1595
+ try { fs.rmSync(extractedFile, { force: true }); } catch {}
1596
+ }
1597
+ originalExit(exitCode);
1598
+ }
1599
+
1600
+ async function waitForPrintFlushIfNeeded() {
1601
+ if (process.env.CLAUDE_TERMUX_PRINT_MODE !== '1') return;
1602
+ if (isStreamJsonPrintMode(argv) && streamJsonWatcher) {
1603
+ let timedOut = false;
1604
+ const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
1605
+ const resultTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
1606
+ let timeoutHandle;
1607
+ const timeoutPromise = new Promise(resolve => {
1608
+ timeoutHandle = setTimeout(() => { timedOut = true; resolve(); }, resultTimeoutMs);
1609
+ });
1610
+ try {
1611
+ await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
1612
+ } finally {
1613
+ clearTimeout(timeoutHandle);
1614
+ }
1615
+ if (timedOut) {
1616
+ forceTimeoutExit(1);
1617
+ return;
1618
+ }
1619
+ return;
1620
+ }
1621
+ const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
1622
+ if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
1623
+ await new Promise(resolve => setTimeout(resolve, printWaitMs));
1624
+ }
1625
+ }
1626
+
1333
1627
  try {
1334
1628
  process.once('uncaughtException', onAsyncError);
1335
1629
  process.once('unhandledRejection', onAsyncError);
@@ -1379,6 +1673,44 @@ async function main() {
1379
1673
  };
1380
1674
  })(),
1381
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
+ },
1382
1714
  };
1383
1715
  Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
1384
1716
  if (typeof globalThis.__claudeBunShim.gc !== 'function') {
@@ -1387,17 +1719,31 @@ async function main() {
1387
1719
  globalThis.__claudeBun = globalThis.__claudeBunShim;
1388
1720
  globalThis.Bun = globalThis.__claudeBunShim;
1389
1721
  process.argv = ['node', extractedFile, ...argv];
1722
+ let lastExitAttemptCode = 0;
1390
1723
  process.exit = code => {
1391
- throw new RequestedExit(code);
1724
+ lastExitAttemptCode = code ?? 0;
1725
+ throw new RequestedExit(lastExitAttemptCode);
1726
+ };
1727
+ process.kill = (pid, signal) => {
1728
+ if (pid === process.pid && (signal === 'SIGKILL' || signal === 9)) {
1729
+ throw new RequestedExit(lastExitAttemptCode);
1730
+ }
1731
+ return originalKill.call(process, pid, signal);
1392
1732
  };
1393
1733
 
1734
+ if (isStreamJsonPrintMode(argv)) {
1735
+ streamJsonWatcher = installStreamJsonTerminalWatcher();
1736
+ }
1737
+
1394
1738
  const moduleLike = { exports: {} };
1395
1739
  const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
1396
1740
  if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
1741
+ await waitForPrintFlushIfNeeded();
1397
1742
  if (asyncErrors.length > 0) throw asyncErrors[0];
1398
1743
  } catch (error) {
1399
1744
  if (error instanceof RequestedExit) {
1400
1745
  process.exitCode = error.code;
1746
+ await waitForPrintFlushIfNeeded();
1401
1747
  return;
1402
1748
  }
1403
1749
  throw error;
@@ -1406,6 +1752,10 @@ async function main() {
1406
1752
  process.removeListener('unhandledRejection', onAsyncError);
1407
1753
  process.argv = originalArgv;
1408
1754
  process.exit = originalExit;
1755
+ process.kill = originalKill;
1756
+ if (streamJsonWatcher) {
1757
+ try { streamJsonWatcher.restore(); } catch {}
1758
+ }
1409
1759
  process.once('exit', () => {
1410
1760
  if (extractedFile) {
1411
1761
  try {