@foxden-app/foxclaw 0.10.0 → 0.11.1
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 +9 -8
- package/CHANGELOG.md +43 -0
- package/dist/antigravity/adapter.d.ts +2 -1
- package/dist/antigravity/adapter.js +180 -42
- package/dist/antigravity/auth.d.ts +5 -0
- package/dist/antigravity/auth.js +37 -0
- package/dist/antigravity/client.js +8 -2
- package/dist/antigravity/controller.d.ts +10 -0
- package/dist/antigravity/controller.js +189 -28
- package/dist/antigravity/events.d.ts +1 -0
- package/dist/antigravity/events.js +29 -0
- package/dist/antigravity/runtime.d.ts +2 -0
- package/dist/antigravity/subagents.d.ts +66 -0
- package/dist/antigravity/subagents.js +459 -0
- package/dist/config.d.ts +3 -1
- package/dist/config.js +36 -29
- package/dist/controller/controller.d.ts +4 -0
- package/dist/controller/controller.js +71 -0
- package/dist/core/engine_spi.d.ts +1 -0
- package/dist/core/orchestrator.d.ts +6 -1
- package/dist/core/orchestrator.js +291 -139
- package/dist/main.js +346 -551
- package/dist/opencode/adapter.js +1 -0
- package/dist/opencode/controller.js +2 -2
- package/dist/store/database.d.ts +3 -0
- package/dist/store/database.js +33 -0
- package/dist/telegram/api.d.ts +1 -0
- package/dist/telegram/api.js +60 -12
- package/dist/telegram/bot_home.js +5 -4
- package/dist/types.d.ts +2 -0
- package/dist/update.js +17 -1
- package/package.json +1 -1
|
@@ -131,6 +131,7 @@ export class BridgeSessionCore {
|
|
|
131
131
|
pendingForceTakeovers = new Map();
|
|
132
132
|
pendingLoginScopesById = new Map();
|
|
133
133
|
pendingAuthAddsByLoginId = new Map();
|
|
134
|
+
authLoginRecoveryTimers = new Map();
|
|
134
135
|
latestTurnDiffs = new Map();
|
|
135
136
|
threadTokenUsageAlerts = new Map();
|
|
136
137
|
pendingAuthChoiceLists = new Map();
|
|
@@ -298,6 +299,9 @@ export class BridgeSessionCore {
|
|
|
298
299
|
this.pendingLoginsByScope.clear();
|
|
299
300
|
this.pendingLoginScopesById.clear();
|
|
300
301
|
this.pendingAuthAddsByLoginId.clear();
|
|
302
|
+
for (const timer of this.authLoginRecoveryTimers.values())
|
|
303
|
+
clearTimeout(timer);
|
|
304
|
+
this.authLoginRecoveryTimers.clear();
|
|
301
305
|
this.latestTurnDiffs.clear();
|
|
302
306
|
this.threadTokenUsageAlerts.clear();
|
|
303
307
|
this.pendingAuthChoiceLists.clear();
|
|
@@ -1812,6 +1816,15 @@ export class BridgeSessionCore {
|
|
|
1812
1816
|
return;
|
|
1813
1817
|
}
|
|
1814
1818
|
const pendingAuthAdd = loginId ? this.pendingAuthAddsByLoginId.get(loginId) ?? null : null;
|
|
1819
|
+
if (params?.success && pendingAuthAdd)
|
|
1820
|
+
await this.reconcileAuthLoginCredential(pendingAuthAdd);
|
|
1821
|
+
// A recovery check and the server notification may complete concurrently.
|
|
1822
|
+
if (this.pendingLoginScopesById.get(loginId) !== scopeId)
|
|
1823
|
+
return;
|
|
1824
|
+
const timer = this.authLoginRecoveryTimers.get(loginId);
|
|
1825
|
+
if (timer)
|
|
1826
|
+
clearTimeout(timer);
|
|
1827
|
+
this.authLoginRecoveryTimers.delete(loginId);
|
|
1815
1828
|
this.pendingLoginScopesById.delete(loginId);
|
|
1816
1829
|
if (this.pendingLoginsByScope.get(scopeId) === loginId) {
|
|
1817
1830
|
this.pendingLoginsByScope.delete(scopeId);
|
|
@@ -1886,6 +1899,62 @@ export class BridgeSessionCore {
|
|
|
1886
1899
|
const state = await this.listCodexAuthState();
|
|
1887
1900
|
await this.restoreAuthAfterAddFailure(state.authDir, state.authPath, record.previousTargetPath);
|
|
1888
1901
|
}
|
|
1902
|
+
scheduleAuthLoginRecovery(loginId) {
|
|
1903
|
+
const timer = setTimeout(() => {
|
|
1904
|
+
this.authLoginRecoveryTimers.delete(loginId);
|
|
1905
|
+
void this.recoverAuthLogin(loginId).catch(error => {
|
|
1906
|
+
this.logger.warn('codex.auth_login_recovery_failed', { error: toErrorMeta(error) });
|
|
1907
|
+
}).finally(() => {
|
|
1908
|
+
if (!this.stopping && this.pendingAuthAddsByLoginId.has(loginId)) {
|
|
1909
|
+
this.scheduleAuthLoginRecovery(loginId);
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
}, 5_000);
|
|
1913
|
+
timer.unref();
|
|
1914
|
+
this.authLoginRecoveryTimers.set(loginId, timer);
|
|
1915
|
+
}
|
|
1916
|
+
async recoverAuthLogin(loginId) {
|
|
1917
|
+
const record = this.pendingAuthAddsByLoginId.get(loginId);
|
|
1918
|
+
if (!record)
|
|
1919
|
+
return;
|
|
1920
|
+
if (Date.now() - record.createdAt >= 15 * 60_000) {
|
|
1921
|
+
await this.handleAccountLoginCompleted({ loginId, success: false, error: 'Device login timed out; completion was not confirmed.' });
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
await this.reconcileAuthLoginCredential(record);
|
|
1925
|
+
const metadata = await readChatGptAuthMetadata(record.path);
|
|
1926
|
+
if (!metadata || metadata.lastRefreshMs < record.createdAt
|
|
1927
|
+
|| !chatGptAuthMetadataMatchesCandidateName(record.name, metadata))
|
|
1928
|
+
return;
|
|
1929
|
+
const account = await this.app.readAccount(true);
|
|
1930
|
+
const limits = await this.app.readAccountRateLimits();
|
|
1931
|
+
if (!account || !limits || !selectCodexRateLimitSnapshot(limits)
|
|
1932
|
+
|| (metadata.email && account.email !== metadata.email))
|
|
1933
|
+
return;
|
|
1934
|
+
if (!this.pendingAuthAddsByLoginId.has(loginId))
|
|
1935
|
+
return;
|
|
1936
|
+
this.logger.info('codex.auth_login_recovered', { candidate: record.name });
|
|
1937
|
+
await this.handleAccountLoginCompleted({ loginId, success: true });
|
|
1938
|
+
}
|
|
1939
|
+
async reconcileAuthLoginCredential(record) {
|
|
1940
|
+
const authPath = path.join(this.resolveAuthDir(), 'auth.json');
|
|
1941
|
+
const [target, current] = await Promise.all([
|
|
1942
|
+
readChatGptAuthRecord(record.path), readChatGptAuthRecord(authPath),
|
|
1943
|
+
]);
|
|
1944
|
+
// Codex can replace auth.json atomically, breaking our candidate symlink.
|
|
1945
|
+
// Only adopt a newly written credential for the same account identity.
|
|
1946
|
+
if (target && current && current.lastRefreshMs >= record.createdAt
|
|
1947
|
+
&& current.quotaIdentityId === target.quotaIdentityId
|
|
1948
|
+
&& current.lastRefreshMs > target.lastRefreshMs
|
|
1949
|
+
&& chatGptAuthMetadataMatchesCandidateName(record.name, current)) {
|
|
1950
|
+
if (!this.pendingAuthAddsByLoginId.has(record.loginId))
|
|
1951
|
+
return;
|
|
1952
|
+
const temporary = `${record.path}.${process.pid}.tmp`;
|
|
1953
|
+
await fs.writeFile(temporary, current.raw, { mode: 0o600 });
|
|
1954
|
+
await fs.rename(temporary, record.path);
|
|
1955
|
+
await pointCodexAuthAtTarget(this.resolveAuthDir(), authPath, record.path);
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1889
1958
|
async restoreAuthAfterAddFailure(authDir, authPath, previousTargetPath) {
|
|
1890
1959
|
if (previousTargetPath) {
|
|
1891
1960
|
await pointCodexAuthAtTarget(authDir, authPath, previousTargetPath);
|
|
@@ -5548,6 +5617,7 @@ export class BridgeSessionCore {
|
|
|
5548
5617
|
mode: 'add',
|
|
5549
5618
|
createdAt: Date.now(),
|
|
5550
5619
|
});
|
|
5620
|
+
this.scheduleAuthLoginRecovery(login.loginId);
|
|
5551
5621
|
await this.sendMessage(scopeId, [
|
|
5552
5622
|
t(locale, 'auth_add_started', { value: candidateName }),
|
|
5553
5623
|
t(locale, 'login_device_prereq'),
|
|
@@ -5591,6 +5661,7 @@ export class BridgeSessionCore {
|
|
|
5591
5661
|
mode: 'repair',
|
|
5592
5662
|
createdAt: Date.now(),
|
|
5593
5663
|
});
|
|
5664
|
+
this.scheduleAuthLoginRecovery(login.loginId);
|
|
5594
5665
|
await this.sendMessage(scopeId, [
|
|
5595
5666
|
t(locale, 'auth_repair_started', { value: target.name }),
|
|
5596
5667
|
t(locale, 'login_device_prereq'),
|
|
@@ -47,6 +47,7 @@ export interface EngineTurnExecution {
|
|
|
47
47
|
on(event: 'result', listener: (result: EngineTurnResult) => void): void;
|
|
48
48
|
on(event: 'error', listener: (error: Error) => void): void;
|
|
49
49
|
on(event: 'exit', listener: (code: number | null) => void): void;
|
|
50
|
+
on(event: 'conversation', listener: (conversationId: string) => void): void;
|
|
50
51
|
}
|
|
51
52
|
export interface EngineTurnErrorContext {
|
|
52
53
|
error: string;
|
|
@@ -79,9 +79,14 @@ export declare class UnifiedChannelOrchestrator {
|
|
|
79
79
|
hasActiveTurn(scopeId: string): boolean;
|
|
80
80
|
sendMessage(scopeId: string, text: string, keyboard?: InlineKeyboard): Promise<number>;
|
|
81
81
|
editMessage(scopeId: string, messageId: number, text: string, keyboard?: InlineKeyboard): Promise<void>;
|
|
82
|
+
private safeDeliverChunks;
|
|
83
|
+
private safeDeliverMessage;
|
|
82
84
|
handleText(event: TelegramTextEvent): Promise<void>;
|
|
83
85
|
handleCallback(event: TelegramCallbackEvent): Promise<void>;
|
|
84
|
-
startPromptTurn(event: TelegramTextEvent, prompt: string, locale: AppLocale
|
|
86
|
+
startPromptTurn(event: TelegramTextEvent, prompt: string, locale: AppLocale, options?: {
|
|
87
|
+
reuseMessageId?: number | undefined;
|
|
88
|
+
forcedThreadId?: string | undefined;
|
|
89
|
+
}): Promise<void>;
|
|
85
90
|
private enqueuePromptTurn;
|
|
86
91
|
private drainNextQueuedTurn;
|
|
87
92
|
private executeTurn;
|