@foxden-app/foxclaw 0.7.3 → 0.10.0
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/.env.example +13 -0
- package/CHANGELOG.md +109 -0
- package/README.md +21 -1
- package/README_EN.md +21 -1
- package/dist/antigravity/adapter.d.ts +17 -0
- package/dist/antigravity/adapter.js +256 -0
- package/dist/antigravity/auth.d.ts +121 -0
- package/dist/antigravity/auth.js +896 -0
- package/dist/antigravity/client.d.ts +32 -0
- package/dist/antigravity/client.js +238 -0
- package/dist/antigravity/controller.d.ts +96 -0
- package/dist/antigravity/controller.js +1922 -0
- package/dist/antigravity/conversations.d.ts +29 -0
- package/dist/antigravity/conversations.js +289 -0
- package/dist/antigravity/events.d.ts +101 -0
- package/dist/antigravity/events.js +114 -0
- package/dist/antigravity/runtime.d.ts +47 -0
- package/dist/antigravity/runtime.js +82 -0
- package/dist/channels/telegram/telegram_channel_adapter.d.ts +10 -3
- package/dist/channels/telegram/telegram_channel_adapter.js +2 -1
- package/dist/channels/weixin/weixin_channel_adapter.d.ts +5 -1
- package/dist/codex_app/adapter.d.ts +20 -0
- package/dist/codex_app/adapter.js +213 -0
- package/dist/codex_app/client.d.ts +1 -1
- package/dist/codex_app/client.js +12 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +42 -0
- package/dist/controller/controller.d.ts +8 -5
- package/dist/controller/controller.js +38 -8
- package/dist/core/attachments.d.ts +11 -0
- package/dist/core/attachments.js +56 -0
- package/dist/core/engine_spi.d.ts +76 -0
- package/dist/core/engine_spi.js +1 -0
- package/dist/core/orchestrator.d.ts +101 -0
- package/dist/core/orchestrator.js +1404 -0
- package/dist/core/stream_preview.d.ts +29 -0
- package/dist/core/stream_preview.js +146 -0
- package/dist/core/turn_queue.d.ts +19 -0
- package/dist/core/turn_queue.js +41 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/i18n.js +49 -0
- package/dist/main.js +146 -12
- package/dist/opencode/adapter.d.ts +11 -0
- package/dist/opencode/adapter.js +168 -0
- package/dist/store/database.d.ts +41 -0
- package/dist/store/database.js +242 -43
- package/dist/store/token_usage.d.ts +23 -0
- package/dist/store/token_usage.js +61 -0
- package/dist/telegram/api.js +30 -1
- package/dist/telegram/gateway.d.ts +4 -0
- package/dist/telegram/gateway.js +11 -0
- package/dist/types.d.ts +1 -0
- package/dist/update.d.ts +6 -0
- package/dist/update.js +78 -6
- package/dist/voice/tts.js +4 -2
- package/docs/devlogs//346/212/200/346/234/257/351/200/232/350/256/257/02./347/273/237/344/270/200/351/200/232/351/201/223/350/260/203/345/272/246/345/231/250/344/270/216/345/217/257/346/217/222/346/213/224/345/274/225/346/223/216SPI/357/274/232FoxClaw/344/273/216/345/215/225/344/275/223/350/265/260/345/220/221/345/244/232Agent/345/272/225/345/272/247.md +192 -0
- package/docs/devlogs//347/254/254/344/270/200/344/272/272/347/247/260/347/211/210/02./347/257/207/344/272/214_/345/275/223/344/270/200/344/270/252/346/241/245/346/216/245/345/231/250/345/274/200/345/247/213/345/255/246/344/274/232/345/220/254/346/207/202/346/211/200/346/234/211Agent.md +45 -0
- package/package.json +2 -2
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AppLocale } from '../types.js';
|
|
2
|
+
export interface StreamPreviewState {
|
|
3
|
+
toolLines: string[];
|
|
4
|
+
accumulatedText: string;
|
|
5
|
+
isBoost?: boolean | undefined;
|
|
6
|
+
engineName?: string | undefined;
|
|
7
|
+
stepIndex?: number | undefined;
|
|
8
|
+
toolCount?: number | undefined;
|
|
9
|
+
currentTool?: string | null | undefined;
|
|
10
|
+
elapsedSeconds?: number | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface FoldedToolsSummaryOptions {
|
|
13
|
+
stepIndex?: number | undefined;
|
|
14
|
+
toolLines?: string[] | undefined;
|
|
15
|
+
toolCount?: number | undefined;
|
|
16
|
+
startTime?: number | undefined;
|
|
17
|
+
durationSeconds?: number | undefined;
|
|
18
|
+
usage?: {
|
|
19
|
+
inputTokens?: number | undefined;
|
|
20
|
+
outputTokens?: number | undefined;
|
|
21
|
+
cachedTokens?: number | undefined;
|
|
22
|
+
totalTokens?: number | undefined;
|
|
23
|
+
} | undefined;
|
|
24
|
+
locale?: AppLocale | undefined;
|
|
25
|
+
}
|
|
26
|
+
export declare function formatElapsedDuration(seconds: number, locale?: AppLocale): string;
|
|
27
|
+
export declare function buildFoldedToolsSummary(options: FoldedToolsSummaryOptions): string;
|
|
28
|
+
export declare function combineSummaryAndResponse(foldedSummary: string, responseText: string, limit?: number): string[];
|
|
29
|
+
export declare function renderStreamPreviewContent(state: StreamPreviewState): string;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { formatMetricTokenCount } from '../store/token_usage.js';
|
|
2
|
+
import { chunkTelegramMessage } from '../telegram/text.js';
|
|
3
|
+
export function formatElapsedDuration(seconds, locale = 'zh') {
|
|
4
|
+
if (!Number.isFinite(seconds) || seconds <= 0)
|
|
5
|
+
return '0s';
|
|
6
|
+
if (seconds < 60)
|
|
7
|
+
return locale === 'zh' ? `${seconds}秒` : `${seconds}s`;
|
|
8
|
+
const mins = Math.floor(seconds / 60);
|
|
9
|
+
const secs = seconds % 60;
|
|
10
|
+
if (mins < 60) {
|
|
11
|
+
return locale === 'zh'
|
|
12
|
+
? `${mins}分${secs > 0 ? `${secs}秒` : ''}`
|
|
13
|
+
: `${mins}m${secs > 0 ? ` ${secs}s` : ''}`;
|
|
14
|
+
}
|
|
15
|
+
const hours = Math.floor(mins / 60);
|
|
16
|
+
const remMins = mins % 60;
|
|
17
|
+
return locale === 'zh'
|
|
18
|
+
? `${hours}小时${remMins > 0 ? `${remMins}分` : ''}`
|
|
19
|
+
: `${hours}h${remMins > 0 ? ` ${remMins}m` : ''}`;
|
|
20
|
+
}
|
|
21
|
+
export function buildFoldedToolsSummary(options) {
|
|
22
|
+
const { stepIndex, toolLines = [], toolCount = toolLines.length, startTime, durationSeconds, usage, locale = 'zh', } = options;
|
|
23
|
+
if (toolCount === 0 && (!stepIndex || stepIndex <= 1) && !usage) {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
const roundText = stepIndex && stepIndex > 1
|
|
27
|
+
? (locale === 'zh' ? ` · 共 ${stepIndex} 轮` : ` · ${stepIndex} turns`)
|
|
28
|
+
: '';
|
|
29
|
+
const toolText = toolCount > 0
|
|
30
|
+
? (locale === 'zh' ? ` · 累计执行 ${toolCount} 次工具` : ` · ${toolCount} tools`)
|
|
31
|
+
: '';
|
|
32
|
+
let durationText = '';
|
|
33
|
+
const elapsedSec = typeof durationSeconds === 'number' && durationSeconds > 0
|
|
34
|
+
? durationSeconds
|
|
35
|
+
: startTime
|
|
36
|
+
? Math.max(1, Math.round((Date.now() - startTime) / 1000))
|
|
37
|
+
: 0;
|
|
38
|
+
if (elapsedSec > 0) {
|
|
39
|
+
durationText = locale === 'zh'
|
|
40
|
+
? ` · 耗时 ${formatElapsedDuration(elapsedSec, 'zh')}`
|
|
41
|
+
: ` · in ${formatElapsedDuration(elapsedSec, 'en')}`;
|
|
42
|
+
}
|
|
43
|
+
// Header line
|
|
44
|
+
const header = `🛠️ <b>${locale === 'zh' ? '执行小结' : 'Execution Summary'}${roundText}${toolText}${durationText}</b>`;
|
|
45
|
+
// Token line
|
|
46
|
+
let usageLine = '';
|
|
47
|
+
if (usage && (usage.totalTokens || usage.inputTokens || usage.outputTokens || usage.cachedTokens)) {
|
|
48
|
+
const totalVal = usage.totalTokens || ((usage.inputTokens || 0) + (usage.outputTokens || 0));
|
|
49
|
+
const total = formatMetricTokenCount(totalVal);
|
|
50
|
+
const input = formatMetricTokenCount(usage.inputTokens || 0);
|
|
51
|
+
const output = formatMetricTokenCount(usage.outputTokens || 0);
|
|
52
|
+
const cached = formatMetricTokenCount(usage.cachedTokens || 0);
|
|
53
|
+
if (locale === 'zh') {
|
|
54
|
+
usageLine = `\n🪙 <b>Token 消耗</b>: 总计 ${total} (输入 ${input} · 输出 ${output} · 缓存 ${cached})`;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
usageLine = `\n🪙 <b>Token Usage</b>: Total ${total} (Input ${input} · Output ${output} · Cached ${cached})`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Tool detail section:
|
|
61
|
+
// If toolLines <= 25 (e.g. 10-20 step summaries in Codex/AGY): preserve ALL of them!
|
|
62
|
+
// If toolLines > 25 (e.g. 100+ raw tool calls): keep first 3 + omitted notice + last 15.
|
|
63
|
+
let toolDetailSection = '';
|
|
64
|
+
if (toolLines.length > 0) {
|
|
65
|
+
let previewLines = [];
|
|
66
|
+
if (toolLines.length <= 25) {
|
|
67
|
+
previewLines = toolLines;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const head = toolLines.slice(0, 3);
|
|
71
|
+
const tail = toolLines.slice(-15);
|
|
72
|
+
const omitted = toolCount - (head.length + tail.length);
|
|
73
|
+
const omittedNote = omitted > 0
|
|
74
|
+
? `<i>${locale === 'zh' ? `(中间 ${omitted} 项历史工具调用已折叠收起)` : `(${omitted} intermediate tools collapsed)`}</i>`
|
|
75
|
+
: '';
|
|
76
|
+
previewLines = [...head, omittedNote, ...tail].filter(Boolean);
|
|
77
|
+
}
|
|
78
|
+
toolDetailSection = `\n\n<i>${locale === 'zh' ? '工具调用记录:' : 'Tool calls:'}</i>\n${previewLines.join('\n')}`;
|
|
79
|
+
}
|
|
80
|
+
return `<blockquote expandable>${header}${usageLine}${toolDetailSection}</blockquote>\n\n`;
|
|
81
|
+
}
|
|
82
|
+
export function combineSummaryAndResponse(foldedSummary, responseText, limit = 4000) {
|
|
83
|
+
const content = (responseText || '(无输出 / No output)').trim();
|
|
84
|
+
if (!foldedSummary) {
|
|
85
|
+
return chunkTelegramMessage(content, limit);
|
|
86
|
+
}
|
|
87
|
+
const combined = `${foldedSummary}${content}`;
|
|
88
|
+
if (combined.length <= limit) {
|
|
89
|
+
return [combined];
|
|
90
|
+
}
|
|
91
|
+
// Combined exceeds limit: chunk responseText cleanly without tearing foldedSummary apart!
|
|
92
|
+
const remainingInFirstChunk = limit - foldedSummary.length;
|
|
93
|
+
if (remainingInFirstChunk >= 300) {
|
|
94
|
+
const window = content.slice(0, remainingInFirstChunk);
|
|
95
|
+
const splitAt = Math.max(window.lastIndexOf('\n\n'), window.lastIndexOf('\n'));
|
|
96
|
+
if (splitAt >= Math.floor(remainingInFirstChunk / 3)) {
|
|
97
|
+
const firstChunkText = content.slice(0, splitAt + 1).trim();
|
|
98
|
+
const rest = content.slice(splitAt + 1).trim();
|
|
99
|
+
const restChunks = chunkTelegramMessage(rest, limit);
|
|
100
|
+
return [`${foldedSummary}${firstChunkText}`, ...restChunks];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// If foldedSummary takes up most of the message or no clean paragraph break was found,
|
|
104
|
+
// foldedSummary gets its own clean message, and responseText is chunked independently.
|
|
105
|
+
const responseChunks = chunkTelegramMessage(content, limit);
|
|
106
|
+
return [foldedSummary.trim(), ...responseChunks];
|
|
107
|
+
}
|
|
108
|
+
export function renderStreamPreviewContent(state) {
|
|
109
|
+
const parts = [];
|
|
110
|
+
const name = state.engineName || 'AI';
|
|
111
|
+
const roundText = state.stepIndex && state.stepIndex > 0 ? `第 ${state.stepIndex} 轮` : '';
|
|
112
|
+
const toolText = typeof state.toolCount === 'number' && state.toolCount > 0 ? `累计执行 ${state.toolCount} 次工具` : '';
|
|
113
|
+
const timeText = typeof state.elapsedSeconds === 'number' && state.elapsedSeconds > 0 ? `已耗时 ${state.elapsedSeconds}s` : '';
|
|
114
|
+
const meta = [roundText, toolText, timeText].filter(Boolean).join(' · ');
|
|
115
|
+
if (meta || state.currentTool || state.toolLines.length > 0) {
|
|
116
|
+
if (state.isBoost) {
|
|
117
|
+
parts.push(`🚀 <b>${name} (Boost 模式) 正在执行中</b>${meta ? ` (${meta})` : ''}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
parts.push(`🔄 <b>${name} 正在执行中</b>${meta ? ` (${meta})` : ''}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (state.currentTool) {
|
|
124
|
+
parts.push(`⚙️ <b>当前正在运行</b>: <code>${escapeTelegramHtml(state.currentTool)}</code>`);
|
|
125
|
+
parts.push('');
|
|
126
|
+
}
|
|
127
|
+
if (state.toolLines.length > 0) {
|
|
128
|
+
const recent = state.toolLines.slice(-6);
|
|
129
|
+
parts.push(`<blockquote expandable>🛠️ <b>正在调用工具 (${state.toolLines.length} 项)</b>\n${recent.join('\n')}</blockquote>`);
|
|
130
|
+
parts.push('');
|
|
131
|
+
}
|
|
132
|
+
if (state.accumulatedText) {
|
|
133
|
+
const preview = state.accumulatedText.slice(-3000);
|
|
134
|
+
parts.push(preview);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
parts.push(state.isBoost ? `🚀 ${name} (Boost 模式) 正在深度思考中…` : `⏳ ${name} 正在思考中…`);
|
|
138
|
+
}
|
|
139
|
+
return parts.join('\n');
|
|
140
|
+
}
|
|
141
|
+
function escapeTelegramHtml(value) {
|
|
142
|
+
return value
|
|
143
|
+
.replace(/&/g, '&')
|
|
144
|
+
.replace(/</g, '<')
|
|
145
|
+
.replace(/>/g, '>');
|
|
146
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type TurnMessageMode = 'steer' | 'queue';
|
|
2
|
+
export interface QueuedTurnItem<T = unknown> {
|
|
3
|
+
id: string;
|
|
4
|
+
scopeId: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
payload: T;
|
|
7
|
+
enqueuedAt: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class TurnQueueManager<T = unknown> {
|
|
10
|
+
private readonly queues;
|
|
11
|
+
private readonly activeModes;
|
|
12
|
+
getMode(scopeId: string, defaultMode?: TurnMessageMode): TurnMessageMode;
|
|
13
|
+
setMode(scopeId: string, mode: TurnMessageMode): void;
|
|
14
|
+
enqueue(scopeId: string, item: Omit<QueuedTurnItem<T>, 'id' | 'enqueuedAt'>): QueuedTurnItem<T>;
|
|
15
|
+
dequeue(scopeId: string): QueuedTurnItem<T> | undefined;
|
|
16
|
+
peek(scopeId: string): QueuedTurnItem<T> | undefined;
|
|
17
|
+
getQueueLength(scopeId: string): number;
|
|
18
|
+
clearQueue(scopeId: string): number;
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export class TurnQueueManager {
|
|
2
|
+
queues = new Map();
|
|
3
|
+
activeModes = new Map();
|
|
4
|
+
getMode(scopeId, defaultMode = 'queue') {
|
|
5
|
+
return this.activeModes.get(scopeId) ?? defaultMode;
|
|
6
|
+
}
|
|
7
|
+
setMode(scopeId, mode) {
|
|
8
|
+
this.activeModes.set(scopeId, mode);
|
|
9
|
+
}
|
|
10
|
+
enqueue(scopeId, item) {
|
|
11
|
+
const fullItem = {
|
|
12
|
+
...item,
|
|
13
|
+
id: `q_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
|
|
14
|
+
enqueuedAt: Date.now(),
|
|
15
|
+
};
|
|
16
|
+
const list = this.queues.get(scopeId) || [];
|
|
17
|
+
list.push(fullItem);
|
|
18
|
+
this.queues.set(scopeId, list);
|
|
19
|
+
return fullItem;
|
|
20
|
+
}
|
|
21
|
+
dequeue(scopeId) {
|
|
22
|
+
const list = this.queues.get(scopeId);
|
|
23
|
+
if (!list || list.length === 0)
|
|
24
|
+
return undefined;
|
|
25
|
+
const item = list.shift();
|
|
26
|
+
if (list.length === 0)
|
|
27
|
+
this.queues.delete(scopeId);
|
|
28
|
+
return item;
|
|
29
|
+
}
|
|
30
|
+
peek(scopeId) {
|
|
31
|
+
return this.queues.get(scopeId)?.[0];
|
|
32
|
+
}
|
|
33
|
+
getQueueLength(scopeId) {
|
|
34
|
+
return this.queues.get(scopeId)?.length ?? 0;
|
|
35
|
+
}
|
|
36
|
+
clearQueue(scopeId) {
|
|
37
|
+
const count = this.getQueueLength(scopeId);
|
|
38
|
+
this.queues.delete(scopeId);
|
|
39
|
+
return count;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/i18n.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ declare const MESSAGES: {
|
|
|
43
43
|
readonly usage_files: "Usage: /files <query>";
|
|
44
44
|
readonly cmd_desc_help: "Show commands";
|
|
45
45
|
readonly cmd_desc_setup: "Unified preference panel";
|
|
46
|
+
readonly cmd_desc_backend: "Switch backend engine and account";
|
|
46
47
|
readonly cmd_desc_fast: "Toggle Fast mode";
|
|
47
48
|
readonly cmd_desc_active: "Active-turn message behavior";
|
|
48
49
|
readonly cmd_desc_rich: "Telegram RichMessage demo";
|
|
@@ -783,6 +784,7 @@ declare const MESSAGES: {
|
|
|
783
784
|
readonly usage_files: "用法:/files <关键词>";
|
|
784
785
|
readonly cmd_desc_help: "查看命令";
|
|
785
786
|
readonly cmd_desc_setup: "统一偏好面板";
|
|
787
|
+
readonly cmd_desc_backend: "切换后端运行环境与账号";
|
|
786
788
|
readonly cmd_desc_fast: "切换 Fast 模式";
|
|
787
789
|
readonly cmd_desc_active: "运行中新消息处理方式";
|
|
788
790
|
readonly cmd_desc_rich: "Telegram RichMessage 演示";
|
|
@@ -1493,4 +1495,8 @@ export declare function getOpencodeTelegramCommands(locale: AppLocale): Array<{
|
|
|
1493
1495
|
command: string;
|
|
1494
1496
|
description: string;
|
|
1495
1497
|
}>;
|
|
1498
|
+
export declare function getAntigravityTelegramCommands(locale: AppLocale): Array<{
|
|
1499
|
+
command: string;
|
|
1500
|
+
description: string;
|
|
1501
|
+
}>;
|
|
1496
1502
|
export {};
|
package/dist/i18n.js
CHANGED
|
@@ -41,6 +41,7 @@ const MESSAGES = {
|
|
|
41
41
|
usage_files: 'Usage: /files <query>',
|
|
42
42
|
cmd_desc_help: 'Show commands',
|
|
43
43
|
cmd_desc_setup: 'Unified preference panel',
|
|
44
|
+
cmd_desc_backend: 'Switch backend engine and account',
|
|
44
45
|
cmd_desc_fast: 'Toggle Fast mode',
|
|
45
46
|
cmd_desc_active: 'Active-turn message behavior',
|
|
46
47
|
cmd_desc_rich: 'Telegram RichMessage demo',
|
|
@@ -781,6 +782,7 @@ const MESSAGES = {
|
|
|
781
782
|
usage_files: '用法:/files <关键词>',
|
|
782
783
|
cmd_desc_help: '查看命令',
|
|
783
784
|
cmd_desc_setup: '统一偏好面板',
|
|
785
|
+
cmd_desc_backend: '切换后端运行环境与账号',
|
|
784
786
|
cmd_desc_fast: '切换 Fast 模式',
|
|
785
787
|
cmd_desc_active: '运行中新消息处理方式',
|
|
786
788
|
cmd_desc_rich: 'Telegram RichMessage 演示',
|
|
@@ -1492,10 +1494,12 @@ export function getTelegramCommands(locale) {
|
|
|
1492
1494
|
return [
|
|
1493
1495
|
{ command: 'help', description: t(locale, 'cmd_desc_help') },
|
|
1494
1496
|
{ command: 'setup', description: t(locale, 'cmd_desc_setup') },
|
|
1497
|
+
{ command: 'backend', description: t(locale, 'cmd_desc_backend') },
|
|
1495
1498
|
{ command: 'status', description: t(locale, 'cmd_desc_status') },
|
|
1496
1499
|
{ command: 'update', description: t(locale, 'cmd_desc_update') },
|
|
1497
1500
|
{ command: 'threads', description: t(locale, 'cmd_desc_threads') },
|
|
1498
1501
|
{ command: 'auth', description: t(locale, 'cmd_desc_auth') },
|
|
1502
|
+
{ command: 'boost', description: locale === 'zh' ? '切换 Boost 深度推理模式' : 'Toggle Boost reasoning mode' },
|
|
1499
1503
|
{ command: 'fast', description: t(locale, 'cmd_desc_fast') },
|
|
1500
1504
|
{ command: 'active', description: t(locale, 'cmd_desc_active') },
|
|
1501
1505
|
{ command: 'rich', description: t(locale, 'cmd_desc_rich') },
|
|
@@ -1578,3 +1582,48 @@ export function getOpencodeTelegramCommands(locale) {
|
|
|
1578
1582
|
.map(([command, description]) => ({ command, description })),
|
|
1579
1583
|
];
|
|
1580
1584
|
}
|
|
1585
|
+
export function getAntigravityTelegramCommands(locale) {
|
|
1586
|
+
return locale === 'zh'
|
|
1587
|
+
? [
|
|
1588
|
+
{ command: 'help', description: '查看帮助' },
|
|
1589
|
+
{ command: 'setup', description: '控制面板与设置' },
|
|
1590
|
+
{ command: 'backend', description: '切换后端运行环境与账号' },
|
|
1591
|
+
{ command: 'threads', description: '查看会话列表' },
|
|
1592
|
+
{ command: 'open', description: '打开指定会话' },
|
|
1593
|
+
{ command: 'watch', description: '只读观察会话' },
|
|
1594
|
+
{ command: 'unwatch', description: '停止观察' },
|
|
1595
|
+
{ command: 'new', description: '新建会话' },
|
|
1596
|
+
{ command: 'boost', description: '切换 Boost 深度推理模式' },
|
|
1597
|
+
{ command: 'models', description: '切换模型' },
|
|
1598
|
+
{ command: 'auth', description: '账号管理与切换' },
|
|
1599
|
+
{ command: 'login', description: '网页授权登录新账号' },
|
|
1600
|
+
{ command: 'active', description: '设置运行中消息模式 (插话/排队)' },
|
|
1601
|
+
{ command: 'queue', description: '排队下一轮回复' },
|
|
1602
|
+
{ command: 'steer', description: '插话并中断当前回复' },
|
|
1603
|
+
{ command: 'effort', description: '设置思考深度' },
|
|
1604
|
+
{ command: 'status', description: '运行状态' },
|
|
1605
|
+
{ command: 'update', description: '自升级服务及后端 (Codex/AGY)' },
|
|
1606
|
+
{ command: 'interrupt', description: '打断当前任务' },
|
|
1607
|
+
]
|
|
1608
|
+
: [
|
|
1609
|
+
{ command: 'help', description: 'Show commands' },
|
|
1610
|
+
{ command: 'setup', description: 'Control panel & settings' },
|
|
1611
|
+
{ command: 'backend', description: 'Switch backend and account' },
|
|
1612
|
+
{ command: 'threads', description: 'List conversations' },
|
|
1613
|
+
{ command: 'open', description: 'Open conversation' },
|
|
1614
|
+
{ command: 'watch', description: 'Watch conversation' },
|
|
1615
|
+
{ command: 'unwatch', description: 'Stop watching' },
|
|
1616
|
+
{ command: 'new', description: 'New session' },
|
|
1617
|
+
{ command: 'boost', description: 'Toggle Boost reasoning mode' },
|
|
1618
|
+
{ command: 'models', description: 'Select model' },
|
|
1619
|
+
{ command: 'auth', description: 'Manage accounts' },
|
|
1620
|
+
{ command: 'login', description: 'Sign in new Google account' },
|
|
1621
|
+
{ command: 'active', description: 'Active-turn message mode' },
|
|
1622
|
+
{ command: 'queue', description: 'Queue next prompt' },
|
|
1623
|
+
{ command: 'steer', description: 'Interrupt and steer turn' },
|
|
1624
|
+
{ command: 'effort', description: 'Reasoning effort' },
|
|
1625
|
+
{ command: 'status', description: 'Bridge status' },
|
|
1626
|
+
{ command: 'update', description: 'Self-update service & backends' },
|
|
1627
|
+
{ command: 'interrupt', description: 'Stop active turn' },
|
|
1628
|
+
];
|
|
1629
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -7,8 +7,9 @@ import process from 'node:process';
|
|
|
7
7
|
import { createInterface } from 'node:readline/promises';
|
|
8
8
|
import { spawnSync } from 'node:child_process';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
|
-
import { APP_HOME, buildCodexApiProviderOverrides, DEFAULT_CODEX_TELEGRAM_HOME, DEFAULT_ENV_PATH, DEFAULT_LOG_PATH, DEFAULT_STATUS_PATH, getLoadedEnvPath, loadConfig, loadEnv, } from './config.js';
|
|
10
|
+
import { APP_HOME, buildCodexApiProviderOverrides, DEFAULT_CODEX_TELEGRAM_HOME, DEFAULT_ANTIGRAVITY_TELEGRAM_HOME, DEFAULT_ENV_PATH, DEFAULT_LOG_PATH, DEFAULT_STATUS_PATH, getLoadedEnvPath, loadConfig, loadEnv, } from './config.js';
|
|
11
11
|
import { createAuthRefreshNotificationAggregator, } from './auth/notifications.js';
|
|
12
|
+
import { getAntigravityTelegramCommands } from './i18n.js';
|
|
12
13
|
import { installBundledCodexSkills } from './codex_skills.js';
|
|
13
14
|
import { acquireProcessLock, LockHeldError } from './lock.js';
|
|
14
15
|
import { readRuntimeStatus, writeRuntimeStatus } from './runtime.js';
|
|
@@ -588,7 +589,7 @@ function truncateStatusLine(value, maxLength) {
|
|
|
588
589
|
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, Math.max(0, maxLength - 1))}…`;
|
|
589
590
|
}
|
|
590
591
|
async function runServeCli() {
|
|
591
|
-
const [{ BridgeMessagingRouter }, { TelegramMessagingPort }, { WeixinChannelAdapter }, { WeixinMessagingPort }, { attachIlinkRuntimeFromBridgeLogger }, { loadWeixinAccount }, { Logger }, { BridgeStore }, { TelegramGateway }, { CodexAppClient }, { BridgeSessionCore }, { TelegramChannelAdapter }, { AuthCandidateMirror }, { CrossNodeAuthSync }, { OpencodeTelegramRuntime },] = await Promise.all([
|
|
592
|
+
const [{ BridgeMessagingRouter }, { TelegramMessagingPort }, { WeixinChannelAdapter }, { WeixinMessagingPort }, { attachIlinkRuntimeFromBridgeLogger }, { loadWeixinAccount }, { Logger }, { BridgeStore }, { TelegramGateway }, { CodexAppClient }, { BridgeSessionCore }, { TelegramChannelAdapter }, { AuthCandidateMirror }, { CrossNodeAuthSync }, { OpencodeTelegramRuntime }, { AntigravityTelegramRuntime }, { UnifiedBridgeCore }, { AntigravityAppClient }, { AntigravityAuthManager },] = await Promise.all([
|
|
592
593
|
import('./channels/bridge_messaging_router.js'),
|
|
593
594
|
import('./channels/telegram/telegram_messaging_port.js'),
|
|
594
595
|
import('./channels/weixin/weixin_channel_adapter.js'),
|
|
@@ -604,6 +605,10 @@ async function runServeCli() {
|
|
|
604
605
|
import('./auth/mirror.js'),
|
|
605
606
|
import('./auth/cross_node_sync.js'),
|
|
606
607
|
import('./opencode/runtime.js'),
|
|
608
|
+
import('./antigravity/runtime.js'),
|
|
609
|
+
import('./antigravity/controller.js'),
|
|
610
|
+
import('./antigravity/client.js'),
|
|
611
|
+
import('./antigravity/auth.js'),
|
|
607
612
|
]);
|
|
608
613
|
const config = loadConfig();
|
|
609
614
|
const logger = new Logger(config.logLevel, config.logPath);
|
|
@@ -619,13 +624,70 @@ async function runServeCli() {
|
|
|
619
624
|
let activeAuthMirror = null;
|
|
620
625
|
let activeAuthSync = null;
|
|
621
626
|
let activeOpencodeRuntime = null;
|
|
627
|
+
const activeAntigravityRuntimes = [];
|
|
628
|
+
let sharedCodexApp = null;
|
|
629
|
+
let sharedAntigravityApp = null;
|
|
630
|
+
let sharedAntigravityAuth = null;
|
|
622
631
|
try {
|
|
623
632
|
store = new BridgeStore(config.storePath);
|
|
633
|
+
sharedAntigravityAuth = new AntigravityAuthManager(config.antigravityAuthDir, logger);
|
|
634
|
+
sharedAntigravityApp = new AntigravityAppClient(config.antigravityCliBin, logger);
|
|
635
|
+
if (config.codexCliBin) {
|
|
636
|
+
sharedCodexApp = new CodexAppClient(config.codexCliBin, config.codexAppLaunchCmd, config.codexAppAutolaunch, config.codexAppServerStatePath, config.codexAppServerLogPath, logger, config.codexHome ? { CODEX_HOME: config.codexHome } : null, codexApiProviderOverrides);
|
|
637
|
+
}
|
|
624
638
|
if (config.opencodeBotToken) {
|
|
625
639
|
activeOpencodeRuntime = new OpencodeTelegramRuntime(config, store, logger);
|
|
626
640
|
await activeOpencodeRuntime.start();
|
|
627
641
|
logger.info('opencode.bridge.started', activeOpencodeRuntime.getRuntimeStatus());
|
|
628
642
|
}
|
|
643
|
+
if (config.antigravityBotTokens.length > 0) {
|
|
644
|
+
for (const token of config.antigravityBotTokens) {
|
|
645
|
+
const bot = new TelegramGateway(token, config.tgAllowedUserId, config.tgAllowedChatId, config.telegramPollIntervalMs, store, logger, true, getAntigravityTelegramCommands);
|
|
646
|
+
const id = await bot.initializeIdentity();
|
|
647
|
+
const username = await bot.resolveUsername();
|
|
648
|
+
const sharedDefaultRuntime = config.antigravityDefaultRuntimeBotToken
|
|
649
|
+
? config.antigravityDefaultRuntimeBotToken === token
|
|
650
|
+
: (token === config.antigravityBotTokens[0]);
|
|
651
|
+
let home;
|
|
652
|
+
let authDir;
|
|
653
|
+
let app;
|
|
654
|
+
let auth;
|
|
655
|
+
if (sharedDefaultRuntime) {
|
|
656
|
+
home = os.homedir();
|
|
657
|
+
authDir = config.antigravityAuthDir;
|
|
658
|
+
app = sharedAntigravityApp;
|
|
659
|
+
auth = sharedAntigravityAuth;
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
home = prepareTelegramBotHome(DEFAULT_ANTIGRAVITY_TELEGRAM_HOME, id, username, null);
|
|
663
|
+
authDir = path.join(home, '.gemini', 'antigravity-cli');
|
|
664
|
+
fs.mkdirSync(authDir, { recursive: true, mode: 0o700 });
|
|
665
|
+
app = new AntigravityAppClient(config.antigravityCliBin, logger, { HOME: home });
|
|
666
|
+
auth = new AntigravityAuthManager(authDir, logger);
|
|
667
|
+
}
|
|
668
|
+
const runtimeConfig = {
|
|
669
|
+
...config,
|
|
670
|
+
antigravityBotToken: token,
|
|
671
|
+
antigravityBotTokens: [token],
|
|
672
|
+
tgScopeBotId: id,
|
|
673
|
+
antigravityAuthDir: authDir,
|
|
674
|
+
};
|
|
675
|
+
const runtime = new AntigravityTelegramRuntime(runtimeConfig, store, logger, {
|
|
676
|
+
botToken: token,
|
|
677
|
+
botId: id,
|
|
678
|
+
botUsername: username ?? undefined,
|
|
679
|
+
sharedDefaultRuntime,
|
|
680
|
+
home,
|
|
681
|
+
authDir,
|
|
682
|
+
codexApp: sharedCodexApp ?? undefined,
|
|
683
|
+
app,
|
|
684
|
+
auth,
|
|
685
|
+
});
|
|
686
|
+
await runtime.start();
|
|
687
|
+
activeAntigravityRuntimes.push(runtime);
|
|
688
|
+
logger.info('antigravity.bridge.started', runtime.getRuntimeStatus());
|
|
689
|
+
}
|
|
690
|
+
}
|
|
629
691
|
if (config.tgMultiBotMode) {
|
|
630
692
|
const seeds = [];
|
|
631
693
|
const canonicalAuthDir = config.codexAuthDir ?? config.codexHome ?? path.join(os.homedir(), '.codex');
|
|
@@ -697,6 +759,7 @@ async function runServeCli() {
|
|
|
697
759
|
statusPath: config.statusPath,
|
|
698
760
|
logPath: path.join(APP_HOME, 'logs', 'update.log'),
|
|
699
761
|
codexCliBin: config.codexCliBin,
|
|
762
|
+
agyCliBin: config.antigravityCliBin,
|
|
700
763
|
});
|
|
701
764
|
const lastSelfUpdatePath = path.join(APP_HOME, 'runtime', 'last-self-update.json');
|
|
702
765
|
let lastSelfUpdate = readSelfUpdateStatus(lastSelfUpdatePath);
|
|
@@ -743,6 +806,20 @@ async function runServeCli() {
|
|
|
743
806
|
...(weixinStatus.codexAppServer ? { codexAppServer: weixinStatus.codexAppServer } : {}),
|
|
744
807
|
},
|
|
745
808
|
} : {}),
|
|
809
|
+
...(activeAntigravityRuntimes.length > 0 ? {
|
|
810
|
+
antigravityBots: activeAntigravityRuntimes.map((runtime) => {
|
|
811
|
+
const status = runtime.getRuntimeStatus();
|
|
812
|
+
return {
|
|
813
|
+
id: runtime.id,
|
|
814
|
+
username: status.botUsername ?? runtime.botGateway.username,
|
|
815
|
+
connected: running && Boolean(status.connected),
|
|
816
|
+
activeTurns: running ? (status.activeTurns ?? 0) : 0,
|
|
817
|
+
runtimeKind: runtime.isSharedDefaultRuntime ? 'default' : 'isolated',
|
|
818
|
+
home: runtime.botHome,
|
|
819
|
+
authDir: runtime.authDirectory,
|
|
820
|
+
};
|
|
821
|
+
}),
|
|
822
|
+
} : {}),
|
|
746
823
|
authMirror: mirror.getStatus(),
|
|
747
824
|
authSync: authSync?.getStatus() ?? null,
|
|
748
825
|
authProactiveRefresh,
|
|
@@ -839,7 +916,14 @@ async function runServeCli() {
|
|
|
839
916
|
for (const seed of seeds) {
|
|
840
917
|
const telegramMessaging = new TelegramMessagingPort(seed.bot);
|
|
841
918
|
const outbound = new BridgeMessagingRouter(telegramMessaging, null);
|
|
842
|
-
const
|
|
919
|
+
const codexCore = new BridgeSessionCore(seed.config, store, logger, seed.bot, seed.app, outbound, selfUpdater, coordinator, false);
|
|
920
|
+
const core = new UnifiedBridgeCore(seed.config, store, logger, seed.bot, sharedAntigravityApp ?? undefined, sharedAntigravityAuth ?? undefined, telegramMessaging, {
|
|
921
|
+
codexApp: seed.app,
|
|
922
|
+
codexCore,
|
|
923
|
+
antigravityApp: sharedAntigravityApp ?? undefined,
|
|
924
|
+
antigravityAuth: sharedAntigravityAuth ?? undefined,
|
|
925
|
+
defaultBackendId: 'codex',
|
|
926
|
+
});
|
|
843
927
|
runtimes.push({ ...seed, core, telegram: new TelegramChannelAdapter(core) });
|
|
844
928
|
}
|
|
845
929
|
if (config.wxEnabled) {
|
|
@@ -925,8 +1009,10 @@ async function runServeCli() {
|
|
|
925
1009
|
await activeWeixinCore?.stop();
|
|
926
1010
|
await Promise.all(runtimes.map((runtime) => runtime.telegram.stop()));
|
|
927
1011
|
await activeOpencodeRuntime?.stop();
|
|
1012
|
+
await Promise.all(activeAntigravityRuntimes.map((runtime) => runtime.stop().catch(() => { })));
|
|
928
1013
|
writeAggregateStatus(false);
|
|
929
|
-
|
|
1014
|
+
const allManaged = [...managedApps, ...(sharedCodexApp ? [sharedCodexApp] : [])];
|
|
1015
|
+
await Promise.all(allManaged.map((app) => app.stop({ terminateServer: true }).catch((error) => {
|
|
930
1016
|
logger.warn('codex.app-server.stop_failed', { error: serializeError(error) });
|
|
931
1017
|
})));
|
|
932
1018
|
store?.close();
|
|
@@ -940,12 +1026,13 @@ async function runServeCli() {
|
|
|
940
1026
|
const singleCodexHome = config.codexHome ?? path.join(os.homedir(), '.codex');
|
|
941
1027
|
installBundledCodexSkills(packageRoot, singleCodexHome);
|
|
942
1028
|
const bot = new TelegramGateway(config.tgBotToken, config.tgAllowedUserId, config.tgAllowedChatId, config.telegramPollIntervalMs, store, logger);
|
|
943
|
-
const app = new CodexAppClient(config.codexCliBin, config.codexAppLaunchCmd, config.codexAppAutolaunch, config.codexAppServerStatePath, config.codexAppServerLogPath, logger, config.codexHome ? { CODEX_HOME: config.codexHome } : null, codexApiProviderOverrides);
|
|
1029
|
+
const app = sharedCodexApp ?? new CodexAppClient(config.codexCliBin, config.codexAppLaunchCmd, config.codexAppAutolaunch, config.codexAppServerStatePath, config.codexAppServerLogPath, logger, config.codexHome ? { CODEX_HOME: config.codexHome } : null, codexApiProviderOverrides);
|
|
944
1030
|
const telegramMessaging = new TelegramMessagingPort(bot);
|
|
945
1031
|
const weixinMessaging = config.wxEnabled
|
|
946
1032
|
? new WeixinMessagingPort(store, (id) => loadWeixinAccount(config.weixinAccountsDir, id))
|
|
947
1033
|
: null;
|
|
948
1034
|
const outbound = new BridgeMessagingRouter(telegramMessaging, weixinMessaging);
|
|
1035
|
+
void outbound;
|
|
949
1036
|
const selfUpdater = createSelfUpdateRuntime({
|
|
950
1037
|
entryPoint,
|
|
951
1038
|
nodePath: process.execPath,
|
|
@@ -953,10 +1040,32 @@ async function runServeCli() {
|
|
|
953
1040
|
statusPath: config.statusPath,
|
|
954
1041
|
logPath: path.join(APP_HOME, 'logs', 'update.log'),
|
|
955
1042
|
codexCliBin: config.codexCliBin,
|
|
1043
|
+
agyCliBin: config.antigravityCliBin,
|
|
956
1044
|
});
|
|
957
1045
|
let singleAuthSync = null;
|
|
958
1046
|
let singleMirror = null;
|
|
959
1047
|
let core = null;
|
|
1048
|
+
const writeSingleStatus = (running = true) => {
|
|
1049
|
+
const coreStatus = core?.getRuntimeStatus();
|
|
1050
|
+
writeRuntimeStatus(config.statusPath, {
|
|
1051
|
+
running,
|
|
1052
|
+
connected: running && Boolean(coreStatus?.connected),
|
|
1053
|
+
userAgent: coreStatus?.userAgent ?? app.getUserAgent(),
|
|
1054
|
+
codexHome: coreStatus?.codexHome ?? singleCodexHome,
|
|
1055
|
+
...(coreStatus?.codexAppServer ? { codexAppServer: coreStatus.codexAppServer } : app.getServerStatus() ? { codexAppServer: app.getServerStatus() } : {}),
|
|
1056
|
+
botUsername: coreStatus?.botUsername ?? bot.username,
|
|
1057
|
+
currentBindings: store?.countBindings() ?? 0,
|
|
1058
|
+
pendingApprovals: store?.countPendingApprovals() ?? 0,
|
|
1059
|
+
pendingUserInputs: store?.countPendingUserInputs() ?? 0,
|
|
1060
|
+
queuedTurns: store?.countQueuedTurnInputs() ?? 0,
|
|
1061
|
+
activeTurns: coreStatus?.activeTurns ?? 0,
|
|
1062
|
+
lastError: null,
|
|
1063
|
+
updatedAt: new Date().toISOString(),
|
|
1064
|
+
channels: { telegram: running, weixin: running && config.wxEnabled },
|
|
1065
|
+
authMirror: singleMirror?.getStatus() ?? null,
|
|
1066
|
+
authSync: singleAuthSync?.getStatus() ?? null,
|
|
1067
|
+
});
|
|
1068
|
+
};
|
|
960
1069
|
const singleAuthDir = config.codexAuthDir ?? config.codexHome ?? process.env.CODEX_AUTH_DIR ?? path.join(os.homedir(), '.codex');
|
|
961
1070
|
const singleLocalAuthRefreshLease = createLocalAuthRefreshLease();
|
|
962
1071
|
const singleAuthSyncLocalIdle = () => Boolean(core?.isIdleForServiceUpdate())
|
|
@@ -1009,12 +1118,9 @@ async function runServeCli() {
|
|
|
1009
1118
|
authSyncPushAll: () => singleAuthSync?.pushAll() ?? Promise.resolve({ sent: 0, skipped: 0 }),
|
|
1010
1119
|
authSyncTest: () => singleAuthSync?.testPeers() ?? Promise.resolve({ sent: 0, replied: 0, missing: [] }),
|
|
1011
1120
|
authSyncAudit: () => singleAuthSync?.auditCluster() ?? Promise.resolve(null),
|
|
1012
|
-
statusUpdated: (
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
authMirror: singleMirror?.getStatus() ?? null,
|
|
1016
|
-
authSync: singleAuthSync?.getStatus() ?? null,
|
|
1017
|
-
});
|
|
1121
|
+
statusUpdated: (_status) => {
|
|
1122
|
+
void _status;
|
|
1123
|
+
writeSingleStatus(true);
|
|
1018
1124
|
},
|
|
1019
1125
|
} : null;
|
|
1020
1126
|
if (config.authSyncEnabled) {
|
|
@@ -1038,7 +1144,15 @@ async function runServeCli() {
|
|
|
1038
1144
|
await singleMirror.initialize();
|
|
1039
1145
|
activeAuthMirror = singleMirror;
|
|
1040
1146
|
}
|
|
1041
|
-
|
|
1147
|
+
const singleOutbound = new BridgeMessagingRouter(telegramMessaging, null);
|
|
1148
|
+
const singleCodexCore = new BridgeSessionCore(config, store, logger, bot, app, singleOutbound, selfUpdater, singleCoordinator, false);
|
|
1149
|
+
core = new UnifiedBridgeCore(config, store, logger, bot, sharedAntigravityApp ?? undefined, sharedAntigravityAuth ?? undefined, telegramMessaging, {
|
|
1150
|
+
codexApp: app,
|
|
1151
|
+
codexCore: singleCodexCore,
|
|
1152
|
+
antigravityApp: sharedAntigravityApp ?? undefined,
|
|
1153
|
+
antigravityAuth: sharedAntigravityAuth ?? undefined,
|
|
1154
|
+
defaultBackendId: 'codex',
|
|
1155
|
+
});
|
|
1042
1156
|
if (config.authSyncEnabled && singleMirror) {
|
|
1043
1157
|
await bot.initializeIdentity();
|
|
1044
1158
|
singleAuthSync = new CrossNodeAuthSync(buildAuthSyncConfig(config, bot.username ? `@${bot.username}` : 'default'), logger, {
|
|
@@ -1096,6 +1210,7 @@ async function runServeCli() {
|
|
|
1096
1210
|
if (weixinAdapter) {
|
|
1097
1211
|
await weixinAdapter.start();
|
|
1098
1212
|
}
|
|
1213
|
+
writeSingleStatus(true);
|
|
1099
1214
|
logger.info('bridge.started', core.getRuntimeStatus());
|
|
1100
1215
|
const shutdown = async (signal) => {
|
|
1101
1216
|
logger.info('bridge.shutting_down', { signal });
|
|
@@ -1105,6 +1220,7 @@ async function runServeCli() {
|
|
|
1105
1220
|
await weixinAdapter?.stop();
|
|
1106
1221
|
await telegram.stop();
|
|
1107
1222
|
await activeOpencodeRuntime?.stop();
|
|
1223
|
+
await Promise.all(activeAntigravityRuntimes.map((runtime) => runtime.stop().catch(() => { })));
|
|
1108
1224
|
writeRuntimeStatus(config.statusPath, {
|
|
1109
1225
|
running: false,
|
|
1110
1226
|
connected: false,
|
|
@@ -1139,6 +1255,7 @@ async function runServeCli() {
|
|
|
1139
1255
|
await activeWeixinCore?.stop().catch(() => { });
|
|
1140
1256
|
await Promise.allSettled(activeTelegramAdapters.map((adapter) => adapter.stop()));
|
|
1141
1257
|
await activeOpencodeRuntime?.stop().catch(() => { });
|
|
1258
|
+
await Promise.allSettled(activeAntigravityRuntimes.map((runtime) => runtime.stop()));
|
|
1142
1259
|
await Promise.allSettled(managedApps.map((app) => app.stop({ terminateServer: true })));
|
|
1143
1260
|
store?.close();
|
|
1144
1261
|
processLock.release();
|
|
@@ -1833,6 +1950,23 @@ function runDoctorChecks() {
|
|
|
1833
1950
|
].map((value) => value.trim()).filter(Boolean);
|
|
1834
1951
|
checks.push(['OpenCode uses an independent Telegram bot', !codexTokens.includes(process.env.OPENCODE_BOT_TOKEN.trim())]);
|
|
1835
1952
|
}
|
|
1953
|
+
const antigravityTokens = [
|
|
1954
|
+
...(process.env.ANTIGRAVITY_BOT_TOKENS ?? '').split(','),
|
|
1955
|
+
process.env.ANTIGRAVITY_BOT_TOKEN ?? '',
|
|
1956
|
+
].map((value) => value.trim()).filter(Boolean);
|
|
1957
|
+
if (antigravityTokens.length > 0) {
|
|
1958
|
+
const configuredAgyBin = process.env.ANTIGRAVITY_CLI_BIN;
|
|
1959
|
+
checks.push(['antigravity (agy) cli available', hasConfiguredCommand(configuredAgyBin, 'agy')]);
|
|
1960
|
+
const codexTokens = [
|
|
1961
|
+
...(process.env.TG_BOT_TOKENS ?? '').split(','),
|
|
1962
|
+
process.env.TG_BOT_TOKEN ?? '',
|
|
1963
|
+
].map((value) => value.trim()).filter(Boolean);
|
|
1964
|
+
const hasConflict = antigravityTokens.some((t) => codexTokens.includes(t));
|
|
1965
|
+
checks.push(['Antigravity uses independent Telegram bot(s)', !hasConflict]);
|
|
1966
|
+
const authDir = process.env.ANTIGRAVITY_AUTH_DIR || path.join(os.homedir(), '.gemini', 'antigravity-cli');
|
|
1967
|
+
const hasAuth = fs.existsSync(path.join(authDir, 'antigravity-oauth-token'));
|
|
1968
|
+
checks.push(['antigravity oauth token available', hasAuth]);
|
|
1969
|
+
}
|
|
1836
1970
|
if (process.env.WX_ENABLED === 'true' || process.env.WX_ENABLED === '1') {
|
|
1837
1971
|
const accountsDir = process.env.WEIXIN_ACCOUNTS_DIR || path.join(APP_HOME, 'weixin', 'accounts');
|
|
1838
1972
|
let hasAccounts = false;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IEngineAdapter, EngineModel, EngineTurnRequest, EngineTurnExecution } from '../core/engine_spi.js';
|
|
2
|
+
import type { OpencodeAppClient } from './client.js';
|
|
3
|
+
export declare class OpencodeEngineAdapter implements IEngineAdapter {
|
|
4
|
+
private readonly client;
|
|
5
|
+
private readonly defaultModel?;
|
|
6
|
+
readonly id = "opencode";
|
|
7
|
+
readonly name = "OpenCode (SDK)";
|
|
8
|
+
constructor(client: OpencodeAppClient, defaultModel?: string | undefined);
|
|
9
|
+
listModels(): Promise<EngineModel[]>;
|
|
10
|
+
executeTurn(request: EngineTurnRequest): EngineTurnExecution;
|
|
11
|
+
}
|