@bash0816/copilot-termux 1.0.63 → 1.0.65
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/config/manifest.json +3 -2
- package/lib/bionic-compat.so +0 -0
- package/lib/platform-patch.js +557 -3
- package/lib/setup.js +5 -5
- package/package.json +28 -5
- package/scripts/bionic-compat.c +3 -0
package/config/manifest.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"wrapperVersion": "2.0.0",
|
|
3
3
|
"copilot": {
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"package": "@github/copilot-linuxmusl-arm64",
|
|
5
|
+
"version": "1.0.64",
|
|
6
|
+
"integrity": "sha512-C+EYoMvmlUxR0YYxLkD3nwn940y0zId8z+pPl9rFO6f9heMGXYCwCZL2i2c3GW6CvGgZF6Wbzw1Kk0Gvw46F2w=="
|
|
6
7
|
}
|
|
7
8
|
}
|
package/lib/bionic-compat.so
CHANGED
|
Binary file
|
package/lib/platform-patch.js
CHANGED
|
@@ -19,6 +19,10 @@ const Module = require('module');
|
|
|
19
19
|
const fs = require('fs');
|
|
20
20
|
const path = require('path');
|
|
21
21
|
|
|
22
|
+
const _pkgVersion = (() => {
|
|
23
|
+
try { return require(path.join(__dirname, '..', 'package.json')).version; } catch (_) { return '1.0.65'; }
|
|
24
|
+
})();
|
|
25
|
+
|
|
22
26
|
// Bundled Termux-native pty.node (built against bionic, not glibc).
|
|
23
27
|
const NATIVE_PTY = path.join(__dirname, 'native', 'pty.node');
|
|
24
28
|
|
|
@@ -58,19 +62,86 @@ Module._load = function (request, parent, isMain) {
|
|
|
58
62
|
const result = origLoad(request, parent, isMain);
|
|
59
63
|
if (typeof request === 'string' &&
|
|
60
64
|
path.basename(request) === 'runtime.node') {
|
|
65
|
+
if (result.__copilotTermuxPatched) return result;
|
|
66
|
+
result.__copilotTermuxPatched = true;
|
|
61
67
|
// Rust tokio を使う関数群を no-op に差し替え。
|
|
62
68
|
// sessionStore*/sessionSqlite* は非同期 SQLite (tokio)、
|
|
63
69
|
// modelHttp*/networkFetch*/ahpRelay*/websocketResponses* は Rust HTTP (tokio)。
|
|
70
|
+
// jsonrpcServer* は拡張 JSON-RPC サーバー (ThreadsafeFunction)、
|
|
71
|
+
// lspClient* は LSP クライアント (ThreadsafeFunction)。
|
|
64
72
|
// featureFlagService* は同期 Rust のため除外(no-op にすると .handle クラッシュ)。
|
|
65
|
-
const TOKIO_PATTERN = /^(modelHttp|networkFetch|ahpRelay|websocketResponses|sessionStore|sessionSqlite)/;
|
|
73
|
+
const TOKIO_PATTERN = /^(modelHttp|networkFetch|ahpRelay|websocketResponses|sessionStore|sessionSqlite|jsonrpcServer|lspClient)/;
|
|
66
74
|
for (const key of Object.keys(result)) {
|
|
67
75
|
if (TOKIO_PATTERN.test(key) && typeof result[key] === 'function') {
|
|
68
76
|
result[key] = () => undefined;
|
|
69
77
|
}
|
|
70
78
|
}
|
|
79
|
+
// git*Async: Rust tokio async functions — type-safe stubs to prevent SIGSEGV.
|
|
80
|
+
// Returns empty/null values matching what app.js callers expect.
|
|
81
|
+
const GIT_ASYNC_STUBS = {
|
|
82
|
+
gitMutateAsync: async () => undefined,
|
|
83
|
+
gitCommandAsync: async () => '',
|
|
84
|
+
gitRemotesAsync: async () => [],
|
|
85
|
+
gitDiffFileAsync: async () => '',
|
|
86
|
+
gitHashFileAsync: async () => [],
|
|
87
|
+
gitMergeBaseAsync: async () => null,
|
|
88
|
+
gitDiffForRefAsync: async () => '',
|
|
89
|
+
gitCurrentBranchAsync: async () => null,
|
|
90
|
+
gitDefaultBranchAsync: async () => null,
|
|
91
|
+
gitListWorktreesAsync: async () => [],
|
|
92
|
+
gitBranchAndHeadAsync: async () => null,
|
|
93
|
+
gitSubmodulePathsAsync: async () => [],
|
|
94
|
+
gitUntrackedPathsAsync: async () => [],
|
|
95
|
+
gitDiffNameStatusAsync: async () => '',
|
|
96
|
+
gitStatusPorcelainAsync: async () => '',
|
|
97
|
+
gitWorkingTreeStatusAsync: async () => ({ hasUnstagedChanges: false, hasStagedChanges: false, hasUntrackedFiles: false }),
|
|
98
|
+
gitStatusPorcelainAllAsync: async () => null,
|
|
99
|
+
gitCurrentBranchRemoteAsync: async () => null,
|
|
100
|
+
gitWorkingTreeDiffStatsAsync: async () => ({ linesAdded: 0, linesRemoved: 0 }),
|
|
101
|
+
};
|
|
102
|
+
for (const [key, stub] of Object.entries(GIT_ASYNC_STUBS)) {
|
|
103
|
+
if (typeof result[key] === 'function') result[key] = stub;
|
|
104
|
+
}
|
|
105
|
+
if (typeof result.registerLogSink === 'function') {
|
|
106
|
+
result.registerLogSink = () => { throw new Error('[copilot-termux] registerLogSink disabled on bionic (no tokio thread)'); };
|
|
107
|
+
}
|
|
71
108
|
if (typeof result.networkFetchGetExtraCaPems === 'function') {
|
|
72
109
|
result.networkFetchGetExtraCaPems = () => ({ errors: [], pems: [] });
|
|
73
110
|
}
|
|
111
|
+
// modelsFilterToPicker: native-first。native が空のとき(model_picker_enabled=true のモデルが
|
|
112
|
+
// 全くない場合)のみ全インデックス fallback。
|
|
113
|
+
// free アカウントでは全モデルが model_picker_enabled=false → native 空 → fallback で全通し
|
|
114
|
+
//(auto モードが enterprise 向けモデルを選んで 400 になる副作用は AUTH-001 解決後に再評価)。
|
|
115
|
+
// enterprise アカウントでは native が正しくフィルタする。
|
|
116
|
+
if (typeof result.modelsFilterToPicker === 'function') {
|
|
117
|
+
const _nativeModelsFilterToPicker = result.modelsFilterToPicker;
|
|
118
|
+
result.modelsFilterToPicker = function(modelsJson) {
|
|
119
|
+
const nativeResult = _nativeModelsFilterToPicker(modelsJson);
|
|
120
|
+
_dbg('modelsFilterToPicker', { nativeResult, modelCount: (() => { try { return JSON.parse(modelsJson).length; } catch(_) { return -1; } })() });
|
|
121
|
+
if (Array.isArray(nativeResult) && nativeResult.length > 0) return nativeResult;
|
|
122
|
+
try {
|
|
123
|
+
const models = JSON.parse(modelsJson);
|
|
124
|
+
return Array.isArray(models) ? models.map((_, i) => i) : [];
|
|
125
|
+
} catch(_) { return []; }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// authGetCopilotApiUrl: type=token/env/user/gh-cli/api-key では native が null を返す。
|
|
129
|
+
// _b() はこれを見て models=[] を返しモデル選択が "No supported model" になる。
|
|
130
|
+
// OAuth token でも標準 copilot API URL は固定のため、null 時はデフォルト URL を返す。
|
|
131
|
+
if (typeof result.authGetCopilotApiUrl === 'function') {
|
|
132
|
+
const _nativeGetCopilotApiUrl = result.authGetCopilotApiUrl;
|
|
133
|
+
result.authGetCopilotApiUrl = function(authInfoJson, token) {
|
|
134
|
+
const r = _nativeGetCopilotApiUrl(authInfoJson, token);
|
|
135
|
+
if (r != null) return r;
|
|
136
|
+
try {
|
|
137
|
+
const info = JSON.parse(authInfoJson);
|
|
138
|
+
if (info && info.type !== 'hmac') {
|
|
139
|
+
return process.env.COPILOT_API_URL || 'https://api.githubcopilot.com';
|
|
140
|
+
}
|
|
141
|
+
} catch (_) {}
|
|
142
|
+
return r;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
74
145
|
// capiClientListModels を Node.js fetch で実装(Rust tokio SIGSEGV 回避)
|
|
75
146
|
if (typeof result.capiClientListModels === 'function') {
|
|
76
147
|
result.capiClientListModels = async function(handle, _includeHidden, _skipCache, _applyModelLimitCaps, _networkingConfigId) {
|
|
@@ -84,7 +155,8 @@ Module._load = function (request, parent, isMain) {
|
|
|
84
155
|
} catch (e) {
|
|
85
156
|
throw new Error(JSON.stringify({kind: 'network', message: `prepareHeaders failed: ${e.message}`}));
|
|
86
157
|
}
|
|
87
|
-
const baseUrl = 'https://api.githubcopilot.com';
|
|
158
|
+
const baseUrl = process.env.COPILOT_API_URL || 'https://api.githubcopilot.com';
|
|
159
|
+
_dbg('capiClientListModels:fetch', { baseUrl });
|
|
88
160
|
let res;
|
|
89
161
|
try {
|
|
90
162
|
res = await globalThis.fetch(`${baseUrl}/models`, {method: 'GET', headers: authHeaders});
|
|
@@ -315,6 +387,7 @@ Module._load = function (request, parent, isMain) {
|
|
|
315
387
|
if (typeof result.anthropicMessageStreamAccumulatorFinish === 'function') {
|
|
316
388
|
result.anthropicMessageStreamAccumulatorFinish = function(id) {
|
|
317
389
|
const acc = _jsAccs.get(id) || { message: null };
|
|
390
|
+
_dbg('accumulatorFinish', { id, message: acc.message ? { stop_reason: acc.message.stop_reason, contentTypes: (acc.message.content||[]).map(b=>b.type+':'+(b.text||'').slice(0,30)) } : null });
|
|
318
391
|
_jsAccs.delete(id);
|
|
319
392
|
return { json: JSON.stringify({ message: acc.message }) };
|
|
320
393
|
};
|
|
@@ -330,6 +403,7 @@ Module._load = function (request, parent, isMain) {
|
|
|
330
403
|
// 4. modelHttpStreamStart → fetch full SSE body, parse events
|
|
331
404
|
result.modelHttpStreamStart = async function(jsonArg) {
|
|
332
405
|
const req = JSON.parse(jsonArg);
|
|
406
|
+
_dbg('modelHttpStreamStart', { url: req.url, method: req.method });
|
|
333
407
|
let body = req.body;
|
|
334
408
|
if (body !== null && body !== undefined && typeof body === 'object') {
|
|
335
409
|
if (body.type === 'Buffer' && Array.isArray(body.data)) {
|
|
@@ -355,12 +429,42 @@ Module._load = function (request, parent, isMain) {
|
|
|
355
429
|
return { json: JSON.stringify({ bodyText, status: res.status, statusText: res.statusText, headers, streamId: null }) };
|
|
356
430
|
}
|
|
357
431
|
const events = _parseAnthropicSSE(bodyText);
|
|
432
|
+
_dbg('modelHttpStreamStart:parsed', { status: res.status, eventCount: events.length, bodySnippet: bodyText.slice(0, 300) });
|
|
358
433
|
const finalMessage = _reconstructFinalMessage(events);
|
|
359
434
|
const streamId = 'js-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);
|
|
360
435
|
_jsStreams.set(streamId, { events, index: 0, finalMessage });
|
|
361
436
|
return { json: JSON.stringify({ bodyText: null, status: res.status, statusText: res.statusText, headers, streamId }) };
|
|
362
437
|
};
|
|
363
438
|
|
|
439
|
+
// Helper: convert Anthropic SSE event → chunkContext for processAnthropicStreamingChunkContext
|
|
440
|
+
function _toChunkContext(event, streamId) {
|
|
441
|
+
const base = { content: '', size: 0, chunkBoundary: false, messageStart: false, streamingId: streamId };
|
|
442
|
+
if (!event || !event.type) return base;
|
|
443
|
+
switch (event.type) {
|
|
444
|
+
case 'message_start':
|
|
445
|
+
return { ...base, messageStart: true };
|
|
446
|
+
case 'content_block_delta': {
|
|
447
|
+
const d = event.delta;
|
|
448
|
+
if (!d) return base;
|
|
449
|
+
if (d.type === 'text_delta') {
|
|
450
|
+
const t = d.text || '';
|
|
451
|
+
return { ...base, content: t, size: Buffer.byteLength(t, 'utf8') };
|
|
452
|
+
}
|
|
453
|
+
if (d.type === 'thinking_delta') {
|
|
454
|
+
const r = d.thinking || '';
|
|
455
|
+
return { ...base, reasoningContent: r, size: Buffer.byteLength(r, 'utf8') };
|
|
456
|
+
}
|
|
457
|
+
return base;
|
|
458
|
+
}
|
|
459
|
+
case 'content_block_stop':
|
|
460
|
+
case 'message_delta':
|
|
461
|
+
case 'message_stop':
|
|
462
|
+
return { ...base, chunkBoundary: true };
|
|
463
|
+
default:
|
|
464
|
+
return base;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
364
468
|
// 5. modelHttpStreamNextAnthropicMessageEvent → yield events one by one
|
|
365
469
|
result.modelHttpStreamNextAnthropicMessageEvent = async function(streamId, accId) {
|
|
366
470
|
const st = _jsStreams.get(streamId);
|
|
@@ -372,7 +476,10 @@ Module._load = function (request, parent, isMain) {
|
|
|
372
476
|
}
|
|
373
477
|
return null;
|
|
374
478
|
}
|
|
375
|
-
|
|
479
|
+
const event = st.events[st.index++];
|
|
480
|
+
const chunkContext = _toChunkContext(event, streamId);
|
|
481
|
+
const tokenEvent = event.type === 'content_block_delta' && !!(event.delta && event.delta.type === 'text_delta');
|
|
482
|
+
return { json: JSON.stringify({ kind: 'ok', processResult: { event, chunkContext, tokenEvent, copilotUsage: null } }) };
|
|
376
483
|
};
|
|
377
484
|
|
|
378
485
|
// 6. modelHttpStreamCancel → cleanup
|
|
@@ -417,6 +524,7 @@ Module._load = function (request, parent, isMain) {
|
|
|
417
524
|
if (!st) {
|
|
418
525
|
throw new Error(`Native mod HTTP stream was not found: ${streamId}`);
|
|
419
526
|
}
|
|
527
|
+
_dbg('responsesStreamDrive:start', { streamId, eventCount: st.events.length, hasProcessors, sample: st.events.slice(0,2) });
|
|
420
528
|
_jsStreams.delete(streamId);
|
|
421
529
|
let copilotUsage = null;
|
|
422
530
|
for (const event of st.events) {
|
|
@@ -427,6 +535,7 @@ Module._load = function (request, parent, isMain) {
|
|
|
427
535
|
if (parsed && parsed.copilotUsage !== undefined && parsed.copilotUsage !== null)
|
|
428
536
|
copilotUsage = parsed.copilotUsage;
|
|
429
537
|
const cc = parsed && parsed.chunkContext;
|
|
538
|
+
_dbg('responsesStreamDrive:chunk', { eventType: event.type, cc: cc ? { content: cc.content, size: cc.size, messageStart: !!cc.messageStart, chunkBoundary: !!cc.chunkBoundary } : null });
|
|
430
539
|
if (hasProcessors && typeof onChunkCallback === 'function' && cc &&
|
|
431
540
|
(cc.content || cc.messageStart || cc.reportIntentArguments || cc.chunkBoundary || cc.size > 0)) {
|
|
432
541
|
try { onChunkCallback(JSON.stringify(cc)); } catch (_) {}
|
|
@@ -434,14 +543,459 @@ Module._load = function (request, parent, isMain) {
|
|
|
434
543
|
}
|
|
435
544
|
return { json: JSON.stringify({ kind: 'ok', copilotUsage, ttftMs: null, interTokenLatencyMs: null }) };
|
|
436
545
|
};
|
|
546
|
+
// === authManager* JS stubs (1.0.64: tokio thread spawn → SIGSEGV on bionic) ===
|
|
547
|
+
const _authMgr = new Map(); // uuid → { cachedInfo, pendingInfo, cachedToken, cachedHost, gen }
|
|
548
|
+
|
|
549
|
+
result.authManagerCreate = function(uuid, hostUri, userAgent, path, normSpec, header, envVar, disableAutoLogin) {
|
|
550
|
+
_authMgr.set(uuid, { cachedInfo: null, pendingInfo: null, cachedToken: null, cachedHost: null, gen: 0 });
|
|
551
|
+
// native 非呼び出し: tokio runtime 生成を阻止
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
async function _buildAuthInfo(token, hostUri) {
|
|
555
|
+
let login = null;
|
|
556
|
+
let copilotUser = null;
|
|
557
|
+
_dbg('buildAuthInfo:start', { tokenHash: _tokenHash(token), hostUri });
|
|
558
|
+
try {
|
|
559
|
+
const apiHost = hostUri.replace('https://github.com', 'https://api.github.com');
|
|
560
|
+
const res = await globalThis.fetch(`${apiHost}/user`, {
|
|
561
|
+
headers: { Authorization: `token ${token}`, 'User-Agent': `copilot-termux/${_pkgVersion}` },
|
|
562
|
+
signal: AbortSignal.timeout(5000),
|
|
563
|
+
});
|
|
564
|
+
if (res.ok) login = (await res.json()).login;
|
|
565
|
+
_dbg('buildAuthInfo:/user', { status: res.status, login });
|
|
566
|
+
} catch (e) {
|
|
567
|
+
_dbg('buildAuthInfo:/user:error', { err: e.message });
|
|
568
|
+
}
|
|
569
|
+
// copilot_internal/user から copilotUser 全体を取得して authInfo に含める。
|
|
570
|
+
// app.js の Wa(authInfo) は authInfo.copilotUser.endpoints.api から CAPI base URL を導く。
|
|
571
|
+
// copilotUser: null のままでは is_mcp_enabled・quota・plan 情報も失われる。
|
|
572
|
+
// env var は後続の capiClientListModels stub / authGetCopilotApiUrl stub でも参照するため並記する。
|
|
573
|
+
try {
|
|
574
|
+
const apiHost = hostUri.replace('https://github.com', 'https://api.github.com');
|
|
575
|
+
const r = await globalThis.fetch(`${apiHost}/copilot_internal/user`, {
|
|
576
|
+
headers: { Authorization: `token ${token}`, 'User-Agent': `copilot-termux/${_pkgVersion}`, 'Copilot-Integration-Id': 'copilot-chat' },
|
|
577
|
+
signal: AbortSignal.timeout(5000),
|
|
578
|
+
});
|
|
579
|
+
if (r.ok) {
|
|
580
|
+
const info = await r.json();
|
|
581
|
+
copilotUser = info;
|
|
582
|
+
const apiUrl = info?.endpoints?.api;
|
|
583
|
+
if (apiUrl && typeof apiUrl === 'string') process.env.COPILOT_API_URL = apiUrl;
|
|
584
|
+
_dbg('buildAuthInfo:/copilot_internal/user', {
|
|
585
|
+
status: r.status,
|
|
586
|
+
access_type_sku: info?.access_type_sku ?? null,
|
|
587
|
+
copilot_plan: info?.copilot_plan ?? null,
|
|
588
|
+
endpoints_api: apiUrl ?? null,
|
|
589
|
+
COPILOT_API_URL: process.env.COPILOT_API_URL ?? null,
|
|
590
|
+
});
|
|
591
|
+
} else {
|
|
592
|
+
_dbg('buildAuthInfo:/copilot_internal/user', { status: r.status, ok: false });
|
|
593
|
+
}
|
|
594
|
+
} catch (e) {
|
|
595
|
+
_dbg('buildAuthInfo:/copilot_internal/user:error', { err: e.message });
|
|
596
|
+
}
|
|
597
|
+
return JSON.stringify({
|
|
598
|
+
authInfo: { type: 'token', host: hostUri, token, login, copilotUser },
|
|
599
|
+
token,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async function _resolveOrCache(uuid, token, env) {
|
|
604
|
+
const entry = _authMgr.get(uuid);
|
|
605
|
+
if (!entry) return null;
|
|
606
|
+
const hostUri = ((typeof result.githubGetUri === 'function'
|
|
607
|
+
? result.githubGetUri(
|
|
608
|
+
(env && env.COPILOT_GH_HOST) || undefined,
|
|
609
|
+
(env && env.GH_HOST) || undefined
|
|
610
|
+
)
|
|
611
|
+
: null) || 'https://github.com').replace(/\/+$/, '');
|
|
612
|
+
if (entry.cachedInfo !== null && (entry.cachedToken !== token || entry.cachedHost !== hostUri)) {
|
|
613
|
+
_dbg('resolveOrCache:cache-invalidate', {
|
|
614
|
+
reason: entry.cachedToken !== token ? 'token-changed' : 'host-changed',
|
|
615
|
+
oldTokenHash: _tokenHash(entry.cachedToken), newTokenHash: _tokenHash(token),
|
|
616
|
+
});
|
|
617
|
+
entry.cachedInfo = null;
|
|
618
|
+
entry.pendingInfo = null;
|
|
619
|
+
}
|
|
620
|
+
if (entry.cachedInfo !== null) {
|
|
621
|
+
_dbg('resolveOrCache:cache-hit', { tokenHash: _tokenHash(token) });
|
|
622
|
+
return entry.cachedInfo;
|
|
623
|
+
}
|
|
624
|
+
if (!entry.pendingInfo) {
|
|
625
|
+
const gen = entry.gen;
|
|
626
|
+
entry.pendingInfo = _buildAuthInfo(token, hostUri).then(info => {
|
|
627
|
+
if (entry.gen !== gen) return info; // stale: a newer switch superseded this fetch
|
|
628
|
+
entry.cachedInfo = info;
|
|
629
|
+
entry.cachedToken = token;
|
|
630
|
+
entry.cachedHost = hostUri;
|
|
631
|
+
entry.pendingInfo = null;
|
|
632
|
+
try {
|
|
633
|
+
const parsed = JSON.parse(info);
|
|
634
|
+
if (parsed && parsed.authInfo &&
|
|
635
|
+
typeof parsed.authInfo.login === 'string' && parsed.authInfo.login.length > 0) {
|
|
636
|
+
_loginTokens.set(`${hostUri}:${parsed.authInfo.login}`, token);
|
|
637
|
+
}
|
|
638
|
+
} catch (_) {}
|
|
639
|
+
return info;
|
|
640
|
+
}).catch(err => {
|
|
641
|
+
if (entry.gen === gen) entry.pendingInfo = null;
|
|
642
|
+
throw err;
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return entry.pendingInfo;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
result.authManagerLoadAuthInfo = async function(uuid, env, _storeTokenPlaintext) {
|
|
649
|
+
const token = await _readGhToken(env);
|
|
650
|
+
if (!token) return null;
|
|
651
|
+
return _resolveOrCache(uuid, token, env);
|
|
652
|
+
};
|
|
653
|
+
result.authManagerGetCurrentAuthInfo = async function(uuid, env, _storeTokenPlaintext) {
|
|
654
|
+
const entry = _authMgr.get(uuid);
|
|
655
|
+
if (!entry) return null;
|
|
656
|
+
if (entry.cachedInfo !== null) return entry.cachedInfo;
|
|
657
|
+
if (entry.pendingInfo) return entry.pendingInfo;
|
|
658
|
+
const token = await _readGhToken(env);
|
|
659
|
+
if (!token) return null;
|
|
660
|
+
return _resolveOrCache(uuid, token, env);
|
|
661
|
+
};
|
|
662
|
+
result.authManagerGetAllAuthAvailable = async function(uuid, env, _storeTokenPlaintext) {
|
|
663
|
+
const token = await _readGhToken(env);
|
|
664
|
+
if (!token) return [];
|
|
665
|
+
const info = await _resolveOrCache(uuid, token, env);
|
|
666
|
+
return info ? [info] : [];
|
|
667
|
+
};
|
|
668
|
+
result.authManagerGetLastAuthErrors = function(uuid) { return []; };
|
|
669
|
+
result.authManagerClearCache = function(uuid) {
|
|
670
|
+
const e = _authMgr.get(uuid);
|
|
671
|
+
if (e) { e.gen++; e.cachedInfo = null; e.pendingInfo = null; e.cachedToken = null; e.cachedHost = null; }
|
|
672
|
+
};
|
|
673
|
+
result.authManagerSwitchToAuth = async function(uuid, authInfoJson, token) {
|
|
674
|
+
const entry = _authMgr.get(uuid);
|
|
675
|
+
if (!entry) return;
|
|
676
|
+
// Clear stale enterprise endpoint and cache regardless of token presence
|
|
677
|
+
delete process.env.COPILOT_API_URL;
|
|
678
|
+
const gen = ++entry.gen;
|
|
679
|
+
entry.cachedInfo = null;
|
|
680
|
+
entry.cachedToken = null;
|
|
681
|
+
entry.cachedHost = null;
|
|
682
|
+
entry.pendingInfo = null;
|
|
683
|
+
if (!token) return;
|
|
684
|
+
const hostUri = (() => {
|
|
685
|
+
try { return (JSON.parse(authInfoJson)?.host || 'https://github.com').replace(/\/+$/, ''); }
|
|
686
|
+
catch (_) { return 'https://github.com'; }
|
|
687
|
+
})();
|
|
688
|
+
entry.pendingInfo = _buildAuthInfo(token, hostUri).then(info => {
|
|
689
|
+
if (entry.gen !== gen) return info; // stale: a newer switch superseded this fetch
|
|
690
|
+
entry.cachedInfo = info;
|
|
691
|
+
entry.cachedToken = token;
|
|
692
|
+
entry.cachedHost = hostUri;
|
|
693
|
+
entry.pendingInfo = null;
|
|
694
|
+
return info;
|
|
695
|
+
}).catch(err => {
|
|
696
|
+
if (entry.gen === gen) entry.pendingInfo = null;
|
|
697
|
+
_dbg('authManagerSwitchToAuth:error', { err: err.message });
|
|
698
|
+
});
|
|
699
|
+
await entry.pendingInfo;
|
|
700
|
+
_dbg('authManagerSwitchToAuth:done', {
|
|
701
|
+
tokenHash: _tokenHash(token), hostUri,
|
|
702
|
+
COPILOT_API_URL_after: process.env.COPILOT_API_URL ?? null,
|
|
703
|
+
});
|
|
704
|
+
};
|
|
705
|
+
result.authManagerLoginUser = async function(uuid, host, login, token) {
|
|
706
|
+
_dbg('authManagerLoginUser:start', { host, login, tokenHash: _tokenHash(token) });
|
|
707
|
+
const entry = _authMgr.get(uuid);
|
|
708
|
+
if (!entry || !token) return;
|
|
709
|
+
const hostUri = (host || 'https://github.com').replace(/\/+$/, '');
|
|
710
|
+
_loginTokens.set(`${hostUri}:${login || ''}`, token);
|
|
711
|
+
const gen = ++entry.gen;
|
|
712
|
+
entry.pendingInfo = _buildAuthInfo(token, hostUri).then(info => {
|
|
713
|
+
if (entry.gen !== gen) return info; // stale: a newer switch superseded this fetch
|
|
714
|
+
entry.cachedInfo = info;
|
|
715
|
+
entry.cachedToken = token;
|
|
716
|
+
entry.cachedHost = hostUri;
|
|
717
|
+
entry.pendingInfo = null;
|
|
718
|
+
try {
|
|
719
|
+
const parsed = JSON.parse(info);
|
|
720
|
+
if (parsed && parsed.authInfo &&
|
|
721
|
+
typeof parsed.authInfo.login === 'string' && parsed.authInfo.login.length > 0) {
|
|
722
|
+
_loginTokens.set(`${hostUri}:${parsed.authInfo.login}`, token);
|
|
723
|
+
}
|
|
724
|
+
} catch (_) {}
|
|
725
|
+
return info;
|
|
726
|
+
}).catch(err => { if (entry.gen === gen) entry.pendingInfo = null; return null; });
|
|
727
|
+
await entry.pendingInfo; // ensure cachedInfo is set before app.js continues
|
|
728
|
+
};
|
|
729
|
+
result.authManagerLogout = async function(uuid, authInfoJson) {
|
|
730
|
+
const e = _authMgr.get(uuid);
|
|
731
|
+
if (e) { e.cachedInfo = null; e.pendingInfo = null; e.cachedToken = null; e.cachedHost = null; }
|
|
732
|
+
return true;
|
|
733
|
+
};
|
|
734
|
+
result.authManagerRefreshCopilotUser = async function(uuid) {
|
|
735
|
+
return null; // null → JS側 authInfoWithTokenPromise フォールバック
|
|
736
|
+
};
|
|
737
|
+
result.authManagerDestroy = function(uuid) { _authMgr.delete(uuid); };
|
|
738
|
+
|
|
739
|
+
result.authResolveAuthInfoFromToken = async function(token, hostUri, skipCache, userAgent) {
|
|
740
|
+
if (!token) return JSON.stringify(null);
|
|
741
|
+
let login = null;
|
|
742
|
+
try {
|
|
743
|
+
const apiHost = (hostUri || 'https://github.com').replace('://github.com', '://api.github.com');
|
|
744
|
+
const res = await globalThis.fetch(`${apiHost}/user`, {
|
|
745
|
+
headers: { Authorization: `token ${token}`, 'User-Agent': userAgent || `copilot-termux/${_pkgVersion}` },
|
|
746
|
+
signal: AbortSignal.timeout(5000),
|
|
747
|
+
});
|
|
748
|
+
if (res.ok) login = (await res.json()).login;
|
|
749
|
+
} catch (_) {}
|
|
750
|
+
const host = hostUri || 'https://github.com';
|
|
751
|
+
return JSON.stringify({ type: 'token', host, token, login, copilotUser: null });
|
|
752
|
+
};
|
|
753
|
+
// === end authManager* stubs ===
|
|
754
|
+
// === tokenStore* JS stubs (bionic: tokio ThreadsafeFunction crash) ===
|
|
755
|
+
// Verified tokens: set by authManagerLoginUser / _resolveOrCache after /user API check
|
|
756
|
+
const _loginTokens = new Map(); // "host:login" → oauthToken
|
|
757
|
+
|
|
758
|
+
const _tokStore = new Map();
|
|
759
|
+
let _tokSeq = 9e6;
|
|
760
|
+
result.tokenStoreCreate = function() { const id = ++_tokSeq; _tokStore.set(id, new Map()); return id; };
|
|
761
|
+
result.tokenStoreDestroy = function(h) { _tokStore.delete(h); };
|
|
762
|
+
result.tokenStoreGetToken = async function(h, host, login) {
|
|
763
|
+
const m = _tokStore.get(h);
|
|
764
|
+
const key = `${(host || 'https://github.com').replace(/\/+$/, '')}:${login || ''}`;
|
|
765
|
+
if (m) { const v = m.get(key); if (v != null) return v; }
|
|
766
|
+
const lt = _loginTokens.get(key);
|
|
767
|
+
if (lt != null) { if (m) m.set(key, lt); return lt; }
|
|
768
|
+
if (login) return null; // login specified: refuse unverified fallback
|
|
769
|
+
return _readGhToken(null);
|
|
770
|
+
};
|
|
771
|
+
result.tokenStoreStoreToken = function(h, token, host, login) {
|
|
772
|
+
const m = _tokStore.get(h);
|
|
773
|
+
if (m && token) m.set(`${(host || 'https://github.com').replace(/\/+$/, '')}:${login || ''}`, token);
|
|
774
|
+
};
|
|
775
|
+
result.tokenStoreRemoveToken = function(h, host, login) {
|
|
776
|
+
const m = _tokStore.get(h);
|
|
777
|
+
if (m) m.delete(`${(host || 'https://github.com').replace(/\/+$/, '')}:${login || ''}`);
|
|
778
|
+
};
|
|
779
|
+
result.tokenStoreGetAnyToken = async function(h) {
|
|
780
|
+
const m = _tokStore.get(h);
|
|
781
|
+
if (m && m.size > 0) return [...m.values()][0];
|
|
782
|
+
return _readGhToken(null);
|
|
783
|
+
};
|
|
784
|
+
result.tokenStoreStoreCurrentTokenInConfig = async function() {};
|
|
785
|
+
// === end tokenStore* stubs ===
|
|
786
|
+
|
|
787
|
+
// === urlManager* JS stubs ===
|
|
788
|
+
const _urlMgr = new Map();
|
|
789
|
+
let _urlSeq = 8e6;
|
|
790
|
+
result.urlManagerCreate = function(urls, unrestricted) {
|
|
791
|
+
const id = ++_urlSeq;
|
|
792
|
+
_urlMgr.set(id, { urls: Array.isArray(urls) ? [...urls] : [], unrestricted: !!unrestricted });
|
|
793
|
+
return id;
|
|
794
|
+
};
|
|
795
|
+
result.urlManagerAddUrl = function(h, url) { const e = _urlMgr.get(h); if (e) e.urls.push(url); };
|
|
796
|
+
result.urlManagerDispose = function(h) { _urlMgr.delete(h); };
|
|
797
|
+
result.urlManagerGetUrls = function(h) { return (_urlMgr.get(h) || {}).urls || []; };
|
|
798
|
+
result.urlManagerIsUrlAllowed = function(h, url) { return true; };
|
|
799
|
+
result.urlManagerIsUnrestrictedMode = function(h) { return true; };
|
|
800
|
+
result.urlManagerSetUnrestrictedMode = function(h, v) { const e = _urlMgr.get(h); if (e) e.unrestricted = v; };
|
|
801
|
+
// === end urlManager* stubs ===
|
|
802
|
+
|
|
803
|
+
// === pathManager* JS stubs ===
|
|
804
|
+
const _pathMgr = new Map();
|
|
805
|
+
let _pathSeq = 7e6;
|
|
806
|
+
result.pathManagerCreateRestricted = async function(dirs, primary) {
|
|
807
|
+
const id = ++_pathSeq;
|
|
808
|
+
_pathMgr.set(id, { dirs: Array.isArray(dirs) ? [...dirs] : [], primary: primary || null });
|
|
809
|
+
return id;
|
|
810
|
+
};
|
|
811
|
+
result.pathManagerCreateUnrestricted = async function(primary) {
|
|
812
|
+
const id = ++_pathSeq;
|
|
813
|
+
_pathMgr.set(id, { dirs: [], primary: primary || null });
|
|
814
|
+
return id;
|
|
815
|
+
};
|
|
816
|
+
result.pathManagerDispose = function(h) { _pathMgr.delete(h); };
|
|
817
|
+
result.pathManagerAddDirectory = function(h, dir) { const e = _pathMgr.get(h); if (e) e.dirs.push(dir); };
|
|
818
|
+
result.pathManagerGetDirectories = function(h) { return (_pathMgr.get(h) || {}).dirs || []; };
|
|
819
|
+
result.pathManagerGetPrimaryDirectory = function(h) { return (_pathMgr.get(h) || {}).primary || null; };
|
|
820
|
+
result.pathManagerIsPathWithinWorkspace = function(h, p) {
|
|
821
|
+
const e = _pathMgr.get(h);
|
|
822
|
+
if (!e || !e.primary) return true;
|
|
823
|
+
return p === e.primary || p.startsWith(e.primary + '/');
|
|
824
|
+
};
|
|
825
|
+
result.pathManagerUpdatePrimaryDirectory = function(h, dir) { const e = _pathMgr.get(h); if (e) e.primary = dir; };
|
|
826
|
+
result.pathManagerIsPathWithinAllowedDirectories = function(h, p) {
|
|
827
|
+
const e = _pathMgr.get(h);
|
|
828
|
+
if (!e || e.dirs.length === 0) return true;
|
|
829
|
+
return e.dirs.some(dir => p === dir || p.startsWith(dir + '/'));
|
|
830
|
+
};
|
|
831
|
+
// === end pathManager* stubs ===
|
|
832
|
+
|
|
833
|
+
// === telemetryQueue* JS stubs ===
|
|
834
|
+
let _telSeq = 6e6;
|
|
835
|
+
result.telemetryQueueCreate = function(name, _config) { return ++_telSeq; };
|
|
836
|
+
result.telemetryQueueDispose = function(h) {};
|
|
837
|
+
result.telemetryQueueEnqueue = function(h, event) {};
|
|
838
|
+
result.telemetryQueueSetDebugLogPayload = function(h, v) {};
|
|
839
|
+
// === end telemetryQueue* stubs ===
|
|
840
|
+
|
|
841
|
+
// === telemetryAppInsightsServiceState* JS stubs (1.0.65+: Azure AppInsights HTTP I/O → tokio SIGSEGV on bionic) ===
|
|
842
|
+
if (typeof result.telemetryAppInsightsServiceStateCreate === 'function') {
|
|
843
|
+
result.telemetryAppInsightsServiceStateCreate = function() { return ++_telSeq; };
|
|
844
|
+
result.telemetryAppInsightsServiceStateDispose = function(h) {};
|
|
845
|
+
result.telemetryAppInsightsServiceStateEnqueue = function(h, e, n, r) { return JSON.stringify({}); };
|
|
846
|
+
result.telemetryAppInsightsServiceStateAuthSucceeded = function(h, e) { return JSON.stringify({}); };
|
|
847
|
+
result.telemetryAppInsightsServiceStateLogout = function(h) { return JSON.stringify({}); };
|
|
848
|
+
}
|
|
849
|
+
// === end telemetryAppInsightsServiceState* stubs ===
|
|
850
|
+
|
|
851
|
+
// === telemetryDelegatingSender* JS stubs (1.0.65+: fire-and-forget HTTP send → tokio SIGSEGV on bionic) ===
|
|
852
|
+
if (typeof result.telemetryDelegatingSenderCreate === 'function') {
|
|
853
|
+
result.telemetryDelegatingSenderCreate = function() { return ++_telSeq; };
|
|
854
|
+
result.telemetryDelegatingSenderDispose = function(h) { return JSON.stringify({ disposeDelegate: false }); };
|
|
855
|
+
result.telemetryDelegatingSenderConfigure = function(h, hasDelegate) {
|
|
856
|
+
return JSON.stringify({ disposePreviousDelegate: false, disposeNewDelegate: false });
|
|
857
|
+
};
|
|
858
|
+
result.telemetryDelegatingSenderIsConfigured = function(h) { return false; };
|
|
859
|
+
result.telemetryDelegatingSenderRequiresDelegate = function(h) {};
|
|
860
|
+
result.telemetryDelegatingSenderSetInternalCorrelationIds = function(h, ids) {
|
|
861
|
+
return JSON.stringify({ applyToDelegate: false });
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
// === end telemetryDelegatingSender* stubs ===
|
|
865
|
+
|
|
866
|
+
// === telemetrySessionTelemetryState* JS stubs (1.0.65+) ===
|
|
867
|
+
if (typeof result.telemetrySessionTelemetryStateCreate === 'function') {
|
|
868
|
+
result.telemetrySessionTelemetryStateCreate = function(h, e) { return ++_telSeq; };
|
|
869
|
+
result.telemetrySessionTelemetryStateDispose = function(h) {};
|
|
870
|
+
result.telemetrySessionTelemetryStateSnapshot = function(h) { return JSON.stringify({ telemetryEvents: [] }); };
|
|
871
|
+
result.telemetrySessionTelemetryStateProcessSessionEvent = function(h, e, n) {
|
|
872
|
+
return JSON.stringify({ telemetryEvents: [] });
|
|
873
|
+
};
|
|
874
|
+
result.telemetrySessionTelemetryStateProcessToolsUpdated = function(h, e) {};
|
|
875
|
+
}
|
|
876
|
+
// === end telemetrySessionTelemetryState* stubs ===
|
|
877
|
+
|
|
878
|
+
// === telemetryLegacyUsageHandler* JS stubs (1.0.65+) ===
|
|
879
|
+
if (typeof result.telemetryLegacyUsageHandlerCreate === 'function') {
|
|
880
|
+
result.telemetryLegacyUsageHandlerCreate = function(h, e) { return ++_telSeq; };
|
|
881
|
+
result.telemetryLegacyUsageHandlerDispose = function(h) {};
|
|
882
|
+
result.telemetryLegacyUsageHandlerProcessEvent = function(h, e) { return JSON.stringify([]); };
|
|
883
|
+
}
|
|
884
|
+
// === end telemetryLegacyUsageHandler* stubs ===
|
|
885
|
+
|
|
886
|
+
// === permissionService* JS stubs ===
|
|
887
|
+
const _permSvc = new Map();
|
|
888
|
+
let _permSeq = 5e6;
|
|
889
|
+
result.permissionServiceCreate = function(config) {
|
|
890
|
+
const id = ++_permSeq;
|
|
891
|
+
_permSvc.set(id, { approveAll: !!(config && config.approveAllTool) });
|
|
892
|
+
return id;
|
|
893
|
+
};
|
|
894
|
+
result.permissionServiceDispose = function(h) { _permSvc.delete(h); };
|
|
895
|
+
result.permissionServiceRequest = async function(h, reqJson) {
|
|
896
|
+
return JSON.stringify({ kind: 'approved' });
|
|
897
|
+
};
|
|
898
|
+
result.permissionServiceComplete = function(h, token, ok, resultJson) {};
|
|
899
|
+
result.permissionServiceConfigure = function(h, approveAllTool, approveAllRead, approvedRules, deniedRules, pathMgr, urlMgr) {};
|
|
900
|
+
result.permissionServiceAddApprovedRules = function(h, rules) {};
|
|
901
|
+
result.permissionServiceGetApproveAllTool = function(h) { return (_permSvc.get(h) || {}).approveAll ?? false; };
|
|
902
|
+
result.permissionServiceSetApproveAllTool = function(h, v) { const e = _permSvc.get(h); if (e) e.approveAll = v; };
|
|
903
|
+
result.permissionServiceRemoveApprovedRules = function(h, rules) {};
|
|
904
|
+
result.permissionServiceCheckSamplingApproval = function(h, k) { return true; };
|
|
905
|
+
result.permissionServiceResetSessionApprovals = function(h) {};
|
|
906
|
+
result.permissionServiceAddLocationApprovedRules = function(h, rules) {};
|
|
907
|
+
result.permissionServiceRemoveLocationApprovedRules = function(h, rules) {};
|
|
908
|
+
// === end permissionService* stubs ===
|
|
909
|
+
|
|
910
|
+
// === lspManager* JS stubs ===
|
|
911
|
+
let _lspMgrSeq = 4e6;
|
|
912
|
+
result.lspManagerCreate = function() { return ++_lspMgrSeq; };
|
|
913
|
+
result.lspManagerClear = function(h) {};
|
|
914
|
+
result.lspManagerPlanForFile = function(h, file, lang, config) { return null; };
|
|
915
|
+
result.lspManagerRemoveClient = function(h, key) {};
|
|
916
|
+
result.lspManagerShutdownKeys = function(h) { return []; };
|
|
917
|
+
result.lspManagerPlanForServerId = function(h, id) { return null; };
|
|
918
|
+
result.lspManagerCachedClientCount = function(h) { return 0; };
|
|
919
|
+
result.lspManagerRelevantServerIds = function(h, file, lang) { return []; };
|
|
920
|
+
// === end lspManager* stubs ===
|
|
921
|
+
|
|
922
|
+
// === ifcEngine* JS stubs ===
|
|
923
|
+
const _ifc = new Map();
|
|
924
|
+
let _ifcSeq = 3e6;
|
|
925
|
+
result.ifcEngineCreate = function(config) { const id = ++_ifcSeq; _ifc.set(id, {}); return id; };
|
|
926
|
+
result.ifcEngineDispose = function(h) { _ifc.delete(h); };
|
|
927
|
+
result.ifcEngineToJson = function(h) { return '{}'; };
|
|
928
|
+
result.ifcEnginePreToolHook = async function(h, tool, argsJson, fetchHandler) { return { converged: true }; };
|
|
929
|
+
result.ifcEngineFetchComplete = function(h, resp) {};
|
|
930
|
+
result.ifcEngineGetContextLabel = function(h) { return null; };
|
|
931
|
+
result.ifcEngineSetContextLabel = function(h, label) {};
|
|
932
|
+
result.ifcEnginePostToolExecution = async function(h, tool, argsJson, fetchHandler) {
|
|
933
|
+
return { converged: true, applied: false, updated: false };
|
|
934
|
+
};
|
|
935
|
+
// === end ifcEngine* stubs ===
|
|
437
936
|
// --- end JS model HTTP implementation ---
|
|
438
937
|
}
|
|
938
|
+
|
|
939
|
+
// === cli-native.node stubs (1.0.64+: color scheme fns use Rust tokio → SIGSEGV on bionic) ===
|
|
940
|
+
if (typeof request === 'string' && path.basename(request) === 'cli-native.node') {
|
|
941
|
+
if (!result.__copilotTermuxCliPatched) {
|
|
942
|
+
result.__copilotTermuxCliPatched = true;
|
|
943
|
+
// Rust tokio background thread → SIGSEGV on bionic. Return null so callers
|
|
944
|
+
// fall back to "unspecified" color scheme (uses default theme).
|
|
945
|
+
if (typeof result.getColorScheme === 'function') {
|
|
946
|
+
result.getColorScheme = () => null;
|
|
947
|
+
}
|
|
948
|
+
if (typeof result.startColorSchemeListener === 'function') {
|
|
949
|
+
result.startColorSchemeListener = (_cb) => undefined;
|
|
950
|
+
}
|
|
951
|
+
if (typeof result.stopColorSchemeListener === 'function') {
|
|
952
|
+
result.stopColorSchemeListener = () => undefined;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
// === end cli-native.node stubs ===
|
|
957
|
+
|
|
439
958
|
return result;
|
|
440
959
|
};
|
|
441
960
|
|
|
442
961
|
// [Android bionic 対応] app.js の oPt() が globalThis.fetch を Rust ベースの B7 に
|
|
443
962
|
// 差し替えるのを阻止する。linuxmusl-arm64/runtime.node の Rust ネットワークスタックは
|
|
444
963
|
// bionic 上の実 I/O で動作しないため、Node.js ビルトイン fetch(動作確認済み)に固定する。
|
|
964
|
+
// GitHub OAuth token via env var or gh CLI (keychain unavailable on bionic)
|
|
965
|
+
// --- AUTH デバッグ計装 ---
|
|
966
|
+
// COPILOT_TERMUX_DEBUG_AUTH=1 を設定すると認証の各ステップを stderr に JSON で出力する。
|
|
967
|
+
// token はセキュリティのため先頭8文字のみ表示。
|
|
968
|
+
const _authDebug = process.env.COPILOT_TERMUX_DEBUG_AUTH === '1';
|
|
969
|
+
function _dbg(event, data) {
|
|
970
|
+
if (!_authDebug) return;
|
|
971
|
+
process.stderr.write('[copilot-termux-auth] ' + JSON.stringify({ event, ...data, ts: new Date().toISOString() }) + '\n');
|
|
972
|
+
}
|
|
973
|
+
function _tokenHash(t) { return t ? t.slice(0, 8) + '...' : null; }
|
|
974
|
+
// --- end 計装 ---
|
|
975
|
+
|
|
976
|
+
async function _readGhToken(env) {
|
|
977
|
+
const envToken =
|
|
978
|
+
(env && (env.GITHUB_TOKEN || env.GH_TOKEN || env.COPILOT_GITHUB_TOKEN)) ||
|
|
979
|
+
process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.COPILOT_GITHUB_TOKEN;
|
|
980
|
+
if (envToken) {
|
|
981
|
+
_dbg('readGhToken', { source: 'env', tokenHash: _tokenHash(envToken) });
|
|
982
|
+
return envToken;
|
|
983
|
+
}
|
|
984
|
+
try {
|
|
985
|
+
const { execFile } = require('child_process');
|
|
986
|
+
const ghToken = await new Promise(resolve => {
|
|
987
|
+
execFile('gh', ['auth', 'token'], { encoding: 'utf8', timeout: 5000 }, (err, stdout) => {
|
|
988
|
+
resolve(err ? null : (stdout.trim() || null));
|
|
989
|
+
});
|
|
990
|
+
});
|
|
991
|
+
_dbg('readGhToken', { source: ghToken ? 'gh-cli' : 'null', tokenHash: _tokenHash(ghToken) });
|
|
992
|
+
return ghToken;
|
|
993
|
+
} catch (_) {
|
|
994
|
+
_dbg('readGhToken', { source: 'error', tokenHash: null });
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
445
999
|
const _nativeFetch = globalThis.fetch;
|
|
446
1000
|
Object.defineProperty(globalThis, 'fetch', {
|
|
447
1001
|
configurable: true,
|
package/lib/setup.js
CHANGED
|
@@ -48,20 +48,20 @@ async function fetchWithIntegrity(url, expectedIntegrity) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async function setup() {
|
|
51
|
-
const { version, integrity } = manifest.copilot;
|
|
51
|
+
const { package: pkg = '@github/copilot-linuxmusl-arm64', version, integrity } = manifest.copilot;
|
|
52
52
|
const versionDir = path.join(CACHE_DIR, version);
|
|
53
53
|
const stagingDir = `${versionDir}.staging`;
|
|
54
54
|
|
|
55
55
|
if (fs.existsSync(path.join(versionDir, 'index.js'))) {
|
|
56
56
|
fs.rmSync(stagingDir, { recursive: true, force: true });
|
|
57
|
-
console.log(
|
|
57
|
+
console.log(`${pkg}@${version} already installed, refreshing symlink...`);
|
|
58
58
|
} else {
|
|
59
|
-
console.log(`Fetching
|
|
60
|
-
const metaBuf = await httpsGet(`${REGISTRY}
|
|
59
|
+
console.log(`Fetching ${pkg}@${version} metadata...`);
|
|
60
|
+
const metaBuf = await httpsGet(`${REGISTRY}/${pkg}/${version}`, { Accept: 'application/json' });
|
|
61
61
|
const meta = JSON.parse(metaBuf.toString());
|
|
62
62
|
const tarballUrl = meta.dist.tarball;
|
|
63
63
|
|
|
64
|
-
console.log(`Downloading
|
|
64
|
+
console.log(`Downloading ${pkg}@${version}...`);
|
|
65
65
|
const tarball = await fetchWithIntegrity(tarballUrl, integrity);
|
|
66
66
|
|
|
67
67
|
const tarballPath = path.join(CACHE_DIR, `copilot-${version}.tgz`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bash0816/copilot-termux",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.65",
|
|
4
4
|
"description": "GitHub Copilot CLI for Termux (Android aarch64)",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"readme": "README.md",
|
|
@@ -9,16 +9,39 @@
|
|
|
9
9
|
"url": "https://github.com/bash0816/Github-Copilot-Termux.git"
|
|
10
10
|
},
|
|
11
11
|
"homepage": "https://github.com/bash0816/Github-Copilot-Termux#readme",
|
|
12
|
-
"keywords": [
|
|
12
|
+
"keywords": [
|
|
13
|
+
"termux",
|
|
14
|
+
"android",
|
|
15
|
+
"github-copilot",
|
|
16
|
+
"copilot-cli",
|
|
17
|
+
"aarch64"
|
|
18
|
+
],
|
|
13
19
|
"bin": {
|
|
14
20
|
"copilot": "bin/copilot",
|
|
15
21
|
"copilot-termux": "bin/copilot-termux"
|
|
16
22
|
},
|
|
17
23
|
"scripts": {},
|
|
18
|
-
"files": [
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"lib/platform-patch.js",
|
|
27
|
+
"lib/setup.js",
|
|
28
|
+
"lib/bionic-compat.so",
|
|
29
|
+
"lib/native/pty.node",
|
|
30
|
+
"scripts/bionic-compat.c",
|
|
31
|
+
"config",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"THIRD-PARTY-NOTICES.md",
|
|
34
|
+
"THIRD-PARTY-LICENSES/",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
19
37
|
"engines": {
|
|
20
38
|
"node": ">=18"
|
|
21
39
|
},
|
|
22
|
-
"os": [
|
|
23
|
-
|
|
40
|
+
"os": [
|
|
41
|
+
"android",
|
|
42
|
+
"linux"
|
|
43
|
+
],
|
|
44
|
+
"cpu": [
|
|
45
|
+
"arm64"
|
|
46
|
+
]
|
|
24
47
|
}
|
package/scripts/bionic-compat.c
CHANGED
|
@@ -58,6 +58,7 @@ typedef float (*fn_ff)(float);
|
|
|
58
58
|
static fn_ddd _pow;
|
|
59
59
|
static fn_dd _log;
|
|
60
60
|
static fn_dd _log2;
|
|
61
|
+
static fn_dd _exp2;
|
|
61
62
|
static fn_ff _expf;
|
|
62
63
|
static fn_ff _log10f;
|
|
63
64
|
static fn_ff _sinf;
|
|
@@ -67,6 +68,7 @@ static void compat_init(void) {
|
|
|
67
68
|
_pow = (fn_ddd)dlsym(RTLD_NEXT, "pow");
|
|
68
69
|
_log = (fn_dd) dlsym(RTLD_NEXT, "log");
|
|
69
70
|
_log2 = (fn_dd) dlsym(RTLD_NEXT, "log2");
|
|
71
|
+
_exp2 = (fn_dd) dlsym(RTLD_NEXT, "exp2");
|
|
70
72
|
_expf = (fn_ff) dlsym(RTLD_NEXT, "expf");
|
|
71
73
|
_log10f = (fn_ff) dlsym(RTLD_NEXT, "log10f");
|
|
72
74
|
_sinf = (fn_ff) dlsym(RTLD_NEXT, "sinf");
|
|
@@ -77,6 +79,7 @@ static void compat_init(void) {
|
|
|
77
79
|
double pow(double x, double y) { if (!_pow) abort(); return _pow(x, y); }
|
|
78
80
|
double log(double x) { if (!_log) abort(); return _log(x); }
|
|
79
81
|
double log2(double x) { if (!_log2) abort(); return _log2(x); }
|
|
82
|
+
double exp2(double x) { if (!_exp2) abort(); return _exp2(x); }
|
|
80
83
|
float expf(float x) { if (!_expf) abort(); return _expf(x); }
|
|
81
84
|
float log10f(float x) { if (!_log10f) abort(); return _log10f(x); }
|
|
82
85
|
float sinf(float x) { if (!_sinf) abort(); return _sinf(x); }
|