@bash0816/claude-code 2.1.150 → 2.1.153-2
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 +23 -32
- package/bin/claude +2 -2
- package/config/claude-native-audited-versions.json +42 -0
- package/config/claude-termux-release-manifest.json +8 -3
- package/lib/check-updates.js +94 -15
- package/lib/postinstall.js +2 -1
- package/lib/preinstall.js +6 -0
- package/lib/prepare-native.js +9 -51
- package/lib/termux-run-claude-native.sh +321 -39
- package/package.json +2 -2
- package/lib/native-update-guard.js +0 -257
- package/lib/native-update-guard.test.js +0 -310
|
@@ -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}"
|
|
@@ -43,10 +42,6 @@ export CURRENT_CLAUDE_VERSION
|
|
|
43
42
|
node - "$@" <<'NODE'
|
|
44
43
|
const fs = require('fs');
|
|
45
44
|
const path = require('path');
|
|
46
|
-
const {
|
|
47
|
-
BLOCK_MESSAGE,
|
|
48
|
-
createGuardedChildProcess,
|
|
49
|
-
} = require(path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib', 'native-update-guard.js'));
|
|
50
45
|
|
|
51
46
|
const sourceBin = process.env.SOURCE_BIN;
|
|
52
47
|
const workdir = process.env.WORKDIR;
|
|
@@ -78,20 +73,8 @@ function ensureEntryFile() {
|
|
|
78
73
|
return extractedFile;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
|
-
function stringWidth(value) {
|
|
82
|
-
const text = String(value ?? '');
|
|
83
|
-
if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
|
|
84
|
-
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
|
|
85
|
-
let width = 0;
|
|
86
|
-
for (const _segment of segmenter.segment(text)) width += 1;
|
|
87
|
-
return width;
|
|
88
|
-
}
|
|
89
|
-
return Array.from(text).length;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
76
|
function createFakeRequire(realRequire) {
|
|
93
77
|
const realChild = realRequire('child_process');
|
|
94
|
-
|
|
95
78
|
function rewriteArgs(args) {
|
|
96
79
|
if (
|
|
97
80
|
Array.isArray(args) &&
|
|
@@ -104,18 +87,6 @@ function createFakeRequire(realRequire) {
|
|
|
104
87
|
return args;
|
|
105
88
|
}
|
|
106
89
|
|
|
107
|
-
const guardedChild = createGuardedChildProcess(
|
|
108
|
-
{
|
|
109
|
-
spawn: (...args) => realChild.spawn(...rewriteArgs(args)),
|
|
110
|
-
execFile: (...args) => realChild.execFile(...args),
|
|
111
|
-
exec: (...args) => realChild.exec(...args),
|
|
112
|
-
spawnSync: (...args) => realChild.spawnSync(...rewriteArgs(args)),
|
|
113
|
-
execFileSync: (...args) => realChild.execFileSync(...args),
|
|
114
|
-
execSync: (...args) => realChild.execSync(...args),
|
|
115
|
-
},
|
|
116
|
-
value => process.stderr.write(value),
|
|
117
|
-
);
|
|
118
|
-
|
|
119
90
|
return function fakeRequire(id) {
|
|
120
91
|
if (id === 'ws') {
|
|
121
92
|
class WS {
|
|
@@ -130,11 +101,14 @@ function createFakeRequire(realRequire) {
|
|
|
130
101
|
}
|
|
131
102
|
|
|
132
103
|
if (id === 'child_process') {
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
104
|
+
return {
|
|
105
|
+
spawn: (...args) => realChild.spawn(...rewriteArgs(args)),
|
|
106
|
+
execFile: (...args) => realChild.execFile(...args),
|
|
107
|
+
exec: (...args) => realChild.exec(...args),
|
|
108
|
+
spawnSync: (...args) => realChild.spawnSync(...rewriteArgs(args)),
|
|
109
|
+
execFileSync: (...args) => realChild.execFileSync(...args),
|
|
110
|
+
execSync: (...args) => realChild.execSync(...args),
|
|
111
|
+
};
|
|
138
112
|
}
|
|
139
113
|
|
|
140
114
|
if (id.startsWith('/$bunfs/root/')) {
|
|
@@ -145,6 +119,318 @@ function createFakeRequire(realRequire) {
|
|
|
145
119
|
};
|
|
146
120
|
}
|
|
147
121
|
|
|
122
|
+
function createBunShim() {
|
|
123
|
+
const childProcess = require('child_process');
|
|
124
|
+
const crypto = require('crypto');
|
|
125
|
+
const net = require('net');
|
|
126
|
+
const os = require('os');
|
|
127
|
+
const ansiPattern =
|
|
128
|
+
/[\u001B\u009B][[\]()#;?]*(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?(?:\u0007|\u001B\u005C|\u009C)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g;
|
|
129
|
+
|
|
130
|
+
function stripANSI(value) {
|
|
131
|
+
if (typeof value !== 'string' || value.length === 0) return '';
|
|
132
|
+
return value.replace(ansiPattern, '');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isZeroWidth(codePoint) {
|
|
136
|
+
return (
|
|
137
|
+
codePoint <= 0x1f ||
|
|
138
|
+
(codePoint >= 0x7f && codePoint <= 0x9f) ||
|
|
139
|
+
(codePoint >= 0x300 && codePoint <= 0x36f) ||
|
|
140
|
+
(codePoint >= 0x200b && codePoint <= 0x200f) ||
|
|
141
|
+
codePoint === 0xfeff ||
|
|
142
|
+
(codePoint >= 0xfe00 && codePoint <= 0xfe0f)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function isWide(codePoint) {
|
|
147
|
+
return (
|
|
148
|
+
(codePoint >= 0x1100 && codePoint <= 0x115f) ||
|
|
149
|
+
(codePoint >= 0x2329 && codePoint <= 0x232a) ||
|
|
150
|
+
(codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
|
|
151
|
+
(codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
|
|
152
|
+
(codePoint >= 0xf900 && codePoint <= 0xfaff) ||
|
|
153
|
+
(codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
|
|
154
|
+
(codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
|
|
155
|
+
(codePoint >= 0xff00 && codePoint <= 0xff60) ||
|
|
156
|
+
(codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
|
|
157
|
+
(codePoint >= 0x1f300 && codePoint <= 0x1faf8) ||
|
|
158
|
+
(codePoint >= 0x20000 && codePoint <= 0x3fffd)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function stringWidth(value) {
|
|
163
|
+
const text = stripANSI(typeof value === 'string' ? value : String(value ?? ''));
|
|
164
|
+
let width = 0;
|
|
165
|
+
for (const char of text) {
|
|
166
|
+
const codePoint = char.codePointAt(0);
|
|
167
|
+
if (isZeroWidth(codePoint)) continue;
|
|
168
|
+
width += isWide(codePoint) ? 2 : 1;
|
|
169
|
+
}
|
|
170
|
+
return width;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function normalizeInput(value) {
|
|
174
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array) return Buffer.from(value);
|
|
175
|
+
if (typeof value === 'string') return Buffer.from(value);
|
|
176
|
+
return Buffer.from(String(value ?? ''));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function hash(value) {
|
|
180
|
+
const digest = crypto.createHash('sha256').update(normalizeInput(value)).digest();
|
|
181
|
+
return digest.readUInt32LE(0);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function which(command) {
|
|
185
|
+
if (typeof command !== 'string' || command.length === 0) return null;
|
|
186
|
+
const pathValue = process.env.PATH || '';
|
|
187
|
+
const separator = os.platform() === 'win32' ? ';' : ':';
|
|
188
|
+
for (const entry of pathValue.split(separator)) {
|
|
189
|
+
if (!entry) continue;
|
|
190
|
+
const candidate = path.join(entry, command);
|
|
191
|
+
try {
|
|
192
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
193
|
+
return candidate;
|
|
194
|
+
} catch {}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function spawn(argv, options = {}) {
|
|
200
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
201
|
+
throw new TypeError('Bun.spawn expects a non-empty argv array');
|
|
202
|
+
}
|
|
203
|
+
const [command, ...args] = argv;
|
|
204
|
+
const terminal = options.terminal || null;
|
|
205
|
+
|
|
206
|
+
function resolveStdio(val, fallback) {
|
|
207
|
+
if (val === 'ignore' || val === 'inherit' || val === 'pipe') return val;
|
|
208
|
+
return fallback;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let stdioSpec;
|
|
212
|
+
if (terminal) {
|
|
213
|
+
stdioSpec = ['pipe', 'pipe', 'pipe'];
|
|
214
|
+
} else if (Array.isArray(options.stdio)) {
|
|
215
|
+
stdioSpec = options.stdio.map(s => resolveStdio(s, 'pipe'));
|
|
216
|
+
} else {
|
|
217
|
+
stdioSpec = [
|
|
218
|
+
resolveStdio(options.stdin, 'pipe'),
|
|
219
|
+
resolveStdio(options.stdout, 'pipe'),
|
|
220
|
+
resolveStdio(options.stderr, 'pipe'),
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const nodeChild = childProcess.spawn(command, args, {
|
|
225
|
+
cwd: options.cwd,
|
|
226
|
+
env: options.env || process.env,
|
|
227
|
+
detached: options.detached,
|
|
228
|
+
windowsHide: options.windowsHide,
|
|
229
|
+
stdio: stdioSpec,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (terminal) {
|
|
233
|
+
const fireData = chunk => {
|
|
234
|
+
if (!terminal._closed && terminal._options && typeof terminal._options.data === 'function') {
|
|
235
|
+
terminal._options.data(terminal, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
nodeChild.stdout?.on('data', fireData);
|
|
239
|
+
nodeChild.stderr?.on('data', fireData);
|
|
240
|
+
const origWrite = terminal.write.bind(terminal);
|
|
241
|
+
terminal.write = data => {
|
|
242
|
+
if (nodeChild.stdin && !nodeChild.stdin.destroyed) {
|
|
243
|
+
nodeChild.stdin.write(Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
244
|
+
}
|
|
245
|
+
return origWrite(data);
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
nodeChild.exited = new Promise(resolve => {
|
|
250
|
+
nodeChild.once('exit', (code, signal) => resolve(code != null ? code : (signal ? 1 : 0)));
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
function makeTextReader(stream) {
|
|
254
|
+
return {
|
|
255
|
+
text() {
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
if (!stream) return resolve('');
|
|
258
|
+
const chunks = [];
|
|
259
|
+
stream.on('data', chunk => chunks.push(chunk));
|
|
260
|
+
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
261
|
+
stream.on('error', reject);
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
if (nodeChild.stdout) Object.assign(nodeChild.stdout, makeTextReader(nodeChild.stdout));
|
|
267
|
+
if (nodeChild.stderr) Object.assign(nodeChild.stderr, makeTextReader(nodeChild.stderr));
|
|
268
|
+
return nodeChild;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
class TerminalShim {
|
|
272
|
+
constructor(options = {}) {
|
|
273
|
+
this._options = options;
|
|
274
|
+
this._cols = options.cols || 80;
|
|
275
|
+
this._rows = options.rows || 24;
|
|
276
|
+
this._closed = false;
|
|
277
|
+
}
|
|
278
|
+
write(data) {
|
|
279
|
+
if (this._closed) return;
|
|
280
|
+
if (this._options.data) this._options.data(this, Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
281
|
+
}
|
|
282
|
+
resize(cols, rows) {
|
|
283
|
+
this._cols = cols;
|
|
284
|
+
this._rows = rows;
|
|
285
|
+
}
|
|
286
|
+
close() {
|
|
287
|
+
this._closed = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function listen(options) {
|
|
292
|
+
const sockets = new Set();
|
|
293
|
+
const server = net.createServer(socket => {
|
|
294
|
+
sockets.add(socket);
|
|
295
|
+
const connection = {
|
|
296
|
+
data: undefined,
|
|
297
|
+
write(chunk) {
|
|
298
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
299
|
+
const ok = socket.write(buffer);
|
|
300
|
+
return ok ? buffer.length : 0;
|
|
301
|
+
},
|
|
302
|
+
end(chunk) {
|
|
303
|
+
socket.end(chunk);
|
|
304
|
+
},
|
|
305
|
+
destroy(error) {
|
|
306
|
+
socket.destroy(error);
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
socket.on('data', chunk => {
|
|
310
|
+
if (options.socket && typeof options.socket.data === 'function') {
|
|
311
|
+
options.socket.data(connection, chunk);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
socket.on('drain', () => {
|
|
315
|
+
if (options.socket && typeof options.socket.drain === 'function') {
|
|
316
|
+
options.socket.drain(connection);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
socket.on('close', () => {
|
|
320
|
+
sockets.delete(socket);
|
|
321
|
+
if (options.socket && typeof options.socket.close === 'function') {
|
|
322
|
+
options.socket.close(connection);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
socket.on('error', error => {
|
|
326
|
+
if (options.socket && typeof options.socket.error === 'function') {
|
|
327
|
+
options.socket.error(connection, error);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
if (options.socket && typeof options.socket.open === 'function') {
|
|
331
|
+
options.socket.open(connection);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
server.listen(options.port || 0, options.hostname || '127.0.0.1');
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
get port() {
|
|
339
|
+
const address = server.address();
|
|
340
|
+
return address && typeof address === 'object' ? address.port : 0;
|
|
341
|
+
},
|
|
342
|
+
stop(closeConnections) {
|
|
343
|
+
server.close();
|
|
344
|
+
if (closeConnections) {
|
|
345
|
+
for (const socket of sockets) socket.destroy();
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const semver = {
|
|
352
|
+
order(left, right) {
|
|
353
|
+
const leftParts = String(left).replace(/^[^0-9]*/, '').split('.').map(Number);
|
|
354
|
+
const rightParts = String(right).replace(/^[^0-9]*/, '').split('.').map(Number);
|
|
355
|
+
const size = Math.max(leftParts.length, rightParts.length);
|
|
356
|
+
for (let index = 0; index < size; index += 1) {
|
|
357
|
+
const diff = (leftParts[index] || 0) - (rightParts[index] || 0);
|
|
358
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
359
|
+
}
|
|
360
|
+
return 0;
|
|
361
|
+
},
|
|
362
|
+
satisfies(version, range) {
|
|
363
|
+
const v = String(version).replace(/^[^0-9]*/, '');
|
|
364
|
+
const clean = String(range).trim();
|
|
365
|
+
const match = clean.match(/^([><=!^~]+)\s*([0-9][^\s]*)/);
|
|
366
|
+
if (!match) return true;
|
|
367
|
+
const [, op, rv] = match;
|
|
368
|
+
const cmp = semver.order(v, rv);
|
|
369
|
+
if (op === '>=' || op === '=>') return cmp >= 0;
|
|
370
|
+
if (op === '>') return cmp > 0;
|
|
371
|
+
if (op === '<=' || op === '=<') return cmp <= 0;
|
|
372
|
+
if (op === '<') return cmp < 0;
|
|
373
|
+
if (op === '==' || op === '=') return cmp === 0;
|
|
374
|
+
if (op === '!=') return cmp !== 0;
|
|
375
|
+
return true;
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const YAML = {
|
|
380
|
+
parse(text) {
|
|
381
|
+
try {
|
|
382
|
+
const lines = String(text).split('\n');
|
|
383
|
+
const result = {};
|
|
384
|
+
for (const line of lines) {
|
|
385
|
+
const m = line.match(/^([^:#]+):\s*(.*)$/);
|
|
386
|
+
if (m) result[m[1].trim()] = m[2].trim().replace(/^["']|["']$/g, '');
|
|
387
|
+
}
|
|
388
|
+
return result;
|
|
389
|
+
} catch { return {}; }
|
|
390
|
+
},
|
|
391
|
+
stringify(obj) {
|
|
392
|
+
try {
|
|
393
|
+
return Object.entries(obj || {}).map(([k, v]) => `${k}: ${v}`).join('\n') + '\n';
|
|
394
|
+
} catch { return ''; }
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
class Transpiler {
|
|
399
|
+
constructor(_options) {}
|
|
400
|
+
transformSync(code) { return typeof code === 'string' ? code : ''; }
|
|
401
|
+
scanImports(code) {
|
|
402
|
+
const imports = [];
|
|
403
|
+
const reStatic = /(?:^|[^.])import\s+(?:[^'"]+\s+from\s+)?['"]([^'"]+)['"]/gm;
|
|
404
|
+
const reDynamic = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
405
|
+
const reRequire = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
406
|
+
let m;
|
|
407
|
+
while ((m = reStatic.exec(String(code))) !== null) imports.push({ path: m[1], kind: 'import-statement' });
|
|
408
|
+
while ((m = reDynamic.exec(String(code))) !== null) imports.push({ path: m[1], kind: 'dynamic-import' });
|
|
409
|
+
while ((m = reRequire.exec(String(code))) !== null) imports.push({ path: m[1], kind: 'require-call' });
|
|
410
|
+
return imports;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
version: '1.1.8',
|
|
416
|
+
embeddedFiles: [],
|
|
417
|
+
gc: typeof global.gc === 'function' ? () => global.gc() : () => {},
|
|
418
|
+
generateHeapSnapshot: () => Buffer.alloc(0),
|
|
419
|
+
hash,
|
|
420
|
+
listen,
|
|
421
|
+
semver,
|
|
422
|
+
spawn,
|
|
423
|
+
stdin: process.stdin,
|
|
424
|
+
stripANSI,
|
|
425
|
+
stringWidth,
|
|
426
|
+
Terminal: TerminalShim,
|
|
427
|
+
Transpiler,
|
|
428
|
+
which,
|
|
429
|
+
wrapAnsi: value => String(value ?? ''),
|
|
430
|
+
YAML,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
148
434
|
async function main() {
|
|
149
435
|
const extractedFile = ensureEntryFile();
|
|
150
436
|
const code = fs.readFileSync(extractedFile, 'utf8');
|
|
@@ -166,7 +452,7 @@ async function main() {
|
|
|
166
452
|
process.once('uncaughtException', onAsyncError);
|
|
167
453
|
process.once('unhandledRejection', onAsyncError);
|
|
168
454
|
Object.defineProperty(process.versions, 'bun', { value: '1.1.8', configurable: true });
|
|
169
|
-
globalThis.Bun =
|
|
455
|
+
globalThis.Bun = createBunShim();
|
|
170
456
|
process.argv = ['node', extractedFile, ...argv];
|
|
171
457
|
process.exit = code => {
|
|
172
458
|
throw new RequestedExit(code);
|
|
@@ -201,10 +487,6 @@ async function main() {
|
|
|
201
487
|
}
|
|
202
488
|
|
|
203
489
|
main().catch(error => {
|
|
204
|
-
if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
|
|
205
|
-
console.error(BLOCK_MESSAGE);
|
|
206
|
-
process.exit(error.status || 1);
|
|
207
|
-
}
|
|
208
490
|
console.error(error && error.stack ? error.stack : String(error));
|
|
209
491
|
process.exit(1);
|
|
210
492
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bash0816/claude-code",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.153-2",
|
|
4
4
|
"description": "Termux-native Claude Code wrapper with audited native replay",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=20"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const EventEmitter = require('events');
|
|
5
|
-
|
|
6
|
-
const OFFICIAL_PACKAGE = '@anthropic-ai/claude-code';
|
|
7
|
-
const BLOCK_MESSAGE = [
|
|
8
|
-
'Official native self-update is disabled on Termux.',
|
|
9
|
-
'Run: claude update',
|
|
10
|
-
].join('\n');
|
|
11
|
-
|
|
12
|
-
function lastPathSegment(value) {
|
|
13
|
-
return String(value || '').replace(/\\/g, '/').split('/').pop();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function isNpmCommand(command) {
|
|
17
|
-
const text = String(command || '');
|
|
18
|
-
const leaf = lastPathSegment(text);
|
|
19
|
-
return leaf === 'npm' || leaf === 'npm-cli.js';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function isPnpmCommand(command) {
|
|
23
|
-
return lastPathSegment(command) === 'pnpm';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function isYarnCommand(command) {
|
|
27
|
-
const leaf = lastPathSegment(command);
|
|
28
|
-
return leaf === 'yarn' || leaf === 'yarnpkg';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function isNpxCommand(command) {
|
|
32
|
-
const leaf = lastPathSegment(command);
|
|
33
|
-
return leaf === 'npx' || leaf === 'pnpx';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function isEnvCommand(command) {
|
|
37
|
-
return lastPathSegment(command) === 'env';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isCorepackCommand(command) {
|
|
41
|
-
return lastPathSegment(command) === 'corepack';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function isShellCommand(command) {
|
|
45
|
-
const leaf = lastPathSegment(command);
|
|
46
|
-
return leaf === 'sh' || leaf === 'bash';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function isSupportedOperation(value) {
|
|
50
|
-
return ['install', 'i', 'add', 'update', 'up', 'upgrade'].includes(String(value || ''));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function isOfficialTarget(value) {
|
|
54
|
-
return String(value || '') === OFFICIAL_PACKAGE || String(value || '').startsWith(`${OFFICIAL_PACKAGE}@`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function normalizeCommand(command, args) {
|
|
58
|
-
let normalizedCommand = command;
|
|
59
|
-
let normalizedArgs = Array.isArray(args) ? args.slice() : [];
|
|
60
|
-
|
|
61
|
-
if (isEnvCommand(normalizedCommand)) {
|
|
62
|
-
while (normalizedArgs.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(String(normalizedArgs[0]))) {
|
|
63
|
-
normalizedArgs.shift();
|
|
64
|
-
}
|
|
65
|
-
if (normalizedArgs.length === 0) return { command: normalizedCommand, args: normalizedArgs };
|
|
66
|
-
normalizedCommand = normalizedArgs.shift();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (isCorepackCommand(normalizedCommand)) {
|
|
70
|
-
if (normalizedArgs.length === 0) return { command: normalizedCommand, args: normalizedArgs };
|
|
71
|
-
normalizedCommand = normalizedArgs.shift();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return { command: normalizedCommand, args: normalizedArgs };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function hasOfficialTarget(args) {
|
|
78
|
-
return args.some(isOfficialTarget);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function shouldBlockNpmLike(command, args) {
|
|
82
|
-
if (!(isNpmCommand(command) || isPnpmCommand(command))) return false;
|
|
83
|
-
if (!args.find(isSupportedOperation)) return false;
|
|
84
|
-
return hasOfficialTarget(args);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function shouldBlockYarn(command, args) {
|
|
88
|
-
if (!isYarnCommand(command)) return false;
|
|
89
|
-
return String(args[0] || '') === 'global' && String(args[1] || '') === 'add' && hasOfficialTarget(args.slice(2));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function shouldBlockNpx(command, args) {
|
|
93
|
-
if (!isNpxCommand(command)) return false;
|
|
94
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
95
|
-
const token = String(args[index] || '');
|
|
96
|
-
if (token === '-p' || token === '--package') {
|
|
97
|
-
if (isOfficialTarget(args[index + 1])) return true;
|
|
98
|
-
index += 1;
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (token.startsWith('--package=')) {
|
|
102
|
-
if (isOfficialTarget(token.slice('--package='.length))) return true;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (!token.startsWith('-')) {
|
|
106
|
-
return isOfficialTarget(token);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function shouldBlockCommand(command, args) {
|
|
113
|
-
if (!Array.isArray(args)) return false;
|
|
114
|
-
const normalized = normalizeCommand(command, args);
|
|
115
|
-
return (
|
|
116
|
-
shouldBlockNpmLike(normalized.command, normalized.args) ||
|
|
117
|
-
shouldBlockYarn(normalized.command, normalized.args) ||
|
|
118
|
-
shouldBlockNpx(normalized.command, normalized.args)
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function normalizeTokensForExec(tokens) {
|
|
123
|
-
if (tokens.length === 0) return tokens;
|
|
124
|
-
const normalized = normalizeCommand(tokens[0], tokens.slice(1));
|
|
125
|
-
return [normalized.command, ...normalized.args].filter(value => value !== undefined);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function unwrapShellCommand(command, args) {
|
|
129
|
-
if (!isShellCommand(command) || !Array.isArray(args) || args.length < 2) return null;
|
|
130
|
-
const first = String(args[0] || '');
|
|
131
|
-
const second = String(args[1] || '');
|
|
132
|
-
if ((first === '-c' || first === '-lc') && second) return second;
|
|
133
|
-
if (first === '-l' && String(args[1] || '') === '-c' && String(args[2] || '')) return String(args[2]);
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function tokenizeShellString(command) {
|
|
138
|
-
const text = String(command || '').trim();
|
|
139
|
-
if (!text) return [];
|
|
140
|
-
return text.match(/(?:[^\s'"]+|'[^']*'|"[^"]*")+/g) || [];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function unquote(token) {
|
|
144
|
-
if (
|
|
145
|
-
(token.startsWith('"') && token.endsWith('"')) ||
|
|
146
|
-
(token.startsWith("'") && token.endsWith("'"))
|
|
147
|
-
) {
|
|
148
|
-
return token.slice(1, -1);
|
|
149
|
-
}
|
|
150
|
-
return token;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function shouldBlockExecString(command) {
|
|
154
|
-
const tokens = normalizeTokensForExec(tokenizeShellString(command).map(unquote));
|
|
155
|
-
if (tokens.length === 0) return false;
|
|
156
|
-
const shellInner = unwrapShellCommand(tokens[0], tokens.slice(1));
|
|
157
|
-
if (shellInner) return shouldBlockExecString(shellInner);
|
|
158
|
-
return shouldBlockCommand(tokens[0], tokens.slice(1));
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function createBlockedError(blockedStderr) {
|
|
162
|
-
const error = new Error(BLOCK_MESSAGE);
|
|
163
|
-
error.code = 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED';
|
|
164
|
-
error.status = 1;
|
|
165
|
-
error.stdout = Buffer.from('');
|
|
166
|
-
error.stderr = Buffer.from(blockedStderr);
|
|
167
|
-
return error;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function createBlockedSpawn(blockedStderr, stderrWriter, options) {
|
|
171
|
-
const child = new EventEmitter();
|
|
172
|
-
child.stdout = null;
|
|
173
|
-
child.stderr = null;
|
|
174
|
-
child.stdin = null;
|
|
175
|
-
child.pid = 0;
|
|
176
|
-
child.killed = false;
|
|
177
|
-
child.kill = () => false;
|
|
178
|
-
process.nextTick(() => {
|
|
179
|
-
if (!(options && options.stdio === 'ignore')) {
|
|
180
|
-
stderrWriter(blockedStderr);
|
|
181
|
-
}
|
|
182
|
-
child.emit('close', 1, null);
|
|
183
|
-
child.emit('exit', 1, null);
|
|
184
|
-
});
|
|
185
|
-
return child;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function createBlockedSpawnSync(blockedStderr, stderrWriter) {
|
|
189
|
-
stderrWriter(blockedStderr);
|
|
190
|
-
return {
|
|
191
|
-
pid: 0,
|
|
192
|
-
output: [null, Buffer.from(''), Buffer.from(blockedStderr)],
|
|
193
|
-
stdout: Buffer.from(''),
|
|
194
|
-
stderr: Buffer.from(blockedStderr),
|
|
195
|
-
status: 1,
|
|
196
|
-
signal: null,
|
|
197
|
-
error: createBlockedError(blockedStderr),
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function createBlockedExecResult(blockedStderr, stderrWriter, callback) {
|
|
202
|
-
const child = createBlockedSpawn(blockedStderr, stderrWriter);
|
|
203
|
-
const error = createBlockedError(blockedStderr);
|
|
204
|
-
process.nextTick(() => {
|
|
205
|
-
if (typeof callback === 'function') {
|
|
206
|
-
callback(error, '', blockedStderr);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
return child;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function shouldBlockSpawnArgs(args) {
|
|
213
|
-
if (!Array.isArray(args) || args.length === 0) return false;
|
|
214
|
-
const command = args[0];
|
|
215
|
-
const commandArgs = Array.isArray(args[1]) ? args[1] : [];
|
|
216
|
-
const shellInner = unwrapShellCommand(command, commandArgs);
|
|
217
|
-
if (shellInner) return shouldBlockExecString(shellInner);
|
|
218
|
-
return shouldBlockCommand(command, commandArgs);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function createGuardedChildProcess(realChild, stderrWriter = value => process.stderr.write(value)) {
|
|
222
|
-
const blockedStderr = `${BLOCK_MESSAGE}\n`;
|
|
223
|
-
return {
|
|
224
|
-
spawn: (...args) => {
|
|
225
|
-
if (shouldBlockSpawnArgs(args)) return createBlockedSpawn(blockedStderr, stderrWriter, args[2]);
|
|
226
|
-
return realChild.spawn(...args);
|
|
227
|
-
},
|
|
228
|
-
execFile: (...args) => {
|
|
229
|
-
if (shouldBlockSpawnArgs(args)) return createBlockedExecResult(blockedStderr, stderrWriter, args[args.length - 1]);
|
|
230
|
-
return realChild.execFile(...args);
|
|
231
|
-
},
|
|
232
|
-
exec: (...args) => {
|
|
233
|
-
if (shouldBlockExecString(args[0])) return createBlockedExecResult(blockedStderr, stderrWriter, args[args.length - 1]);
|
|
234
|
-
return realChild.exec(...args);
|
|
235
|
-
},
|
|
236
|
-
spawnSync: (...args) => {
|
|
237
|
-
if (shouldBlockSpawnArgs(args)) return createBlockedSpawnSync(blockedStderr, stderrWriter);
|
|
238
|
-
return realChild.spawnSync(...args);
|
|
239
|
-
},
|
|
240
|
-
execFileSync: (...args) => {
|
|
241
|
-
if (shouldBlockSpawnArgs(args)) throw createBlockedError(blockedStderr);
|
|
242
|
-
return realChild.execFileSync(...args);
|
|
243
|
-
},
|
|
244
|
-
execSync: (...args) => {
|
|
245
|
-
if (shouldBlockExecString(args[0])) throw createBlockedError(blockedStderr);
|
|
246
|
-
return realChild.execSync(...args);
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
module.exports = {
|
|
252
|
-
BLOCK_MESSAGE,
|
|
253
|
-
OFFICIAL_PACKAGE,
|
|
254
|
-
createGuardedChildProcess,
|
|
255
|
-
shouldBlockCommand,
|
|
256
|
-
shouldBlockExecString,
|
|
257
|
-
};
|