@bash0816/claude-code 2.1.240 → 2.1.245
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 +1 -1
- package/bin/claude +10 -2
- package/config/claude-native-audited-versions.json +17 -0
- package/config/claude-termux-release-manifest.json +3 -3
- package/lib/bunfs-child-process-guard.mjs +18 -0
- package/lib/bunfs-child-process-guard.test.js +113 -0
- package/lib/bunfs-esm-loader.mjs +74 -0
- package/lib/bunfs-esm-loader.test.js +329 -0
- package/lib/bunfs-extract.js +205 -0
- package/lib/bunfs-extract.test.js +265 -0
- package/lib/bunfs-vm-guard.mjs +116 -0
- package/lib/bunfs-vm-guard.test.js +142 -0
- package/lib/bunfs-ws-stub.mjs +11 -0
- package/lib/bunfs-yaml-shim.mjs +91 -0
- package/lib/prepare-native.js +30 -0
- package/lib/termux-run-claude-native.sh +132 -4
- package/lib/termux-run-claude-native.test.js +3 -3
- package/package.json +2 -2
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
|
|
6
|
+
test('bunfs-vm-guard exports all vm module methods', async () => {
|
|
7
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
8
|
+
|
|
9
|
+
assert.equal(typeof vmGuard.createContext, 'function');
|
|
10
|
+
assert.equal(typeof vmGuard.isContext, 'function');
|
|
11
|
+
assert.equal(typeof vmGuard.runInContext, 'function');
|
|
12
|
+
assert.equal(typeof vmGuard.runInNewContext, 'function');
|
|
13
|
+
assert.equal(typeof vmGuard.runInThisContext, 'function');
|
|
14
|
+
assert.equal(typeof vmGuard.createScript, 'function');
|
|
15
|
+
assert.equal(typeof vmGuard.compileFunction, 'function');
|
|
16
|
+
assert.equal(typeof vmGuard.measureMemory, 'function');
|
|
17
|
+
assert.equal(typeof vmGuard.Script, 'function');
|
|
18
|
+
// SourceTextModule and SyntheticModule only exist with --experimental-vm-modules flag
|
|
19
|
+
assert.ok('SourceTextModule' in vmGuard);
|
|
20
|
+
assert.ok('SyntheticModule' in vmGuard);
|
|
21
|
+
assert.ok(vmGuard.constants);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('bunfs-vm-guard provides default export with vm module API', async () => {
|
|
25
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
26
|
+
const defaultExport = vmGuard.default;
|
|
27
|
+
|
|
28
|
+
assert.ok(defaultExport);
|
|
29
|
+
assert.equal(typeof defaultExport, 'object');
|
|
30
|
+
assert.equal(typeof defaultExport.createContext, 'function');
|
|
31
|
+
assert.equal(typeof defaultExport.isContext, 'function');
|
|
32
|
+
assert.equal(typeof defaultExport.runInContext, 'function');
|
|
33
|
+
assert.equal(typeof defaultExport.runInNewContext, 'function');
|
|
34
|
+
assert.equal(typeof defaultExport.runInThisContext, 'function');
|
|
35
|
+
assert.equal(typeof defaultExport.createScript, 'function');
|
|
36
|
+
assert.equal(typeof defaultExport.compileFunction, 'function');
|
|
37
|
+
assert.equal(typeof defaultExport.measureMemory, 'function');
|
|
38
|
+
assert.equal(typeof defaultExport.Script, 'function');
|
|
39
|
+
// SourceTextModule and SyntheticModule may not exist in default export without --experimental-vm-modules
|
|
40
|
+
// They are exported as named exports if they exist
|
|
41
|
+
assert.ok(defaultExport.constants);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('bunfs-vm-guard injects Bun into context in createContext', async () => {
|
|
45
|
+
globalThis.Bun = { __dummy: true };
|
|
46
|
+
try {
|
|
47
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
48
|
+
|
|
49
|
+
const context = vmGuard.createContext({});
|
|
50
|
+
// Check that Bun property exists in context
|
|
51
|
+
assert.ok(Object.prototype.hasOwnProperty.call(context, 'Bun'));
|
|
52
|
+
|
|
53
|
+
// Verify Bun is defined when we run code in context
|
|
54
|
+
const result = vmGuard.runInContext('typeof Bun', context);
|
|
55
|
+
assert.equal(result, 'object');
|
|
56
|
+
} finally {
|
|
57
|
+
delete globalThis.Bun;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('bunfs-vm-guard injects Bun into context in runInNewContext', async () => {
|
|
62
|
+
globalThis.Bun = { __dummy: true };
|
|
63
|
+
try {
|
|
64
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
65
|
+
|
|
66
|
+
const code = 'typeof Bun';
|
|
67
|
+
const result = vmGuard.runInNewContext(code, {});
|
|
68
|
+
assert.equal(result, 'object');
|
|
69
|
+
} finally {
|
|
70
|
+
delete globalThis.Bun;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('bunfs-vm-guard injects __claudeYaml into context', async () => {
|
|
75
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
76
|
+
|
|
77
|
+
const context = vmGuard.createContext({});
|
|
78
|
+
// Check that __claudeYaml property exists
|
|
79
|
+
assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeYaml'));
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('bunfs-vm-guard injects __claudeBun and __claudeBunShim into context', async () => {
|
|
83
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
84
|
+
|
|
85
|
+
const context = vmGuard.createContext({});
|
|
86
|
+
// Check that shim properties exist
|
|
87
|
+
assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeBun'));
|
|
88
|
+
assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeBunShim'));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('bunfs-vm-guard Script class works with context injection', async () => {
|
|
92
|
+
globalThis.Bun = { __dummy: true };
|
|
93
|
+
try {
|
|
94
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
95
|
+
|
|
96
|
+
const code = 'typeof Bun';
|
|
97
|
+
const script = new vmGuard.Script(code);
|
|
98
|
+
const context = vmGuard.createContext({});
|
|
99
|
+
const result = script.runInContext(context);
|
|
100
|
+
assert.equal(result, 'object');
|
|
101
|
+
} finally {
|
|
102
|
+
delete globalThis.Bun;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('bunfs-vm-guard handles context with existing Bun property', async () => {
|
|
107
|
+
globalThis.Bun = { __dummy: true };
|
|
108
|
+
try {
|
|
109
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
110
|
+
|
|
111
|
+
// Create context with pre-existing Bun property
|
|
112
|
+
const context = vmGuard.createContext({ Bun: { custom: true } });
|
|
113
|
+
// The guard should have replaced/overwritten it with globalThis.Bun
|
|
114
|
+
const result = vmGuard.runInContext('typeof Bun', context);
|
|
115
|
+
assert.equal(result, 'object');
|
|
116
|
+
} finally {
|
|
117
|
+
delete globalThis.Bun;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('bunfs-vm-guard does not break normal vm functionality', async () => {
|
|
122
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
123
|
+
|
|
124
|
+
// Test that normal code execution still works
|
|
125
|
+
const code = '2 + 2';
|
|
126
|
+
const result = vmGuard.runInNewContext(code);
|
|
127
|
+
assert.equal(result, 4);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('bunfs-vm-guard Script.runInNewContext works with injections', async () => {
|
|
131
|
+
globalThis.Bun = { __dummy: true };
|
|
132
|
+
try {
|
|
133
|
+
const vmGuard = await import('./bunfs-vm-guard.mjs');
|
|
134
|
+
|
|
135
|
+
const code = 'typeof Bun';
|
|
136
|
+
const script = new vmGuard.Script(code);
|
|
137
|
+
const result = script.runInNewContext({});
|
|
138
|
+
assert.equal(result, 'object');
|
|
139
|
+
} finally {
|
|
140
|
+
delete globalThis.Bun;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
function parseScalar(value) {
|
|
2
|
+
const text = String(value ?? '').trim();
|
|
3
|
+
if (text === '') return '';
|
|
4
|
+
if (text === 'true') return true;
|
|
5
|
+
if (text === 'false') return false;
|
|
6
|
+
if (text === 'null' || text === '~') return null;
|
|
7
|
+
if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(text)) return Number(text);
|
|
8
|
+
if (
|
|
9
|
+
(text.startsWith('"') && text.endsWith('"')) ||
|
|
10
|
+
(text.startsWith("'") && text.endsWith("'"))
|
|
11
|
+
) {
|
|
12
|
+
return text.slice(1, -1);
|
|
13
|
+
}
|
|
14
|
+
return text;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseInlineArray(value) {
|
|
18
|
+
const inner = String(value ?? '').trim().slice(1, -1).trim();
|
|
19
|
+
if (inner === '') return [];
|
|
20
|
+
const items = [];
|
|
21
|
+
let current = '';
|
|
22
|
+
let quote = null;
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < inner.length; i += 1) {
|
|
25
|
+
const ch = inner[i];
|
|
26
|
+
if (quote) {
|
|
27
|
+
if (ch === quote && inner[i - 1] !== '\\') quote = null;
|
|
28
|
+
current += ch;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (ch === '"' || ch === "'") {
|
|
32
|
+
quote = ch;
|
|
33
|
+
current += ch;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (ch === ',') {
|
|
37
|
+
items.push(parseScalar(current));
|
|
38
|
+
current = '';
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
current += ch;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (current !== '') items.push(parseScalar(current));
|
|
45
|
+
return items;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function yamlParse(text) {
|
|
49
|
+
const source = String(text ?? '');
|
|
50
|
+
const result = {};
|
|
51
|
+
for (const rawLine of source.split(/\r?\n/)) {
|
|
52
|
+
const line = rawLine.trim();
|
|
53
|
+
if (!line || line.startsWith('#')) continue;
|
|
54
|
+
const idx = line.indexOf(':');
|
|
55
|
+
if (idx < 0) continue;
|
|
56
|
+
const key = line.slice(0, idx).trim();
|
|
57
|
+
const rawValue = line.slice(idx + 1).trim();
|
|
58
|
+
if (!key) continue;
|
|
59
|
+
result[key] = rawValue.startsWith('[') && rawValue.endsWith(']')
|
|
60
|
+
? parseInlineArray(rawValue)
|
|
61
|
+
: parseScalar(rawValue);
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function yamlStringify(value) {
|
|
67
|
+
if (!value || typeof value !== 'object') return String(value ?? '');
|
|
68
|
+
const lines = [];
|
|
69
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
70
|
+
if (Array.isArray(raw)) {
|
|
71
|
+
lines.push(`${key}: [${raw.map(item => JSON.stringify(String(item))).join(', ')}]`);
|
|
72
|
+
} else if (raw === null) {
|
|
73
|
+
lines.push(`${key}: null`);
|
|
74
|
+
} else if (typeof raw === 'string') {
|
|
75
|
+
lines.push(`${key}: ${JSON.stringify(raw)}`);
|
|
76
|
+
} else {
|
|
77
|
+
lines.push(`${key}: ${String(raw)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return lines.join('\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function createYamlShim() {
|
|
84
|
+
const yaml = {
|
|
85
|
+
parse: yamlParse,
|
|
86
|
+
stringify: yamlStringify,
|
|
87
|
+
};
|
|
88
|
+
yaml.YAML = yaml;
|
|
89
|
+
yaml.default = yaml;
|
|
90
|
+
return yaml;
|
|
91
|
+
}
|
package/lib/prepare-native.js
CHANGED
|
@@ -128,6 +128,14 @@ function verifyTarball(file, audited) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
function validateOffsets(file, audited) {
|
|
131
|
+
if (audited.entry_format === 'esm-chunked') {
|
|
132
|
+
validateEsmChunkedOffsets(file, audited);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
validateLegacyCjsOffsets(file, audited);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function validateLegacyCjsOffsets(file, audited) {
|
|
131
139
|
const buf = fs.readFileSync(file);
|
|
132
140
|
const start = Number(audited.entry_js_offset);
|
|
133
141
|
const end = Number(audited.entry_end_offset);
|
|
@@ -144,3 +152,25 @@ function validateOffsets(file, audited) {
|
|
|
144
152
|
throw new Error(`audited end offset validation failed for ${version}`);
|
|
145
153
|
}
|
|
146
154
|
}
|
|
155
|
+
|
|
156
|
+
function validateEsmChunkedOffsets(file, audited) {
|
|
157
|
+
// 371MB超のバイナリ全体をreadFileSyncしない(実機でOOM確認済み)。
|
|
158
|
+
// discoverModuleGraphは範囲readSyncのみでトレイラー・モジュールテーブルを検証する。
|
|
159
|
+
const { discoverModuleGraph, readEntryContentPrefix } = require(path.join(packageDir, 'lib', 'bunfs-extract.js'));
|
|
160
|
+
const graph = discoverModuleGraph(file);
|
|
161
|
+
try {
|
|
162
|
+
if (!(graph.numModules > 0)) {
|
|
163
|
+
throw new Error(`esm-chunked module graph is empty for ${version}`);
|
|
164
|
+
}
|
|
165
|
+
if (graph.entryName !== '/$bunfs/root/cli') {
|
|
166
|
+
throw new Error(`esm-chunked entry module name mismatch for ${version}: ${graph.entryName}`);
|
|
167
|
+
}
|
|
168
|
+
const prefix = readEntryContentPrefix(graph.fd, graph.entryModule, 256).toString('utf8');
|
|
169
|
+
const codeStart = prefix.replace(/^(\s*\/\/[^\n]*\n)+/, '').replace(/^\(/, '');
|
|
170
|
+
if (codeStart.startsWith('function(exports, require, module, __filename, __dirname) {')) {
|
|
171
|
+
throw new Error(`entry module for ${version} is legacy-cjs wrapped, but audited entry_format is esm-chunked`);
|
|
172
|
+
}
|
|
173
|
+
} finally {
|
|
174
|
+
fs.closeSync(graph.fd);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -3,8 +3,14 @@ set -eu
|
|
|
3
3
|
|
|
4
4
|
SOURCE_BIN="${SOURCE_BIN:?SOURCE_BIN is required}"
|
|
5
5
|
WORKDIR="${WORKDIR:-${HOME}/.claude-termux-native-package/launcher-workdir}"
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
ENTRY_FORMAT="${ENTRY_FORMAT:-legacy-cjs}"
|
|
7
|
+
if [ "${ENTRY_FORMAT}" = "esm-chunked" ]; then
|
|
8
|
+
ENTRY_JS_OFFSET="${ENTRY_JS_OFFSET:-0}"
|
|
9
|
+
ENTRY_END_OFFSET="${ENTRY_END_OFFSET:-0}"
|
|
10
|
+
else
|
|
11
|
+
ENTRY_JS_OFFSET="${ENTRY_JS_OFFSET:?ENTRY_JS_OFFSET is required}"
|
|
12
|
+
ENTRY_END_OFFSET="${ENTRY_END_OFFSET:?ENTRY_END_OFFSET is required}"
|
|
13
|
+
fi
|
|
8
14
|
CURRENT_CLAUDE_VERSION="${CURRENT_CLAUDE_VERSION:?CURRENT_CLAUDE_VERSION is required}"
|
|
9
15
|
CLAUDE_TERMUX_PACKAGE_DIR="${CLAUDE_TERMUX_PACKAGE_DIR:?CLAUDE_TERMUX_PACKAGE_DIR is required}"
|
|
10
16
|
TERMUX_TMPDIR="${TMPDIR:-/data/data/com.termux/files/usr/tmp}"
|
|
@@ -45,6 +51,7 @@ export SSL_CERT_FILE
|
|
|
45
51
|
export DISABLE_AUTOUPDATER
|
|
46
52
|
export SOURCE_BIN
|
|
47
53
|
export WORKDIR
|
|
54
|
+
export ENTRY_FORMAT
|
|
48
55
|
export ENTRY_JS_OFFSET
|
|
49
56
|
export ENTRY_END_OFFSET
|
|
50
57
|
export CURRENT_CLAUDE_VERSION
|
|
@@ -656,7 +663,60 @@ function rewriteNativeChunkSource(source) {
|
|
|
656
663
|
return patched;
|
|
657
664
|
}
|
|
658
665
|
|
|
659
|
-
async function
|
|
666
|
+
async function esmChunkedMain() {
|
|
667
|
+
const { prepareProcessOwnedDir } = require(path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib', 'bunfs-extract.js'));
|
|
668
|
+
const { register } = require('node:module');
|
|
669
|
+
const { pathToFileURL } = require('node:url');
|
|
670
|
+
|
|
671
|
+
const { ownedDir, entryRelPath } = prepareProcessOwnedDir(sourceBin, workdir);
|
|
672
|
+
const libDir = path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib');
|
|
673
|
+
|
|
674
|
+
globalThis.__claudeYaml = createYamlShim();
|
|
675
|
+
globalThis.Bun = {
|
|
676
|
+
version: '1.1.8',
|
|
677
|
+
stringWidth,
|
|
678
|
+
wrapAnsi,
|
|
679
|
+
stripANSI,
|
|
680
|
+
hash: stableHash,
|
|
681
|
+
which: (cmd) => {
|
|
682
|
+
try {
|
|
683
|
+
return require('child_process').execFileSync('which', [String(cmd)], { encoding: 'utf8' }).trim() || null;
|
|
684
|
+
} catch { return null; }
|
|
685
|
+
},
|
|
686
|
+
gc: () => {},
|
|
687
|
+
YAML: globalThis.__claudeYaml,
|
|
688
|
+
};
|
|
689
|
+
Object.defineProperty(process.versions, 'bun', { value: '1.1.8', configurable: true });
|
|
690
|
+
globalThis.__claudeBunShim = globalThis.Bun;
|
|
691
|
+
globalThis.__claudeBun = globalThis.Bun;
|
|
692
|
+
|
|
693
|
+
register(pathToFileURL(path.join(libDir, 'bunfs-esm-loader.mjs')).href, {
|
|
694
|
+
parentURL: pathToFileURL(__filename).href,
|
|
695
|
+
data: {
|
|
696
|
+
processOwnedDir: ownedDir,
|
|
697
|
+
sourceBin,
|
|
698
|
+
childProcessGuardPath: path.join(libDir, 'bunfs-child-process-guard.mjs'),
|
|
699
|
+
vmGuardPath: path.join(libDir, 'bunfs-vm-guard.mjs'),
|
|
700
|
+
wsStubPath: path.join(libDir, 'bunfs-ws-stub.mjs'),
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
const entryUrl = pathToFileURL(path.join(ownedDir, entryRelPath)).href;
|
|
705
|
+
|
|
706
|
+
// 2.1.245実チャンクのエントリは、内部のmain相当処理をトップレベルでawaitせず
|
|
707
|
+
// fire-and-forgetで起動する(Bunランタイム前提の実装)。そのためawait import()は
|
|
708
|
+
// 内部の非同期処理が完了する前に解決してしまい、legacy-cjs経路のような
|
|
709
|
+
// process.exitパッチ+ここでの強制exit呼び出しを行うと、まだ実行中の内部処理を
|
|
710
|
+
// 強制終了させ出力が失われる(実機で確認済み)。process.exit/killは一切パッチせず、
|
|
711
|
+
// 実際のCLIコードが自ら呼ぶprocess.exit()に任せてNodeの自然なイベントループ終了を
|
|
712
|
+
// 待つ(この関数はawait import()完了後、何もせずreturnするだけでよい)。
|
|
713
|
+
// 同じ理由で、ここでglobalThis.Bun/__claudeYamlを削除するcleanupも行わない
|
|
714
|
+
// (fire-and-forgetの内部処理がimport()解決後も継続してBunを参照するため、
|
|
715
|
+
// 早期に消すと実機で"Bun is not defined"を引き起こす。プロセス終了まで残す)。
|
|
716
|
+
await import(entryUrl);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
async function legacyCjsMain() {
|
|
660
720
|
let extractedFile;
|
|
661
721
|
extractedFile = ensureEntryFile();
|
|
662
722
|
const code = fs.readFileSync(extractedFile, 'utf8');
|
|
@@ -1000,6 +1060,10 @@ async function main() {
|
|
|
1000
1060
|
}
|
|
1001
1061
|
}
|
|
1002
1062
|
|
|
1063
|
+
function main() {
|
|
1064
|
+
return process.env.ENTRY_FORMAT === 'esm-chunked' ? esmChunkedMain() : legacyCjsMain();
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1003
1067
|
main().catch(error => {
|
|
1004
1068
|
if (error && error.code === 'CLAUDE_TERMUX_OFFICIAL_UPDATE_BLOCKED') {
|
|
1005
1069
|
console.error(BLOCK_MESSAGE);
|
|
@@ -1613,7 +1677,60 @@ function rewriteNativeChunkSource(source) {
|
|
|
1613
1677
|
return patched;
|
|
1614
1678
|
}
|
|
1615
1679
|
|
|
1616
|
-
async function
|
|
1680
|
+
async function esmChunkedMain() {
|
|
1681
|
+
const { prepareProcessOwnedDir } = require(path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib', 'bunfs-extract.js'));
|
|
1682
|
+
const { register } = require('node:module');
|
|
1683
|
+
const { pathToFileURL } = require('node:url');
|
|
1684
|
+
|
|
1685
|
+
const { ownedDir, entryRelPath } = prepareProcessOwnedDir(sourceBin, workdir);
|
|
1686
|
+
const libDir = path.join(process.env.CLAUDE_TERMUX_PACKAGE_DIR, 'lib');
|
|
1687
|
+
|
|
1688
|
+
globalThis.__claudeYaml = createYamlShim();
|
|
1689
|
+
globalThis.Bun = {
|
|
1690
|
+
version: '1.1.8',
|
|
1691
|
+
stringWidth,
|
|
1692
|
+
wrapAnsi,
|
|
1693
|
+
stripANSI,
|
|
1694
|
+
hash: stableHash,
|
|
1695
|
+
which: (cmd) => {
|
|
1696
|
+
try {
|
|
1697
|
+
return require('child_process').execFileSync('which', [String(cmd)], { encoding: 'utf8' }).trim() || null;
|
|
1698
|
+
} catch { return null; }
|
|
1699
|
+
},
|
|
1700
|
+
gc: () => {},
|
|
1701
|
+
YAML: globalThis.__claudeYaml,
|
|
1702
|
+
};
|
|
1703
|
+
Object.defineProperty(process.versions, 'bun', { value: '1.1.8', configurable: true });
|
|
1704
|
+
globalThis.__claudeBunShim = globalThis.Bun;
|
|
1705
|
+
globalThis.__claudeBun = globalThis.Bun;
|
|
1706
|
+
|
|
1707
|
+
register(pathToFileURL(path.join(libDir, 'bunfs-esm-loader.mjs')).href, {
|
|
1708
|
+
parentURL: pathToFileURL(__filename).href,
|
|
1709
|
+
data: {
|
|
1710
|
+
processOwnedDir: ownedDir,
|
|
1711
|
+
sourceBin,
|
|
1712
|
+
childProcessGuardPath: path.join(libDir, 'bunfs-child-process-guard.mjs'),
|
|
1713
|
+
vmGuardPath: path.join(libDir, 'bunfs-vm-guard.mjs'),
|
|
1714
|
+
wsStubPath: path.join(libDir, 'bunfs-ws-stub.mjs'),
|
|
1715
|
+
},
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
const entryUrl = pathToFileURL(path.join(ownedDir, entryRelPath)).href;
|
|
1719
|
+
|
|
1720
|
+
// 2.1.245実チャンクのエントリは、内部のmain相当処理をトップレベルでawaitせず
|
|
1721
|
+
// fire-and-forgetで起動する(Bunランタイム前提の実装)。そのためawait import()は
|
|
1722
|
+
// 内部の非同期処理が完了する前に解決してしまい、legacy-cjs経路のような
|
|
1723
|
+
// process.exitパッチ+ここでの強制exit呼び出しを行うと、まだ実行中の内部処理を
|
|
1724
|
+
// 強制終了させ出力が失われる(実機で確認済み)。process.exit/killは一切パッチせず、
|
|
1725
|
+
// 実際のCLIコードが自ら呼ぶprocess.exit()に任せてNodeの自然なイベントループ終了を
|
|
1726
|
+
// 待つ(この関数はawait import()完了後、何もせずreturnするだけでよい)。
|
|
1727
|
+
// 同じ理由で、ここでglobalThis.Bun/__claudeYamlを削除するcleanupも行わない
|
|
1728
|
+
// (fire-and-forgetの内部処理がimport()解決後も継続してBunを参照するため、
|
|
1729
|
+
// 早期に消すと実機で"Bun is not defined"を引き起こす。プロセス終了まで残す)。
|
|
1730
|
+
await import(entryUrl);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
async function legacyCjsMain() {
|
|
1617
1734
|
let extractedFile;
|
|
1618
1735
|
extractedFile = ensureEntryFile();
|
|
1619
1736
|
const code = fs.readFileSync(extractedFile, 'utf8');
|
|
@@ -1961,8 +2078,19 @@ async function main() {
|
|
|
1961
2078
|
}
|
|
1962
2079
|
}
|
|
1963
2080
|
|
|
2081
|
+
function main() {
|
|
2082
|
+
return process.env.ENTRY_FORMAT === 'esm-chunked' ? esmChunkedMain() : legacyCjsMain();
|
|
2083
|
+
}
|
|
2084
|
+
|
|
1964
2085
|
main()
|
|
1965
2086
|
.then(() => {
|
|
2087
|
+
// esm-chunked経路は内部のfire-and-forget非同期処理が実際のprocess.exit()を
|
|
2088
|
+
// 自ら呼ぶまでNodeのイベントループを生かしておく必要があるため、TUIモードと
|
|
2089
|
+
// 同様にここでは強制exitしない(実機で確認済み: 強制exitすると--helpの出力等が
|
|
2090
|
+
// 完了前に打ち切られる)。
|
|
2091
|
+
if (process.env.ENTRY_FORMAT === 'esm-chunked') {
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
1966
2094
|
if (process.env.CLAUDE_TERMUX_TUI === '1' && process.exitCode === undefined) {
|
|
1967
2095
|
return;
|
|
1968
2096
|
}
|
|
@@ -81,7 +81,7 @@ function loadHelperApi() {
|
|
|
81
81
|
const rewriteSource = extractFunction(
|
|
82
82
|
helperBlock,
|
|
83
83
|
'function rewriteNativeChunkSource(source) {',
|
|
84
|
-
'\n\nasync function
|
|
84
|
+
'\n\nasync function esmChunkedMain() {',
|
|
85
85
|
);
|
|
86
86
|
|
|
87
87
|
const context = vm.createContext({ module: { exports: {} }, exports: {}, fs, path, process });
|
|
@@ -113,12 +113,12 @@ test('helper and bootstrap rewrite helpers stay identical', () => {
|
|
|
113
113
|
const helperRewrite = extractFunction(
|
|
114
114
|
helperBlock,
|
|
115
115
|
'function rewriteNativeChunkSource(source) {',
|
|
116
|
-
'\n\nasync function
|
|
116
|
+
'\n\nasync function esmChunkedMain() {',
|
|
117
117
|
);
|
|
118
118
|
const bootstrapRewrite = extractFunction(
|
|
119
119
|
bootstrapBlock,
|
|
120
120
|
'function rewriteNativeChunkSource(source) {',
|
|
121
|
-
'\n\nasync function
|
|
121
|
+
'\n\nasync function esmChunkedMain() {',
|
|
122
122
|
);
|
|
123
123
|
const helperWrapAnsi = extractFunction(
|
|
124
124
|
helperBlock,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bash0816/claude-code",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.245",
|
|
4
4
|
"description": "Unofficial Termux-native Claude Code wrapper with audited native replay",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"LICENSE"
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=20.6.0"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"claude-code",
|