@bash0816/claude-code 2.1.220 → 2.1.223-1
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.
|
|
40
|
+
npm install -g @bash0816/claude-code@2.1.223
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
## Update / 更新
|
|
@@ -66,6 +66,35 @@ Normal launch also checks the same manifest with a short timeout and prints a no
|
|
|
66
66
|
|
|
67
67
|
通常起動時も、同じ manifest を短い timeout で確認し、新しい監査済み version があれば通知します。
|
|
68
68
|
|
|
69
|
+
## Known Issues / 既知の問題
|
|
70
|
+
|
|
71
|
+
Background sessions (`/background`, `claude agents`, the on-demand daemon) do not work on this
|
|
72
|
+
Termux wrapper: the Bun `Terminal` (PTY) API is not implemented by the compatibility shim. Since
|
|
73
|
+
`2.1.223-1`, this feature is disabled by default (`CLAUDE_CODE_DISABLE_AGENT_VIEW=1`) because
|
|
74
|
+
attempting to use it can cause an in-progress foreground conversation to be unexpectedly moved to
|
|
75
|
+
the background and become unreachable.
|
|
76
|
+
|
|
77
|
+
この Termux wrapper では、background session 機能(`/background`、`claude agents`、on-demand
|
|
78
|
+
daemon)が動作しません。互換 shim には Bun の `Terminal`(PTY)API が実装されていないためです。
|
|
79
|
+
`2.1.223-1` からはこの機能をデフォルトで無効化しています(`CLAUDE_CODE_DISABLE_AGENT_VIEW=1`)。
|
|
80
|
+
これは、この機能を使おうとすると、**進行中のフォアグラウンド会話が予告なくバックグラウンドへ
|
|
81
|
+
移動し、到達不能になることがある**ためです。
|
|
82
|
+
|
|
83
|
+
If you want to re-enable it anyway (understanding it may cause this issue), set the variable to
|
|
84
|
+
exactly `0` before launching:
|
|
85
|
+
|
|
86
|
+
理解した上であえて再有効化したい場合は、起動前に厳密に `0` を設定してください:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
CLAUDE_CODE_DISABLE_AGENT_VIEW=0 claude
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Any value other than `1`/`true`/`yes`/`on` (case-insensitive) re-enables the feature, so a typo
|
|
93
|
+
like `disable` or `Y` will silently turn protection off. Use exactly `0` to be safe.
|
|
94
|
+
|
|
95
|
+
`1`/`true`/`yes`/`on`(大文字小文字を区別しません)以外の値は全て機能を再有効化してしまうため、
|
|
96
|
+
`disable` や `Y` のような typo でも保護が黙って外れます。安全のため厳密に `0` を指定してください。
|
|
97
|
+
|
|
69
98
|
## Policy / 方針
|
|
70
99
|
|
|
71
100
|
- Only audited versions in `config/claude-native-audited-versions.json` can run.
|
package/bin/claude
CHANGED
|
@@ -63,4 +63,5 @@ ENTRY_END_OFFSET="${ENTRY_END_OFFSET}" \
|
|
|
63
63
|
CURRENT_CLAUDE_VERSION="${CLAUDE_VERSION}" \
|
|
64
64
|
CLAUDE_TERMUX_PACKAGE_DIR="${PACKAGE_DIR}" \
|
|
65
65
|
CLAUDE_NATIVE_UPDATE_CHECK=0 \
|
|
66
|
+
CLAUDE_CODE_DISABLE_AGENT_VIEW="${CLAUDE_CODE_DISABLE_AGENT_VIEW:-1}" \
|
|
66
67
|
exec sh "${PACKAGE_DIR}/lib/termux-run-claude-native.sh" "$@"
|
|
@@ -580,6 +580,69 @@
|
|
|
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",
|
|
637
|
+
"status": "termux_verified"
|
|
638
|
+
},
|
|
639
|
+
"2.1.223-1": {
|
|
640
|
+
"wrapper_spec": "@anthropic-ai/claude-code@2.1.223",
|
|
641
|
+
"native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.223",
|
|
642
|
+
"entry_js_offset": 257987828,
|
|
643
|
+
"entry_end_offset": 281109040,
|
|
644
|
+
"tarball_integrity": "sha512-gh0n3fvUgzsrjeTqZraOhDKOzS7afB9U/qFvRY0FBpccogbJCk8otTYavPfdhAA2xESAoA0BaoVdzO4k4VkphA==",
|
|
645
|
+
"tarball_sha256": "29c49ec62bfbe995e5b1354a4c32d17101065d2c7722d5d0285cfa6a08d8c441",
|
|
583
646
|
"status": "offset_discovered"
|
|
584
647
|
}
|
|
585
648
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 1,
|
|
3
3
|
"package_name": "@bash0816/claude-code",
|
|
4
|
-
"latest_audited_version": "2.1.
|
|
5
|
-
"latest_candidate_version": "2.1.
|
|
6
|
-
"previous_stable_version": "2.1.
|
|
4
|
+
"latest_audited_version": "2.1.223",
|
|
5
|
+
"latest_candidate_version": "2.1.223-1",
|
|
6
|
+
"previous_stable_version": "2.1.222",
|
|
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,25 @@ 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
|
+
);
|
|
638
|
+
const _agentViewDisabled = ['1', 'true', 'yes', 'on'].includes(
|
|
639
|
+
String(process.env.CLAUDE_CODE_DISABLE_AGENT_VIEW ?? '').toLowerCase().trim(),
|
|
640
|
+
);
|
|
641
|
+
if (_agentViewDisabled) {
|
|
642
|
+
patched = replaceRequired(
|
|
643
|
+
patched,
|
|
644
|
+
/(\{type:"local-jsx",name:"background",aliases:\["bg"\][^}]*?isEnabled:\(\)=>)!0(\})/g,
|
|
645
|
+
'$1!1$2',
|
|
646
|
+
'/background command isEnabled disable',
|
|
647
|
+
1,
|
|
648
|
+
);
|
|
649
|
+
}
|
|
614
650
|
return patched;
|
|
615
651
|
}
|
|
616
652
|
|
|
@@ -623,10 +659,12 @@ async function main() {
|
|
|
623
659
|
|
|
624
660
|
const originalArgv = process.argv.slice();
|
|
625
661
|
const originalExit = process.exit;
|
|
662
|
+
const originalKill = process.kill;
|
|
626
663
|
const originalBun = process.versions.bun;
|
|
627
664
|
const hadGlobalBun = Object.prototype.hasOwnProperty.call(globalThis, 'Bun');
|
|
628
665
|
const originalGlobalBun = globalThis.Bun;
|
|
629
666
|
const asyncErrors = [];
|
|
667
|
+
let streamJsonWatcher = null;
|
|
630
668
|
|
|
631
669
|
globalThis.__claudeYaml = createYamlShim();
|
|
632
670
|
if (!globalThis.__claudeBunShim || typeof globalThis.__claudeBunShim !== 'object') {
|
|
@@ -636,6 +674,100 @@ async function main() {
|
|
|
636
674
|
function onAsyncError(error) {
|
|
637
675
|
asyncErrors.push(error);
|
|
638
676
|
}
|
|
677
|
+
const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
|
|
678
|
+
|
|
679
|
+
function installStreamJsonTerminalWatcher() {
|
|
680
|
+
const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
|
|
681
|
+
const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
|
|
682
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
683
|
+
const { StringDecoder } = require('string_decoder');
|
|
684
|
+
const decoder = new StringDecoder('utf8');
|
|
685
|
+
let lineBuffer = '';
|
|
686
|
+
let resultPromiseResolve = null;
|
|
687
|
+
let foundResult = false;
|
|
688
|
+
let restored = false;
|
|
689
|
+
|
|
690
|
+
process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
|
|
691
|
+
let cb = callback;
|
|
692
|
+
let enc = encoding;
|
|
693
|
+
if (typeof encoding === 'function') {
|
|
694
|
+
cb = encoding;
|
|
695
|
+
enc = undefined;
|
|
696
|
+
}
|
|
697
|
+
const combinedCallback = (err) => {
|
|
698
|
+
if (!err && !foundResult) {
|
|
699
|
+
const chunkStr = typeof chunk === 'string'
|
|
700
|
+
? decoder.write(Buffer.from(chunk, typeof enc === 'string' ? enc : 'utf8'))
|
|
701
|
+
: decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
702
|
+
lineBuffer += chunkStr;
|
|
703
|
+
const lines = lineBuffer.split('\n');
|
|
704
|
+
lineBuffer = lines[lines.length - 1];
|
|
705
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
706
|
+
try {
|
|
707
|
+
const parsed = JSON.parse(lines[i]);
|
|
708
|
+
if (parsed && parsed.type === 'result') {
|
|
709
|
+
foundResult = true;
|
|
710
|
+
if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
|
|
711
|
+
}
|
|
712
|
+
} catch {}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if (typeof cb === 'function') cb(err);
|
|
716
|
+
};
|
|
717
|
+
return originalWrite(chunk, enc, combinedCallback);
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
return {
|
|
721
|
+
waitForResult() {
|
|
722
|
+
if (foundResult) return Promise.resolve();
|
|
723
|
+
return new Promise((resolve, reject) => {
|
|
724
|
+
resultPromiseResolve = resolve;
|
|
725
|
+
});
|
|
726
|
+
},
|
|
727
|
+
restore() {
|
|
728
|
+
if (restored) return;
|
|
729
|
+
restored = true;
|
|
730
|
+
if (hadOwnWrite) {
|
|
731
|
+
Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
|
|
732
|
+
} else {
|
|
733
|
+
delete process.stdout.write;
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function forceTimeoutExit(exitCode) {
|
|
740
|
+
try { if (streamJsonWatcher) streamJsonWatcher.restore(); } catch {}
|
|
741
|
+
if (extractedFile) {
|
|
742
|
+
try { fs.rmSync(extractedFile, { force: true }); } catch {}
|
|
743
|
+
}
|
|
744
|
+
originalExit(exitCode);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
async function waitForPrintFlush() {
|
|
748
|
+
if (isStreamJsonPrintMode(argv) && streamJsonWatcher) {
|
|
749
|
+
let timedOut = false;
|
|
750
|
+
const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
|
|
751
|
+
const resultTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
|
|
752
|
+
let timeoutHandle;
|
|
753
|
+
const timeoutPromise = new Promise(resolve => {
|
|
754
|
+
timeoutHandle = setTimeout(() => { timedOut = true; resolve(); }, resultTimeoutMs);
|
|
755
|
+
});
|
|
756
|
+
try {
|
|
757
|
+
await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
|
|
758
|
+
} finally {
|
|
759
|
+
clearTimeout(timeoutHandle);
|
|
760
|
+
}
|
|
761
|
+
if (timedOut) {
|
|
762
|
+
forceTimeoutExit(1);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
|
|
768
|
+
await new Promise(resolve => setTimeout(resolve, printWaitMs));
|
|
769
|
+
}
|
|
770
|
+
}
|
|
639
771
|
|
|
640
772
|
try {
|
|
641
773
|
process.once('uncaughtException', onAsyncError);
|
|
@@ -683,9 +815,47 @@ async function main() {
|
|
|
683
815
|
gte: (a, b) => _cmp(a, b) >= 0,
|
|
684
816
|
lt: (a, b) => _cmp(a, b) < 0,
|
|
685
817
|
lte: (a, b) => _cmp(a, b) <= 0,
|
|
686
|
-
|
|
818
|
+
};
|
|
687
819
|
})(),
|
|
688
820
|
YAML: globalThis.__claudeYaml,
|
|
821
|
+
spawn: (cmd, options) => {
|
|
822
|
+
const opts = options || {};
|
|
823
|
+
const stdioArrayRaw = opts.stdio;
|
|
824
|
+
const cmdArray = Array.isArray(cmd) ? cmd : [cmd];
|
|
825
|
+
const normalizeStdio = (v) => {
|
|
826
|
+
if (typeof v === 'number' && Number.isInteger(v) && v >= 0) return v;
|
|
827
|
+
return (v === 'ignore' || v === 'pipe' || v === 'inherit') ? v : 'pipe';
|
|
828
|
+
};
|
|
829
|
+
const stdioMapped = Array.isArray(stdioArrayRaw)
|
|
830
|
+
? stdioArrayRaw.map(normalizeStdio)
|
|
831
|
+
: [normalizeStdio(opts.stdin), normalizeStdio(opts.stdout), normalizeStdio(opts.stderr)];
|
|
832
|
+
const child = _realChild.spawn(cmdArray[0], cmdArray.slice(1), {
|
|
833
|
+
stdio: stdioMapped,
|
|
834
|
+
cwd: opts.cwd,
|
|
835
|
+
env: opts.env,
|
|
836
|
+
detached: !!opts.detached,
|
|
837
|
+
argv0: opts.argv0,
|
|
838
|
+
});
|
|
839
|
+
const stdoutChunks = [];
|
|
840
|
+
if (child.stdout) child.stdout.on('data', d => stdoutChunks.push(d));
|
|
841
|
+
let resolveExited;
|
|
842
|
+
const exited = new Promise(resolve => { resolveExited = resolve; });
|
|
843
|
+
child.on('exit', (code, signal) => resolveExited(code !== null ? code : (signal ? 128 : 0)));
|
|
844
|
+
child.on('error', () => resolveExited(1));
|
|
845
|
+
return {
|
|
846
|
+
pid: child.pid,
|
|
847
|
+
exited,
|
|
848
|
+
stdout: { text: async () => { await exited; return Buffer.concat(stdoutChunks).toString('utf8'); } },
|
|
849
|
+
unref: () => { try { child.unref(); } catch {} },
|
|
850
|
+
kill: (signal) => { try { child.kill(signal); } catch {} },
|
|
851
|
+
};
|
|
852
|
+
},
|
|
853
|
+
file: (path) => {
|
|
854
|
+
const err = new Error(`ENOENT: Bun.file(${String(path)}) is not supported by the Termux compatibility shim`);
|
|
855
|
+
err.code = 'ENOENT';
|
|
856
|
+
err.errno = -2;
|
|
857
|
+
throw err;
|
|
858
|
+
},
|
|
689
859
|
};
|
|
690
860
|
Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
|
|
691
861
|
if (typeof globalThis.__claudeBunShim.gc !== 'function') {
|
|
@@ -694,21 +864,31 @@ async function main() {
|
|
|
694
864
|
globalThis.__claudeBun = globalThis.__claudeBunShim;
|
|
695
865
|
globalThis.Bun = globalThis.__claudeBunShim;
|
|
696
866
|
process.argv = ['node', extractedFile, ...argv];
|
|
867
|
+
let lastExitAttemptCode = 0;
|
|
697
868
|
process.exit = code => {
|
|
698
|
-
|
|
869
|
+
lastExitAttemptCode = code ?? 0;
|
|
870
|
+
throw new RequestedExit(lastExitAttemptCode);
|
|
871
|
+
};
|
|
872
|
+
process.kill = (pid, signal) => {
|
|
873
|
+
if (pid === process.pid && (signal === 'SIGKILL' || signal === 9)) {
|
|
874
|
+
throw new RequestedExit(lastExitAttemptCode);
|
|
875
|
+
}
|
|
876
|
+
return originalKill.call(process, pid, signal);
|
|
699
877
|
};
|
|
700
878
|
|
|
701
|
-
|
|
879
|
+
if (isStreamJsonPrintMode(argv)) {
|
|
880
|
+
streamJsonWatcher = installStreamJsonTerminalWatcher();
|
|
881
|
+
}
|
|
882
|
+
|
|
702
883
|
const moduleLike = { exports: {} };
|
|
703
884
|
const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
|
|
704
885
|
if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
|
|
705
|
-
|
|
706
|
-
await new Promise(resolve => setTimeout(resolve, printWaitMs));
|
|
707
|
-
}
|
|
886
|
+
await waitForPrintFlush();
|
|
708
887
|
if (asyncErrors.length > 0) throw asyncErrors[0];
|
|
709
888
|
} catch (error) {
|
|
710
889
|
if (error instanceof RequestedExit) {
|
|
711
890
|
process.exitCode = error.code;
|
|
891
|
+
await waitForPrintFlush();
|
|
712
892
|
return;
|
|
713
893
|
}
|
|
714
894
|
throw error;
|
|
@@ -722,6 +902,10 @@ async function main() {
|
|
|
722
902
|
}
|
|
723
903
|
process.argv = originalArgv;
|
|
724
904
|
process.exit = originalExit;
|
|
905
|
+
process.kill = originalKill;
|
|
906
|
+
if (streamJsonWatcher) {
|
|
907
|
+
try { streamJsonWatcher.restore(); } catch {}
|
|
908
|
+
}
|
|
725
909
|
try {
|
|
726
910
|
if (originalBun === undefined) {
|
|
727
911
|
delete process.versions.bun;
|
|
@@ -758,6 +942,7 @@ else
|
|
|
758
942
|
_bootstrap=$(mktemp "${TERMUX_TMPDIR}/claude-bootstrap.XXXXXX.js")
|
|
759
943
|
trap 'rm -f "$_bootstrap"' EXIT HUP INT TERM
|
|
760
944
|
export CLAUDE_TERMUX_TUI="${_tui}"
|
|
945
|
+
export CLAUDE_TERMUX_PRINT_MODE="${_pf}"
|
|
761
946
|
cat <<'NODE' > "$_bootstrap"
|
|
762
947
|
const fs = require('fs');
|
|
763
948
|
const path = require('path');
|
|
@@ -772,6 +957,22 @@ const entryJsOffset = Number(process.env.ENTRY_JS_OFFSET);
|
|
|
772
957
|
const entryEndOffset = Number(process.env.ENTRY_END_OFFSET);
|
|
773
958
|
const argv = process.argv.slice(2);
|
|
774
959
|
|
|
960
|
+
function isStreamJsonPrintMode(argv) {
|
|
961
|
+
const dashDashIndex = argv.indexOf('--');
|
|
962
|
+
const ownArgs = dashDashIndex === -1 ? argv : argv.slice(0, dashDashIndex);
|
|
963
|
+
const hasPrintFlag = ownArgs.includes('-p') || ownArgs.includes('--print');
|
|
964
|
+
let hasStreamJsonFormat = false;
|
|
965
|
+
for (let i = 0; i < ownArgs.length; i++) {
|
|
966
|
+
const tok = ownArgs[i];
|
|
967
|
+
if (tok === '--output-format=stream-json') { hasStreamJsonFormat = true; break; }
|
|
968
|
+
if (tok === '--output-format' && ownArgs[i + 1] === 'stream-json') {
|
|
969
|
+
hasStreamJsonFormat = true;
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return hasPrintFlag && hasStreamJsonFormat;
|
|
974
|
+
}
|
|
975
|
+
|
|
775
976
|
class RequestedExit extends Error {
|
|
776
977
|
constructor(code) {
|
|
777
978
|
super(`process.exit ${code}`);
|
|
@@ -1276,6 +1477,7 @@ function rewriteNativeChunkSource(source) {
|
|
|
1276
1477
|
const _bunPropertyAccessExpected = (() => {
|
|
1277
1478
|
const _ver = String(process.env.CURRENT_CLAUDE_VERSION || '');
|
|
1278
1479
|
const _m = _ver.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
1480
|
+
if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 223)) return 43;
|
|
1279
1481
|
if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 219)) return 42;
|
|
1280
1482
|
if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 216)) return 40;
|
|
1281
1483
|
if (_m && (Number(_m[1]) > 2 || Number(_m[2]) > 1 || Number(_m[3]) >= 214)) return 39;
|
|
@@ -1304,6 +1506,25 @@ function rewriteNativeChunkSource(source) {
|
|
|
1304
1506
|
'npmInstallDeprecated flag',
|
|
1305
1507
|
_npmInstallDeprecatedExpected,
|
|
1306
1508
|
);
|
|
1509
|
+
patched = replaceRequired(
|
|
1510
|
+
patched,
|
|
1511
|
+
/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,
|
|
1512
|
+
'function $1(){return undefined;$2',
|
|
1513
|
+
'bg-pty-host factory disable',
|
|
1514
|
+
1,
|
|
1515
|
+
);
|
|
1516
|
+
const _agentViewDisabled = ['1', 'true', 'yes', 'on'].includes(
|
|
1517
|
+
String(process.env.CLAUDE_CODE_DISABLE_AGENT_VIEW ?? '').toLowerCase().trim(),
|
|
1518
|
+
);
|
|
1519
|
+
if (_agentViewDisabled) {
|
|
1520
|
+
patched = replaceRequired(
|
|
1521
|
+
patched,
|
|
1522
|
+
/(\{type:"local-jsx",name:"background",aliases:\["bg"\][^}]*?isEnabled:\(\)=>)!0(\})/g,
|
|
1523
|
+
'$1!1$2',
|
|
1524
|
+
'/background command isEnabled disable',
|
|
1525
|
+
1,
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1307
1528
|
return patched;
|
|
1308
1529
|
}
|
|
1309
1530
|
|
|
@@ -1316,10 +1537,12 @@ async function main() {
|
|
|
1316
1537
|
|
|
1317
1538
|
const originalArgv = process.argv.slice();
|
|
1318
1539
|
const originalExit = process.exit;
|
|
1540
|
+
const originalKill = process.kill;
|
|
1319
1541
|
const originalBun = process.versions.bun;
|
|
1320
1542
|
const hadGlobalBun = Object.prototype.hasOwnProperty.call(globalThis, 'Bun');
|
|
1321
1543
|
const originalGlobalBun = globalThis.Bun;
|
|
1322
1544
|
const asyncErrors = [];
|
|
1545
|
+
let streamJsonWatcher = null;
|
|
1323
1546
|
|
|
1324
1547
|
globalThis.__claudeYaml = createYamlShim();
|
|
1325
1548
|
if (!globalThis.__claudeBunShim || typeof globalThis.__claudeBunShim !== 'object') {
|
|
@@ -1330,6 +1553,101 @@ async function main() {
|
|
|
1330
1553
|
asyncErrors.push(error);
|
|
1331
1554
|
}
|
|
1332
1555
|
|
|
1556
|
+
function installStreamJsonTerminalWatcher() {
|
|
1557
|
+
const hadOwnWrite = Object.prototype.hasOwnProperty.call(process.stdout, 'write');
|
|
1558
|
+
const originalWriteDescriptor = hadOwnWrite ? Object.getOwnPropertyDescriptor(process.stdout, 'write') : undefined;
|
|
1559
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
1560
|
+
const { StringDecoder } = require('string_decoder');
|
|
1561
|
+
const decoder = new StringDecoder('utf8');
|
|
1562
|
+
let lineBuffer = '';
|
|
1563
|
+
let resultPromiseResolve = null;
|
|
1564
|
+
let foundResult = false;
|
|
1565
|
+
let restored = false;
|
|
1566
|
+
|
|
1567
|
+
process.stdout.write = function wrappedWrite(chunk, encoding, callback) {
|
|
1568
|
+
let cb = callback;
|
|
1569
|
+
let enc = encoding;
|
|
1570
|
+
if (typeof encoding === 'function') {
|
|
1571
|
+
cb = encoding;
|
|
1572
|
+
enc = undefined;
|
|
1573
|
+
}
|
|
1574
|
+
const combinedCallback = (err) => {
|
|
1575
|
+
if (!err && !foundResult) {
|
|
1576
|
+
const chunkStr = typeof chunk === 'string'
|
|
1577
|
+
? decoder.write(Buffer.from(chunk, typeof enc === 'string' ? enc : 'utf8'))
|
|
1578
|
+
: decoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1579
|
+
lineBuffer += chunkStr;
|
|
1580
|
+
const lines = lineBuffer.split('\n');
|
|
1581
|
+
lineBuffer = lines[lines.length - 1];
|
|
1582
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
1583
|
+
try {
|
|
1584
|
+
const parsed = JSON.parse(lines[i]);
|
|
1585
|
+
if (parsed && parsed.type === 'result') {
|
|
1586
|
+
foundResult = true;
|
|
1587
|
+
if (typeof resultPromiseResolve === 'function') resultPromiseResolve();
|
|
1588
|
+
}
|
|
1589
|
+
} catch {}
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
if (typeof cb === 'function') cb(err);
|
|
1593
|
+
};
|
|
1594
|
+
return originalWrite(chunk, enc, combinedCallback);
|
|
1595
|
+
};
|
|
1596
|
+
|
|
1597
|
+
return {
|
|
1598
|
+
waitForResult() {
|
|
1599
|
+
if (foundResult) return Promise.resolve();
|
|
1600
|
+
return new Promise((resolve, reject) => {
|
|
1601
|
+
resultPromiseResolve = resolve;
|
|
1602
|
+
});
|
|
1603
|
+
},
|
|
1604
|
+
restore() {
|
|
1605
|
+
if (restored) return;
|
|
1606
|
+
restored = true;
|
|
1607
|
+
if (hadOwnWrite) {
|
|
1608
|
+
Object.defineProperty(process.stdout, 'write', originalWriteDescriptor);
|
|
1609
|
+
} else {
|
|
1610
|
+
delete process.stdout.write;
|
|
1611
|
+
}
|
|
1612
|
+
},
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
function forceTimeoutExit(exitCode) {
|
|
1617
|
+
try { if (streamJsonWatcher) streamJsonWatcher.restore(); } catch {}
|
|
1618
|
+
if (extractedFile) {
|
|
1619
|
+
try { fs.rmSync(extractedFile, { force: true }); } catch {}
|
|
1620
|
+
}
|
|
1621
|
+
originalExit(exitCode);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
async function waitForPrintFlushIfNeeded() {
|
|
1625
|
+
if (process.env.CLAUDE_TERMUX_PRINT_MODE !== '1') return;
|
|
1626
|
+
if (isStreamJsonPrintMode(argv) && streamJsonWatcher) {
|
|
1627
|
+
let timedOut = false;
|
|
1628
|
+
const rawResultTimeoutMs = Number(process.env.CLAUDE_TERMUX_PRINT_RESULT_TIMEOUT_MS);
|
|
1629
|
+
const resultTimeoutMs = (Number.isFinite(rawResultTimeoutMs) && rawResultTimeoutMs > 0) ? rawResultTimeoutMs : 300000;
|
|
1630
|
+
let timeoutHandle;
|
|
1631
|
+
const timeoutPromise = new Promise(resolve => {
|
|
1632
|
+
timeoutHandle = setTimeout(() => { timedOut = true; resolve(); }, resultTimeoutMs);
|
|
1633
|
+
});
|
|
1634
|
+
try {
|
|
1635
|
+
await Promise.race([streamJsonWatcher.waitForResult(), timeoutPromise]);
|
|
1636
|
+
} finally {
|
|
1637
|
+
clearTimeout(timeoutHandle);
|
|
1638
|
+
}
|
|
1639
|
+
if (timedOut) {
|
|
1640
|
+
forceTimeoutExit(1);
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
const printWaitMs = Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 5000);
|
|
1646
|
+
if (Number.isFinite(printWaitMs) && printWaitMs > 0) {
|
|
1647
|
+
await new Promise(resolve => setTimeout(resolve, printWaitMs));
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1333
1651
|
try {
|
|
1334
1652
|
process.once('uncaughtException', onAsyncError);
|
|
1335
1653
|
process.once('unhandledRejection', onAsyncError);
|
|
@@ -1379,6 +1697,44 @@ async function main() {
|
|
|
1379
1697
|
};
|
|
1380
1698
|
})(),
|
|
1381
1699
|
YAML: globalThis.__claudeYaml,
|
|
1700
|
+
spawn: (cmd, options) => {
|
|
1701
|
+
const opts = options || {};
|
|
1702
|
+
const stdioArrayRaw = opts.stdio;
|
|
1703
|
+
const cmdArray = Array.isArray(cmd) ? cmd : [cmd];
|
|
1704
|
+
const normalizeStdio = (v) => {
|
|
1705
|
+
if (typeof v === 'number' && Number.isInteger(v) && v >= 0) return v;
|
|
1706
|
+
return (v === 'ignore' || v === 'pipe' || v === 'inherit') ? v : 'pipe';
|
|
1707
|
+
};
|
|
1708
|
+
const stdioMapped = Array.isArray(stdioArrayRaw)
|
|
1709
|
+
? stdioArrayRaw.map(normalizeStdio)
|
|
1710
|
+
: [normalizeStdio(opts.stdin), normalizeStdio(opts.stdout), normalizeStdio(opts.stderr)];
|
|
1711
|
+
const child = _realChild.spawn(cmdArray[0], cmdArray.slice(1), {
|
|
1712
|
+
stdio: stdioMapped,
|
|
1713
|
+
cwd: opts.cwd,
|
|
1714
|
+
env: opts.env,
|
|
1715
|
+
detached: !!opts.detached,
|
|
1716
|
+
argv0: opts.argv0,
|
|
1717
|
+
});
|
|
1718
|
+
const stdoutChunks = [];
|
|
1719
|
+
if (child.stdout) child.stdout.on('data', d => stdoutChunks.push(d));
|
|
1720
|
+
let resolveExited;
|
|
1721
|
+
const exited = new Promise(resolve => { resolveExited = resolve; });
|
|
1722
|
+
child.on('exit', (code, signal) => resolveExited(code !== null ? code : (signal ? 128 : 0)));
|
|
1723
|
+
child.on('error', () => resolveExited(1));
|
|
1724
|
+
return {
|
|
1725
|
+
pid: child.pid,
|
|
1726
|
+
exited,
|
|
1727
|
+
stdout: { text: async () => { await exited; return Buffer.concat(stdoutChunks).toString('utf8'); } },
|
|
1728
|
+
unref: () => { try { child.unref(); } catch {} },
|
|
1729
|
+
kill: (signal) => { try { child.kill(signal); } catch {} },
|
|
1730
|
+
};
|
|
1731
|
+
},
|
|
1732
|
+
file: (path) => {
|
|
1733
|
+
const err = new Error(`ENOENT: Bun.file(${String(path)}) is not supported by the Termux compatibility shim`);
|
|
1734
|
+
err.code = 'ENOENT';
|
|
1735
|
+
err.errno = -2;
|
|
1736
|
+
throw err;
|
|
1737
|
+
},
|
|
1382
1738
|
};
|
|
1383
1739
|
Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
|
|
1384
1740
|
if (typeof globalThis.__claudeBunShim.gc !== 'function') {
|
|
@@ -1387,17 +1743,31 @@ async function main() {
|
|
|
1387
1743
|
globalThis.__claudeBun = globalThis.__claudeBunShim;
|
|
1388
1744
|
globalThis.Bun = globalThis.__claudeBunShim;
|
|
1389
1745
|
process.argv = ['node', extractedFile, ...argv];
|
|
1746
|
+
let lastExitAttemptCode = 0;
|
|
1390
1747
|
process.exit = code => {
|
|
1391
|
-
|
|
1748
|
+
lastExitAttemptCode = code ?? 0;
|
|
1749
|
+
throw new RequestedExit(lastExitAttemptCode);
|
|
1750
|
+
};
|
|
1751
|
+
process.kill = (pid, signal) => {
|
|
1752
|
+
if (pid === process.pid && (signal === 'SIGKILL' || signal === 9)) {
|
|
1753
|
+
throw new RequestedExit(lastExitAttemptCode);
|
|
1754
|
+
}
|
|
1755
|
+
return originalKill.call(process, pid, signal);
|
|
1392
1756
|
};
|
|
1393
1757
|
|
|
1758
|
+
if (isStreamJsonPrintMode(argv)) {
|
|
1759
|
+
streamJsonWatcher = installStreamJsonTerminalWatcher();
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1394
1762
|
const moduleLike = { exports: {} };
|
|
1395
1763
|
const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
|
|
1396
1764
|
if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
|
|
1765
|
+
await waitForPrintFlushIfNeeded();
|
|
1397
1766
|
if (asyncErrors.length > 0) throw asyncErrors[0];
|
|
1398
1767
|
} catch (error) {
|
|
1399
1768
|
if (error instanceof RequestedExit) {
|
|
1400
1769
|
process.exitCode = error.code;
|
|
1770
|
+
await waitForPrintFlushIfNeeded();
|
|
1401
1771
|
return;
|
|
1402
1772
|
}
|
|
1403
1773
|
throw error;
|
|
@@ -1406,6 +1776,10 @@ async function main() {
|
|
|
1406
1776
|
process.removeListener('unhandledRejection', onAsyncError);
|
|
1407
1777
|
process.argv = originalArgv;
|
|
1408
1778
|
process.exit = originalExit;
|
|
1779
|
+
process.kill = originalKill;
|
|
1780
|
+
if (streamJsonWatcher) {
|
|
1781
|
+
try { streamJsonWatcher.restore(); } catch {}
|
|
1782
|
+
}
|
|
1409
1783
|
process.once('exit', () => {
|
|
1410
1784
|
if (extractedFile) {
|
|
1411
1785
|
try {
|