@bash0816/claude-code 2.1.159-1 → 2.1.159-13

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
@@ -43,7 +43,7 @@ Current quick examples:
43
43
  現在の quick example:
44
44
 
45
45
  ```sh
46
- npm install -g @bash0816/claude-code@2.1.157
46
+ npm install -g @bash0816/claude-code@2.1.159-13
47
47
  ```
48
48
 
49
49
  ## Update / 更新
@@ -68,8 +68,8 @@ Normal launch also checks the same manifest with a short timeout and prints a no
68
68
 
69
69
  - Only audited versions in `config/claude-native-audited-versions.json` can run.
70
70
  - `config/claude-native-audited-versions.json` にある監査済み version だけを実行できます。
71
- - `2.1.150-1`, `2.1.150-2`, `2.1.150-3`, `2.1.153-1`, `2.1.153-2`, `2.1.153-3`, `2.1.153-4`, `2.1.118`, `2.1.119`, `2.1.121`, `2.1.122`, `2.1.123`, `2.1.126`, `2.1.128`, `2.1.136`, `2.1.137`, `2.1.138`, `2.1.139`, `2.1.140`, `2.1.141`, `2.1.142`, `2.1.143`, `2.1.144`, `2.1.150`, `2.1.153`, `2.1.157` are included in the package metadata.
72
- - `2.1.150-1`、`2.1.150-2`、`2.1.150-3`、`2.1.153-1`、`2.1.153-2`、`2.1.153-3`、`2.1.153-4`、`2.1.118`、`2.1.119`、`2.1.121`、`2.1.122`、`2.1.123`、`2.1.126`、`2.1.128`、`2.1.136`、`2.1.137`、`2.1.138`、`2.1.139`、`2.1.140`、`2.1.141`、`2.1.142`、`2.1.143`、`2.1.144`、`2.1.150`、`2.1.153`、`2.1.157` を package metadata に含めています。
71
+ - `2.1.118`, `2.1.119`, `2.1.121`, `2.1.122`, `2.1.123`, `2.1.126`, `2.1.128`, `2.1.136`, `2.1.137`, `2.1.138`, `2.1.139`, `2.1.140`, `2.1.141`, `2.1.142`, `2.1.143`, `2.1.144`, `2.1.150`, `2.1.150-1`, `2.1.150-2`, `2.1.150-3`, `2.1.153`, `2.1.153-1`, `2.1.153-2`, `2.1.153-3`, `2.1.153-4`, `2.1.157`, `2.1.159-4`, `2.1.159-8`, `2.1.159-10`, `2.1.159-13` are included in the package metadata.
72
+ - `2.1.118`、`2.1.119`、`2.1.121`、`2.1.122`、`2.1.123`、`2.1.126`、`2.1.128`、`2.1.136`、`2.1.137`、`2.1.138`、`2.1.139`、`2.1.140`、`2.1.141`、`2.1.142`、`2.1.143`、`2.1.144`、`2.1.150`、`2.1.150-1`、`2.1.150-2`、`2.1.150-3`、`2.1.153`、`2.1.153-1`、`2.1.153-2`、`2.1.153-3`、`2.1.153-4`、`2.1.157`、`2.1.159-4`、`2.1.159-8`、`2.1.159-10`、`2.1.159-13` を package metadata に含めています。
73
73
  - The metadata file is the source of truth for the currently audited set.
74
74
  - 現在の監査済み version 集合の source of truth は metadata file です。
75
75
  - Native artifacts are cached under `${HOME}/.claude-termux-native-package`.
@@ -181,6 +181,69 @@
181
181
  "entry_js_offset": 223210916,
182
182
  "entry_end_offset": 238725072,
183
183
  "status": "termux_verified"
184
+ },
185
+ "2.1.159-2": {
186
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
187
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
188
+ "entry_js_offset": 223232708,
189
+ "entry_end_offset": 238749397,
190
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
191
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
192
+ "status": "offset_discovered"
193
+ },
194
+ "2.1.159-4": {
195
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
196
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
197
+ "entry_js_offset": 223232708,
198
+ "entry_end_offset": 238749397,
199
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
200
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
201
+ "status": "termux_verified"
202
+ },
203
+ "2.1.159-5": {
204
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
205
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
206
+ "entry_js_offset": 223232708,
207
+ "entry_end_offset": 238749397,
208
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
209
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
210
+ "status": "offset_discovered"
211
+ },
212
+ "2.1.159-8": {
213
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
214
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
215
+ "entry_js_offset": 223232708,
216
+ "entry_end_offset": 238749397,
217
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
218
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
219
+ "status": "termux_verified"
220
+ },
221
+ "2.1.159-10": {
222
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
223
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
224
+ "entry_js_offset": 223232708,
225
+ "entry_end_offset": 238749397,
226
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
227
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
228
+ "status": "termux_verified"
229
+ },
230
+ "2.1.159-12": {
231
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
232
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
233
+ "entry_js_offset": 223232708,
234
+ "entry_end_offset": 238749397,
235
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
236
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
237
+ "status": "offset_discovered"
238
+ },
239
+ "2.1.159-13": {
240
+ "wrapper_spec": "@anthropic-ai/claude-code@2.1.159",
241
+ "native_spec": "@anthropic-ai/claude-code-linux-arm64@2.1.159",
242
+ "entry_js_offset": 223232708,
243
+ "entry_end_offset": 238749397,
244
+ "tarball_integrity": "sha512-c8dXbuQdrotGWll46GlnXm5IPpORK2VrBSosCmI6f8t7Snc/3F58fX0MbIjJ/ycXpY0aaKuOnufCuxf7wi1Xqw==",
245
+ "tarball_sha256": "0b551634f11742310ba3b6344fb7912ba1ed8ee0ef4702eab0099d31b4eeb070",
246
+ "status": "termux_verified"
184
247
  }
185
248
  }
186
249
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "manifest_version": 1,
3
3
  "package_name": "@bash0816/claude-code",
4
- "latest_audited_version": "2.1.157",
5
- "latest_candidate_version": "2.1.157",
6
- "previous_stable_version": "2.1.153-4",
4
+ "latest_audited_version": "2.1.159-13",
5
+ "latest_candidate_version": "2.1.159-13",
6
+ "previous_stable_version": "2.1.159-10",
7
7
  "manifest_url": "https://raw.githubusercontent.com/bash0816/ClaudeCode-Termux/main/config/claude-termux-release-manifest.json"
8
8
  }
@@ -10,6 +10,7 @@ const path = require('path');
10
10
  const packageDir = path.resolve(__dirname, '..');
11
11
  const pkg = require(path.join(packageDir, 'package.json'));
12
12
  const localManifest = require(path.join(packageDir, 'config', 'claude-termux-release-manifest.json'));
13
+ const { compareVersions } = require('./version-utils');
13
14
  const mode = process.argv[2] || 'notify';
14
15
  const currentVersion = process.argv[3] || pkg.version;
15
16
  const dryRun = process.argv.includes('--dry-run');
@@ -20,17 +21,6 @@ const ttlMs = Number(process.env.CLAUDE_TERMUX_UPDATE_CACHE_TTL_MS || String(24
20
21
  const skipCheck = process.env.CLAUDE_TERMUX_SKIP_UPDATE_CHECK === '1';
21
22
  const manifestUrl = process.env.CLAUDE_TERMUX_MANIFEST_URL || localManifest.manifest_url;
22
23
 
23
- function compareVersions(a, b) {
24
- const aParts = String(a).split('.').map(Number);
25
- const bParts = String(b).split('.').map(Number);
26
- const len = Math.max(aParts.length, bParts.length);
27
- for (let index = 0; index < len; index += 1) {
28
- const diff = (aParts[index] || 0) - (bParts[index] || 0);
29
- if (diff !== 0) return diff;
30
- }
31
- return 0;
32
- }
33
-
34
24
  function readCache() {
35
25
  try {
36
26
  return JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
@@ -6,7 +6,6 @@ WORKDIR="${WORKDIR:-${HOME}/.claude-termux-native-package/launcher-workdir}"
6
6
  ENTRY_JS_OFFSET="${ENTRY_JS_OFFSET:?ENTRY_JS_OFFSET is required}"
7
7
  ENTRY_END_OFFSET="${ENTRY_END_OFFSET:?ENTRY_END_OFFSET is required}"
8
8
  CURRENT_CLAUDE_VERSION="${CURRENT_CLAUDE_VERSION:?CURRENT_CLAUDE_VERSION is required}"
9
- CLAUDE_TERMUX_PACKAGE_DIR="${CLAUDE_TERMUX_PACKAGE_DIR:?CLAUDE_TERMUX_PACKAGE_DIR is required}"
10
9
  TERMUX_TMPDIR="${TMPDIR:-/data/data/com.termux/files/usr/tmp}"
11
10
  SSL_CERT_DIR="${SSL_CERT_DIR:-/data/data/com.termux/files/usr/etc/tls}"
12
11
  SSL_CERT_FILE="${SSL_CERT_FILE:-/data/data/com.termux/files/usr/etc/tls/cert.pem}"
@@ -39,31 +38,30 @@ export WORKDIR
39
38
  export ENTRY_JS_OFFSET
40
39
  export ENTRY_END_OFFSET
41
40
  export CURRENT_CLAUDE_VERSION
41
+ export CLAUDE_TERMUX_PACKAGE_DIR="${CLAUDE_TERMUX_PACKAGE_DIR:-}"
42
+ export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="${CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:-1}"
43
+ export ENABLE_CLAUDEAI_MCP_SERVERS="${ENABLE_CLAUDEAI_MCP_SERVERS:-0}"
42
44
 
43
- _pf=0
44
- for _a in "$@"; do
45
- case "$_a" in
46
- -p|--print) _pf=1; break ;;
47
- --) break ;;
48
- esac
49
- done
50
-
51
- if [ "$_pf" = "1" ] && [ "${CLAUDE_TERMUX_STDIN:-}" != "inherit" ]; then
52
- _helper=$(mktemp "${TMPDIR:-/tmp}/claude-helper.XXXXXX.js")
53
- trap 'rm -f "$_helper"' EXIT HUP INT TERM
54
- cat <<'NODE' > "$_helper"
45
+ node - "$@" <<'NODE'
55
46
  const fs = require('fs');
56
47
  const path = require('path');
57
- const {
58
- BLOCK_MESSAGE,
59
- createGuardedChildProcess,
60
- } = require(path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib', 'native-update-guard.js'));
61
48
 
62
49
  const sourceBin = process.env.SOURCE_BIN;
63
50
  const workdir = process.env.WORKDIR;
64
51
  const entryJsOffset = Number(process.env.ENTRY_JS_OFFSET);
65
52
  const entryEndOffset = Number(process.env.ENTRY_END_OFFSET);
66
53
  const argv = process.argv.slice(2);
54
+ const packageDir = process.env.CLAUDE_TERMUX_PACKAGE_DIR || "";
55
+ function loadNativeUpdateGuard() {
56
+ if (!packageDir) return null;
57
+ const guardPath = path.join(packageDir, 'lib', 'native-update-guard.js');
58
+ if (!fs.existsSync(guardPath)) return null;
59
+ try { return require(guardPath); } catch (e) {
60
+ process.stderr.write('[termux] native-update-guard load failed: ' + e.message + '\n');
61
+ return null;
62
+ }
63
+ }
64
+ const _nativeUpdateGuard = loadNativeUpdateGuard();
67
65
 
68
66
  class RequestedExit extends Error {
69
67
  constructor(code) {
@@ -100,207 +98,244 @@ function stringWidth(value) {
100
98
  return Array.from(text).length;
101
99
  }
102
100
 
103
- function createFakeRequire(realRequire) {
104
- const realChild = realRequire('child_process');
105
-
106
- function rewriteArgs(args) {
107
- if (
108
- Array.isArray(args) &&
109
- args[0] === 'xdg-open' &&
110
- Array.isArray(args[1]) &&
111
- typeof args[1][0] === 'string'
112
- ) {
113
- return ['termux-open-url', [args[1][0]], ...args.slice(2)];
114
- }
115
- return args;
116
- }
117
-
118
- const guardedChild = createGuardedChildProcess(
119
- {
120
- spawn: (...args) => realChild.spawn(...rewriteArgs(args)),
121
- execFile: (...args) => realChild.execFile(...args),
122
- exec: (...args) => realChild.exec(...args),
123
- spawnSync: (...args) => realChild.spawnSync(...rewriteArgs(args)),
124
- execFileSync: (...args) => realChild.execFileSync(...args),
125
- execSync: (...args) => realChild.execSync(...args),
126
- },
127
- value => process.stderr.write(value),
128
- );
129
-
130
- return function fakeRequire(id) {
131
- if (id === 'ws') {
132
- class WS {
133
- on() {}
134
- once() {}
135
- addEventListener() {}
136
- close() {}
137
- send() {}
138
- ping() {}
139
- }
140
- return { default: WS, WebSocket: WS };
141
- }
142
-
143
- if (id === 'child_process') {
144
- return guardedChild;
145
- }
101
+ function stripANSI(text) {
102
+ return String(text ?? '').replace(/\u001B\[[0-9;]*m/g, '');
103
+ }
146
104
 
147
- if (id === 'node:child_process') {
148
- return guardedChild;
105
+ function wrapAnsi(text, columns) {
106
+ const value = String(text ?? '');
107
+ const width = Number(columns);
108
+ if (!Number.isFinite(width) || width <= 0) return value;
109
+
110
+ let lineWidth = 0;
111
+ let result = '';
112
+ for (const ch of value) {
113
+ if (ch === '\n') {
114
+ result += ch;
115
+ lineWidth = 0;
116
+ continue;
149
117
  }
150
118
 
151
- if (id.startsWith('/$bunfs/root/')) {
152
- throw new Error('bunfs require blocked: ' + id);
119
+ const chWidth = stringWidth(ch);
120
+ if (lineWidth > 0 && lineWidth + chWidth > width) {
121
+ result += '\n';
122
+ lineWidth = 0;
153
123
  }
154
124
 
155
- return realRequire(id);
156
- };
125
+ result += ch;
126
+ lineWidth += chWidth;
127
+ }
128
+ return result;
157
129
  }
158
130
 
159
- async function main() {
160
- const extractedFile = ensureEntryFile();
161
- const code = fs.readFileSync(extractedFile, 'utf8');
162
- const fn = eval('(' + code);
131
+ function hash(value) {
132
+ const crypto = require('crypto');
133
+ const digest = crypto.createHash('sha256').update(String(value ?? '')).digest();
134
+ return digest.readUInt32LE(0);
135
+ }
163
136
 
164
- const originalArgv = process.argv.slice();
165
- const originalExit = process.exit;
166
- const originalBun = process.versions.bun;
167
- const hadGlobalBun = Object.prototype.hasOwnProperty.call(globalThis, 'Bun');
168
- const originalGlobalBun = globalThis.Bun;
169
- const asyncErrors = [];
137
+ function compareSemver(left, right) {
138
+ const a = String(left).replace(/^[^0-9]*/, '').split('.').map(Number);
139
+ const b = String(right).replace(/^[^0-9]*/, '').split('.').map(Number);
140
+ const size = Math.max(a.length, b.length);
141
+ for (let i = 0; i < size; i += 1) {
142
+ const diff = (a[i] || 0) - (b[i] || 0);
143
+ if (diff !== 0) return diff > 0 ? 1 : -1;
144
+ }
145
+ return 0;
146
+ }
170
147
 
171
- const fakeRequire = createFakeRequire(require);
172
- function onAsyncError(error) {
173
- asyncErrors.push(error);
148
+ function satisfiesSemver(version, range) {
149
+ const cleanRange = String(range ?? '').trim();
150
+ const match = cleanRange.match(/^([><=!]{1,2})\s*([0-9][^\s]*)$/);
151
+ if (!match) {
152
+ return /^[0-9]+(?:\.[0-9]+){0,2}$/.test(cleanRange)
153
+ ? compareSemver(version, cleanRange) === 0
154
+ : true;
174
155
  }
175
156
 
176
- try {
177
- process.once('uncaughtException', onAsyncError);
178
- process.once('unhandledRejection', onAsyncError);
179
- Object.defineProperty(process.versions, 'bun', { value: '1.1.8', configurable: true });
180
- globalThis.Bun = { version: '1.1.8', stringWidth };
181
- process.argv = ['node', extractedFile, ...argv];
182
- process.exit = code => {
183
- throw new RequestedExit(code);
184
- };
157
+ const [, op, target] = match;
158
+ const cmp = compareSemver(version, target);
159
+ if (op === '>') return cmp > 0;
160
+ if (op === '>=') return cmp >= 0;
161
+ if (op === '<') return cmp < 0;
162
+ if (op === '<=') return cmp <= 0;
163
+ if (op === '=' || op === '==') return cmp === 0;
164
+ if (op === '!=') return cmp !== 0;
165
+ return true;
166
+ }
185
167
 
186
- const moduleLike = { exports: {} };
187
- const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
188
- if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
189
- await new Promise(resolve => setTimeout(resolve, 200));
190
- if (asyncErrors.length > 0) throw asyncErrors[0];
191
- } catch (error) {
192
- if (error instanceof RequestedExit) {
193
- process.exitCode = error.code;
194
- return;
195
- }
196
- throw error;
197
- } finally {
198
- process.removeListener('uncaughtException', onAsyncError);
199
- process.removeListener('unhandledRejection', onAsyncError);
200
- process.argv = originalArgv;
201
- process.exit = originalExit;
202
- try {
203
- if (originalBun === undefined) {
204
- delete process.versions.bun;
205
- } else {
206
- Object.defineProperty(process.versions, 'bun', { value: originalBun, configurable: true });
207
- }
208
- } catch {}
209
- if (hadGlobalBun) globalThis.Bun = originalGlobalBun;
210
- else delete globalThis.Bun;
168
+ function createSemverShim() {
169
+ return {
170
+ order: compareSemver,
171
+ compare: compareSemver,
172
+ satisfies: satisfiesSemver,
173
+ gt: (left, right) => compareSemver(left, right) > 0,
174
+ gte: (left, right) => compareSemver(left, right) >= 0,
175
+ lt: (left, right) => compareSemver(left, right) < 0,
176
+ lte: (left, right) => compareSemver(left, right) <= 0,
177
+ };
178
+ }
179
+
180
+ function parseScalar(value) {
181
+ const text = String(value ?? '').trim();
182
+ if (text === '') return '';
183
+ if (text === 'true') return true;
184
+ if (text === 'false') return false;
185
+ if (text === 'null' || text === '~') return null;
186
+ if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(text)) return Number(text);
187
+ if (
188
+ (text.startsWith('"') && text.endsWith('"')) ||
189
+ (text.startsWith("'") && text.endsWith("'"))
190
+ ) {
191
+ return text.slice(1, -1);
211
192
  }
193
+ return text;
212
194
  }
213
195
 
214
- main().catch(error => {
215
- if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
216
- console.error(BLOCK_MESSAGE);
217
- process.exit(error.status || 1);
196
+ function parseInlineArray(value) {
197
+ const inner = String(value ?? '').trim().slice(1, -1).trim();
198
+ if (inner === '') return [];
199
+ const items = [];
200
+ let current = '';
201
+ let quote = null;
202
+
203
+ for (let i = 0; i < inner.length; i += 1) {
204
+ const ch = inner[i];
205
+ if (quote) {
206
+ if (ch === quote && inner[i - 1] !== '\\') quote = null;
207
+ current += ch;
208
+ continue;
209
+ }
210
+ if (ch === '"' || ch === "'") {
211
+ quote = ch;
212
+ current += ch;
213
+ continue;
214
+ }
215
+ if (ch === ',') {
216
+ items.push(parseScalar(current));
217
+ current = '';
218
+ continue;
219
+ }
220
+ current += ch;
218
221
  }
219
- console.error(error && error.stack ? error.stack : String(error));
220
- process.exit(1);
221
- });
222
- NODE
223
- node "$_helper" "$@" </dev/null
224
- _status=$?
225
- rm -f "$_helper"
226
- trap - EXIT HUP INT TERM
227
- exit "$_status"
228
- else
229
- exec node - "$@" <<'NODE'
230
- const fs = require('fs');
231
- const path = require('path');
232
- const {
233
- BLOCK_MESSAGE,
234
- createGuardedChildProcess,
235
- } = require(path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib', 'native-update-guard.js'));
236
222
 
237
- const sourceBin = process.env.SOURCE_BIN;
238
- const workdir = process.env.WORKDIR;
239
- const entryJsOffset = Number(process.env.ENTRY_JS_OFFSET);
240
- const entryEndOffset = Number(process.env.ENTRY_END_OFFSET);
241
- const argv = process.argv.slice(2);
223
+ if (current !== '') items.push(parseScalar(current));
224
+ return items;
225
+ }
242
226
 
243
- class RequestedExit extends Error {
244
- constructor(code) {
245
- super(`process.exit ${code}`);
246
- this.name = 'RequestedExit';
247
- this.code = code;
227
+ function yamlParse(text) {
228
+ const source = String(text ?? '');
229
+ const result = {};
230
+ for (const rawLine of source.split(/\r?\n/)) {
231
+ const line = rawLine.trim();
232
+ if (!line || line.startsWith('#')) continue;
233
+ const idx = line.indexOf(':');
234
+ if (idx < 0) continue;
235
+ const key = line.slice(0, idx).trim();
236
+ const rawValue = line.slice(idx + 1).trim();
237
+ if (!key) continue;
238
+ result[key] = rawValue.startsWith('[') && rawValue.endsWith(']')
239
+ ? parseInlineArray(rawValue)
240
+ : parseScalar(rawValue);
248
241
  }
242
+ return result;
249
243
  }
250
244
 
251
- function ensureEntryFile() {
252
- const extractedFile = path.join(workdir, `cli.${entryJsOffset}.${entryEndOffset}.bare-path.js`);
253
- if (fs.existsSync(extractedFile)) return extractedFile;
254
-
255
- const len = entryEndOffset - entryJsOffset;
256
- if (!(len > 0)) throw new Error('invalid replay offsets');
257
-
258
- const fd = fs.openSync(sourceBin, 'r');
259
- const buf = Buffer.alloc(len);
260
- fs.readSync(fd, buf, 0, len, entryJsOffset);
261
- fs.closeSync(fd);
262
-
263
- fs.writeFileSync(extractedFile, buf.toString('utf8').replace(/[\0\s]+$/g, ''));
264
- return extractedFile;
245
+ function yamlStringify(value) {
246
+ if (!value || typeof value !== 'object') return String(value ?? '');
247
+ const lines = [];
248
+ for (const [key, raw] of Object.entries(value)) {
249
+ if (Array.isArray(raw)) {
250
+ lines.push(`${key}: [${raw.map(item => JSON.stringify(String(item))).join(', ')}]`);
251
+ } else if (raw === null) {
252
+ lines.push(`${key}: null`);
253
+ } else if (typeof raw === 'string') {
254
+ lines.push(`${key}: ${JSON.stringify(raw)}`);
255
+ } else {
256
+ lines.push(`${key}: ${String(raw)}`);
257
+ }
258
+ }
259
+ return lines.join('\n');
265
260
  }
266
261
 
267
- function stringWidth(value) {
268
- const text = String(value ?? '');
269
- if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
270
- const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
271
- let width = 0;
272
- for (const _segment of segmenter.segment(text)) width += 1;
273
- return width;
274
- }
275
- return Array.from(text).length;
262
+ function createYamlShim() {
263
+ const yaml = {
264
+ parse: yamlParse,
265
+ stringify: yamlStringify,
266
+ };
267
+ yaml.YAML = yaml;
268
+ yaml.default = yaml;
269
+ return yaml;
276
270
  }
277
271
 
278
272
  function createFakeRequire(realRequire) {
279
273
  const realChild = realRequire('child_process');
280
-
274
+ const realVm = realRequire('vm');
281
275
  function rewriteArgs(args) {
282
- if (
283
- Array.isArray(args) &&
284
- args[0] === 'xdg-open' &&
285
- Array.isArray(args[1]) &&
286
- typeof args[1][0] === 'string'
287
- ) {
276
+ if (Array.isArray(args) && args[0] === 'xdg-open' && Array.isArray(args[1]) && typeof args[1][0] === 'string') {
288
277
  return ['termux-open-url', [args[1][0]], ...args.slice(2)];
289
278
  }
290
279
  return args;
291
280
  }
281
+ const _baseChild = {
282
+ spawn: (...args) => realChild.spawn(...rewriteArgs(args)),
283
+ execFile: (...args) => realChild.execFile(...args),
284
+ exec: (...args) => realChild.exec(...args),
285
+ spawnSync: (...args) => realChild.spawnSync(...rewriteArgs(args)),
286
+ execFileSync: (...args) => realChild.execFileSync(...args),
287
+ execSync: (...args) => realChild.execSync(...args),
288
+ };
289
+ const guardedChild = _nativeUpdateGuard
290
+ ? _nativeUpdateGuard.createGuardedChildProcess(_baseChild, v => process.stderr.write(v))
291
+ : _baseChild;
292
292
 
293
- const guardedChild = createGuardedChildProcess(
294
- {
295
- spawn: (...args) => realChild.spawn(...rewriteArgs(args)),
296
- execFile: (...args) => realChild.execFile(...args),
297
- exec: (...args) => realChild.exec(...args),
298
- spawnSync: (...args) => realChild.spawnSync(...rewriteArgs(args)),
299
- execFileSync: (...args) => realChild.execFileSync(...args),
300
- execSync: (...args) => realChild.execSync(...args),
301
- },
302
- value => process.stderr.write(value),
303
- );
293
+ function injectBunIntoContext(context) {
294
+ if (!context || typeof context !== 'object') return context;
295
+ try {
296
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeBunShim')) {
297
+ Object.defineProperty(context, '__claudeBunShim', {
298
+ value: globalThis.__claudeBunShim,
299
+ configurable: true,
300
+ writable: true,
301
+ });
302
+ }
303
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeYaml')) {
304
+ Object.defineProperty(context, '__claudeYaml', {
305
+ value: globalThis.__claudeYaml,
306
+ configurable: true,
307
+ writable: true,
308
+ });
309
+ }
310
+ if (Object.prototype.hasOwnProperty.call(context, 'Bun')) {
311
+ if (context.Bun && typeof context.Bun === 'object' && context.Bun !== globalThis.Bun) {
312
+ try {
313
+ context.Bun = globalThis.Bun;
314
+ } catch {
315
+ Object.defineProperty(context, 'Bun', {
316
+ value: globalThis.Bun,
317
+ configurable: true,
318
+ writable: true,
319
+ });
320
+ }
321
+ }
322
+ if (!context.Bun || typeof context.Bun !== 'object') {
323
+ Object.defineProperty(context, 'Bun', {
324
+ value: globalThis.Bun,
325
+ configurable: true,
326
+ writable: true,
327
+ });
328
+ }
329
+ } else {
330
+ Object.defineProperty(context, 'Bun', {
331
+ value: globalThis.Bun,
332
+ configurable: true,
333
+ writable: true,
334
+ });
335
+ }
336
+ } catch {}
337
+ return context;
338
+ }
304
339
 
305
340
  return function fakeRequire(id) {
306
341
  if (id === 'ws') {
@@ -315,6 +350,36 @@ function createFakeRequire(realRequire) {
315
350
  return { default: WS, WebSocket: WS };
316
351
  }
317
352
 
353
+ if (id === 'vm') {
354
+ if (!realVm.__bunShimPatched) {
355
+ const originalCreateContext = realVm.createContext.bind(realVm);
356
+ const originalRunInNewContext = realVm.runInNewContext.bind(realVm);
357
+ const ScriptProto = realVm.Script && realVm.Script.prototype;
358
+
359
+ realVm.createContext = (contextObject, ...rest) =>
360
+ originalCreateContext(injectBunIntoContext(contextObject), ...rest);
361
+ realVm.runInNewContext = (code, contextObject, ...rest) =>
362
+ originalRunInNewContext(code, injectBunIntoContext(contextObject), ...rest);
363
+
364
+ if (ScriptProto && !ScriptProto.__bunShimPatched) {
365
+ const originalRunInContext = ScriptProto.runInContext;
366
+ const originalRunInNewContext = ScriptProto.runInNewContext;
367
+
368
+ ScriptProto.runInContext = function (contextObject, ...rest) {
369
+ return originalRunInContext.call(this, injectBunIntoContext(contextObject), ...rest);
370
+ };
371
+ ScriptProto.runInNewContext = function (contextObject, ...rest) {
372
+ return originalRunInNewContext.call(this, injectBunIntoContext(contextObject), ...rest);
373
+ };
374
+
375
+ Object.defineProperty(ScriptProto, '__bunShimPatched', { value: true });
376
+ }
377
+
378
+ Object.defineProperty(realVm, '__bunShimPatched', { value: true });
379
+ }
380
+ return realVm;
381
+ }
382
+
318
383
  if (id === 'child_process') {
319
384
  return guardedChild;
320
385
  }
@@ -323,6 +388,14 @@ function createFakeRequire(realRequire) {
323
388
  return guardedChild;
324
389
  }
325
390
 
391
+ if (id === 'yaml' || id === 'yamljs' || id === 'js-yaml') {
392
+ return createYamlShim();
393
+ }
394
+
395
+ if (id === 'vm' || id === 'node:vm') {
396
+ return realVm;
397
+ }
398
+
326
399
  if (id.startsWith('/$bunfs/root/')) {
327
400
  throw new Error('bunfs require blocked: ' + id);
328
401
  }
@@ -332,8 +405,31 @@ function createFakeRequire(realRequire) {
332
405
  }
333
406
 
334
407
  async function main() {
408
+ let bunShim;
335
409
  const extractedFile = ensureEntryFile();
336
- const code = fs.readFileSync(extractedFile, 'utf8');
410
+ let code = fs.readFileSync(extractedFile, 'utf8');
411
+ globalThis.__claudeYaml = createYamlShim();
412
+ if (!globalThis.__claudeBunShim || typeof globalThis.__claudeBunShim !== 'object') {
413
+ globalThis.__claudeBunShim = {};
414
+ }
415
+ code = code.replace(
416
+ /^function\(exports, require, module, __filename, __dirname\) \{/,
417
+ 'function(exports, require, module, __filename, __dirname) {var __claudeBun = globalThis.__claudeBunShim;',
418
+ );
419
+ const patchedCode = code.replace(
420
+ /\btypeof Bun\b/g,
421
+ 'typeof __claudeBun',
422
+ ).replace(
423
+ /\bBun\./g,
424
+ '__claudeBun.',
425
+ ).replace(
426
+ /function t5q\(q\)\{return Bun\.YAML\.parse\(q\)\}/g,
427
+ 'function t5q(q){return globalThis.__claudeYaml.parse(q)}',
428
+ ).replace(
429
+ /function VK6\(q\)\{return Bun\.YAML\.stringify\(q,null,2\)\+`/g,
430
+ 'function VK6(q){return globalThis.__claudeYaml.stringify(q,null,2)+`',
431
+ );
432
+ code = patchedCode;
337
433
  const fn = eval('(' + code);
338
434
 
339
435
  const originalArgv = process.argv.slice();
@@ -352,7 +448,26 @@ async function main() {
352
448
  process.once('uncaughtException', onAsyncError);
353
449
  process.once('unhandledRejection', onAsyncError);
354
450
  Object.defineProperty(process.versions, 'bun', { value: '1.1.8', configurable: true });
355
- globalThis.Bun = { version: '1.1.8', stringWidth };
451
+ globalThis.Bun = {
452
+ version: '1.1.8',
453
+ gc: () => {},
454
+ hash,
455
+ stripANSI,
456
+ YAML: createYamlShim(),
457
+ stringWidth,
458
+ which: cmd => {
459
+ try {
460
+ return require('child_process').execFileSync('which', [String(cmd)], { encoding: 'utf8' }).trim() || null;
461
+ } catch {
462
+ return null;
463
+ }
464
+ },
465
+ wrapAnsi,
466
+ semver: createSemverShim(),
467
+ };
468
+ Object.assign(globalThis.__claudeBunShim, globalThis.Bun);
469
+ globalThis.Bun = globalThis.__claudeBunShim;
470
+ bunShim = globalThis.Bun;
356
471
  process.argv = ['node', extractedFile, ...argv];
357
472
  process.exit = code => {
358
473
  throw new RequestedExit(code);
@@ -361,9 +476,14 @@ async function main() {
361
476
  const moduleLike = { exports: {} };
362
477
  const maybePromise = fn(moduleLike.exports, fakeRequire, moduleLike, extractedFile, workdir);
363
478
  if (maybePromise && typeof maybePromise.then === 'function') await maybePromise;
364
- await new Promise(resolve => setTimeout(resolve, 200));
479
+ await new Promise(resolve => setTimeout(resolve, Number(process.env.CLAUDE_TERMUX_PRINT_WAIT_MS || 1000)));
365
480
  if (asyncErrors.length > 0) throw asyncErrors[0];
366
481
  } catch (error) {
482
+ if (_nativeUpdateGuard && error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
483
+ console.error(_nativeUpdateGuard.BLOCK_MESSAGE);
484
+ process.exitCode = error.status || 1;
485
+ return;
486
+ }
367
487
  if (error instanceof RequestedExit) {
368
488
  process.exitCode = error.code;
369
489
  return;
@@ -381,18 +501,15 @@ async function main() {
381
501
  Object.defineProperty(process.versions, 'bun', { value: originalBun, configurable: true });
382
502
  }
383
503
  } catch {}
504
+ delete globalThis.__claudeYaml;
505
+ delete globalThis.__claudeBunShim;
506
+ delete globalThis.Bun;
384
507
  if (hadGlobalBun) globalThis.Bun = originalGlobalBun;
385
- else delete globalThis.Bun;
386
508
  }
387
509
  }
388
510
 
389
511
  main().catch(error => {
390
- if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
391
- console.error(BLOCK_MESSAGE);
392
- process.exit(error.status || 1);
393
- }
394
512
  console.error(error && error.stack ? error.stack : String(error));
395
513
  process.exit(1);
396
514
  });
397
515
  NODE
398
- fi
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ function parseVersion(v) {
4
+ const str = String(v);
5
+ const dashIdx = str.lastIndexOf('-');
6
+ if (dashIdx !== -1) {
7
+ const base = str.slice(0, dashIdx);
8
+ const suffix = Number(str.slice(dashIdx + 1));
9
+ return { parts: base.split('.').map(Number), suffix: isNaN(suffix) ? 0 : suffix };
10
+ }
11
+ return { parts: str.split('.').map(Number), suffix: 0 };
12
+ }
13
+
14
+ function compareVersions(a, b) {
15
+ const ap = parseVersion(a), bp = parseVersion(b);
16
+ const len = Math.max(ap.parts.length, bp.parts.length);
17
+ for (let i = 0; i < len; i++) {
18
+ const diff = (ap.parts[i] || 0) - (bp.parts[i] || 0);
19
+ if (diff !== 0) return diff;
20
+ }
21
+ return ap.suffix - bp.suffix;
22
+ }
23
+
24
+ module.exports = { parseVersion, compareVersions };
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const test = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+
6
+ const { parseVersion, compareVersions } = require('./version-utils');
7
+
8
+ test('parseVersion splits suffix versions', () => {
9
+ assert.deepEqual(parseVersion('2.1.159-2'), {
10
+ parts: [2, 1, 159],
11
+ suffix: 2,
12
+ });
13
+ });
14
+
15
+ test('compareVersions orders suffix versions after the base release', () => {
16
+ assert.equal(compareVersions('2.1.159', '2.1.159-1') < 0, true);
17
+ assert.equal(compareVersions('2.1.159-1', '2.1.159-2') < 0, true);
18
+ assert.equal(compareVersions('2.1.159-2', '2.1.159') > 0, true);
19
+ });
20
+
21
+ test('compareVersions preserves numeric ordering across patch versions', () => {
22
+ assert.equal(compareVersions('2.1.136', '2.1.137') < 0, true);
23
+ assert.equal(compareVersions('2.1.137', '2.1.136') > 0, true);
24
+ assert.equal(compareVersions('2.1.137', '2.1.137'), 0);
25
+ });
package/package.json CHANGED
@@ -1,22 +1,28 @@
1
1
  {
2
2
  "name": "@bash0816/claude-code",
3
- "version": "2.1.159-1",
4
- "description": "Termux-native Claude Code wrapper with audited native replay",
3
+ "version": "2.1.159-13",
4
+ "description": "Unofficial Termux-native Claude Code wrapper with audited native replay",
5
5
  "license": "MIT",
6
6
  "bin": {
7
7
  "claude": "bin/claude"
8
8
  },
9
- "scripts": {
10
- "preinstall": "node lib/preinstall.js",
11
- "postinstall": "node lib/postinstall.js"
12
- },
9
+ "scripts": {},
13
10
  "files": [
14
- "bin",
15
- "lib",
16
- "config",
11
+ "bin/",
12
+ "lib/",
13
+ "config/",
17
14
  "README.md"
18
15
  ],
19
16
  "engines": {
20
17
  "node": ">=18"
18
+ },
19
+ "keywords": [
20
+ "claude-code",
21
+ "termux",
22
+ "android",
23
+ "wrapper"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
21
27
  }
22
28
  }