@foxden-app/foxclaw 0.12.0 → 0.13.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/CHANGELOG.md +20 -0
- package/dist/antigravity/account_ui.d.ts +34 -0
- package/dist/antigravity/account_ui.js +354 -0
- package/dist/antigravity/adapter.js +1 -1
- package/dist/antigravity/auth.d.ts +4 -1
- package/dist/antigravity/auth.js +17 -5
- package/dist/antigravity/controller.d.ts +3 -108
- package/dist/antigravity/controller.js +2 -2129
- package/dist/antigravity/conversation_ui.d.ts +56 -0
- package/dist/antigravity/conversation_ui.js +509 -0
- package/dist/antigravity/ui_callbacks.d.ts +6 -0
- package/dist/antigravity/ui_callbacks.js +6 -0
- package/dist/bridge/unified_bridge.d.ts +114 -0
- package/dist/bridge/unified_bridge.js +1343 -0
- package/dist/channels/bridge_messaging_router.d.ts +8 -4
- package/dist/channels/bridge_messaging_router.js +15 -4
- package/dist/channels/telegram/telegram_messaging_port.d.ts +16 -0
- package/dist/channels/telegram/telegram_messaging_port.js +22 -2
- package/dist/channels/text_actions.d.ts +14 -0
- package/dist/channels/text_actions.js +48 -0
- package/dist/channels/weixin/weixin_channel_adapter.d.ts +3 -4
- package/dist/channels/weixin/weixin_channel_adapter.js +2 -2
- package/dist/channels/weixin/weixin_messaging_port.d.ts +16 -1
- package/dist/channels/weixin/weixin_messaging_port.js +34 -7
- package/dist/codex_app/activity.d.ts +62 -0
- package/dist/codex_app/activity.js +418 -0
- package/dist/codex_app/adapter.d.ts +2 -2
- package/dist/codex_app/adapter.js +55 -25
- package/dist/codex_app/backend_ui.d.ts +4 -0
- package/dist/codex_app/backend_ui.js +48 -0
- package/dist/codex_app/client.js +0 -12
- package/dist/controller/access.d.ts +1 -11
- package/dist/controller/access.js +1 -33
- package/dist/controller/activity.d.ts +1 -62
- package/dist/controller/activity.js +2 -418
- package/dist/controller/auth_errors.d.ts +11 -0
- package/dist/controller/auth_errors.js +124 -0
- package/dist/controller/auth_files.d.ts +13 -0
- package/dist/controller/auth_files.js +156 -0
- package/dist/controller/auth_presentation.d.ts +77 -0
- package/dist/controller/auth_presentation.js +697 -0
- package/dist/controller/auth_quota_service.d.ts +27 -0
- package/dist/controller/auth_quota_service.js +151 -0
- package/dist/controller/controller.d.ts +30 -56
- package/dist/controller/controller.js +181 -3497
- package/dist/controller/interactions.d.ts +74 -0
- package/dist/controller/interactions.js +560 -0
- package/dist/controller/local_usage_service.d.ts +19 -0
- package/dist/controller/local_usage_service.js +62 -0
- package/dist/controller/native_panel_service.d.ts +55 -0
- package/dist/controller/native_panel_service.js +214 -0
- package/dist/controller/native_panels.d.ts +61 -0
- package/dist/controller/native_panels.js +784 -0
- package/dist/controller/shared_helpers.d.ts +53 -0
- package/dist/controller/shared_helpers.js +399 -0
- package/dist/controller/state_types.d.ts +390 -0
- package/dist/controller/state_types.js +82 -0
- package/dist/controller/turn_rendering.d.ts +22 -0
- package/dist/controller/turn_rendering.js +288 -0
- package/dist/core/access.d.ts +11 -0
- package/dist/core/access.js +33 -0
- package/dist/core/attachment_files.d.ts +13 -0
- package/dist/core/attachment_files.js +180 -0
- package/dist/core/attachment_types.d.ts +22 -0
- package/dist/core/attachment_types.js +1 -0
- package/dist/core/attachments.d.ts +5 -3
- package/dist/core/attachments.js +2 -2
- package/dist/core/backend_registry.d.ts +22 -0
- package/dist/core/backend_registry.js +50 -0
- package/dist/core/backend_ui.d.ts +28 -0
- package/dist/core/backend_ui.js +1 -0
- package/dist/core/channel_events.d.ts +48 -0
- package/dist/core/channel_events.js +1 -0
- package/dist/core/channel_port.d.ts +52 -8
- package/dist/core/engine_spi.d.ts +19 -4
- package/dist/core/listener_scope.d.ts +11 -0
- package/dist/core/listener_scope.js +10 -0
- package/dist/core/message_text.d.ts +2 -0
- package/dist/core/message_text.js +28 -0
- package/dist/core/network_errors.d.ts +1 -0
- package/dist/core/network_errors.js +23 -0
- package/dist/core/orchestrator.d.ts +53 -24
- package/dist/core/orchestrator.js +855 -507
- package/dist/core/queued_engine_input.d.ts +12 -0
- package/dist/core/queued_engine_input.js +16 -0
- package/dist/core/runtime_supervisor.d.ts +19 -0
- package/dist/core/runtime_supervisor.js +45 -0
- package/dist/core/scope_operations.d.ts +7 -0
- package/dist/core/scope_operations.js +19 -0
- package/dist/core/stream_preview.js +21 -9
- package/dist/dsh/adapter.js +18 -5
- package/dist/dsh/backend.d.ts +7 -0
- package/dist/dsh/backend.js +21 -0
- package/dist/dsh/runtime.d.ts +0 -1
- package/dist/dsh/runtime.js +4 -13
- package/dist/dsh/ui.d.ts +8 -8
- package/dist/dsh/ui.js +1 -1
- package/dist/main.js +55 -43
- package/dist/opencode/adapter.js +28 -9
- package/dist/opencode/controller.js +1 -1
- package/dist/store/channel_inbox.d.ts +14 -0
- package/dist/store/channel_inbox.js +21 -0
- package/dist/store/database.d.ts +7 -3
- package/dist/store/database.js +7 -2
- package/dist/store/task_journal.d.ts +32 -0
- package/dist/store/task_journal.js +70 -0
- package/dist/telegram/api.d.ts +2 -2
- package/dist/telegram/api.js +10 -28
- package/dist/telegram/gateway.d.ts +13 -27
- package/dist/telegram/gateway.js +86 -43
- package/dist/telegram/media.d.ts +2 -34
- package/dist/telegram/media.js +1 -180
- package/dist/telegram/task_preview.d.ts +13 -0
- package/dist/telegram/task_preview.js +92 -0
- package/dist/telegram/task_result.d.ts +2 -0
- package/dist/telegram/task_result.js +12 -0
- package/dist/telegram/text.d.ts +1 -1
- package/dist/telegram/text.js +2 -27
- package/dist/types.d.ts +1 -1
- package/docs/release.md +13 -11
- package/docs/zh/architecture-review.md +106 -0
- package/docs/zh/release.md +13 -11
- package/docs/zh/telegram-experience.md +40 -0
- package/package.json +5 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readCodexLocalUsageSnapshot, readCodexLocalUsageStats, writeCodexLocalUsageSnapshot, } from '../codex_app/local_usage.js';
|
|
2
|
+
import { CODEX_LOCAL_USAGE_REFRESH_MS, CODEX_LOCAL_USAGE_SNAPSHOT_FILENAME } from './state_types.js';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export class CodexLocalUsageService {
|
|
5
|
+
config;
|
|
6
|
+
store;
|
|
7
|
+
closed = false;
|
|
8
|
+
async stop() { this.closed = true; await this.localUsageRefresh?.catch(() => { }); }
|
|
9
|
+
localUsageCache = null;
|
|
10
|
+
localUsageCacheLoaded = false;
|
|
11
|
+
localUsageRefresh = null;
|
|
12
|
+
constructor(config, store) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.store = store;
|
|
15
|
+
}
|
|
16
|
+
async readCachedCodexLocalUsageStats() {
|
|
17
|
+
if (this.localUsageCacheLoaded) {
|
|
18
|
+
return this.localUsageCache;
|
|
19
|
+
}
|
|
20
|
+
this.localUsageCache = await readCodexLocalUsageSnapshot(this.codexLocalUsageSnapshotPath());
|
|
21
|
+
this.localUsageCacheLoaded = true;
|
|
22
|
+
return this.localUsageCache;
|
|
23
|
+
}
|
|
24
|
+
async refreshCodexLocalUsageIfNeeded(snapshot) {
|
|
25
|
+
const current = snapshot === undefined ? await this.readCachedCodexLocalUsageStats() : snapshot;
|
|
26
|
+
if (this.closed)
|
|
27
|
+
return;
|
|
28
|
+
if (current && Date.now() - current.computedAtMs < CODEX_LOCAL_USAGE_REFRESH_MS) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (this.localUsageRefresh) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.localUsageRefresh = this.refreshCodexLocalUsageStats().finally(() => {
|
|
35
|
+
this.localUsageRefresh = null;
|
|
36
|
+
});
|
|
37
|
+
await this.localUsageRefresh;
|
|
38
|
+
}
|
|
39
|
+
async refreshCodexLocalUsageStats() {
|
|
40
|
+
if (this.closed)
|
|
41
|
+
return;
|
|
42
|
+
const stats = await readCodexLocalUsageStats(this.config.codexHome ?? undefined);
|
|
43
|
+
const snapshot = { computedAtMs: Date.now(), stats };
|
|
44
|
+
this.localUsageCache = snapshot;
|
|
45
|
+
this.localUsageCacheLoaded = true;
|
|
46
|
+
await writeCodexLocalUsageSnapshot(this.codexLocalUsageSnapshotPath(), snapshot);
|
|
47
|
+
if (this.closed)
|
|
48
|
+
return;
|
|
49
|
+
this.store.setBackendCumulativeTokenUsage({
|
|
50
|
+
inputTokens: stats.totals.inputTokens,
|
|
51
|
+
outputTokens: stats.totals.outputTokens,
|
|
52
|
+
cachedTokens: stats.totals.cachedInputTokens,
|
|
53
|
+
totalTokens: stats.totals.totalTokens,
|
|
54
|
+
turnsCount: stats.turns,
|
|
55
|
+
}, 'codex');
|
|
56
|
+
}
|
|
57
|
+
codexLocalUsageSnapshotPath() {
|
|
58
|
+
return path.join(path.dirname(this.config.statusPath), this.runtimeSnapshotFilename(CODEX_LOCAL_USAGE_SNAPSHOT_FILENAME));
|
|
59
|
+
}
|
|
60
|
+
invalidate() { this.localUsageCache = null; }
|
|
61
|
+
runtimeSnapshotFilename(filename) { return this.config.tgScopeBotId ? filename.replace(/\.json$/, `-${this.config.tgScopeBotId}.json`) : filename; }
|
|
62
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AppLocale, CodexSkillsListEntry } from '../types.js';
|
|
2
|
+
import type { TelegramCallbackEvent } from '../telegram/gateway.js';
|
|
3
|
+
import type { AppConfig } from '../config.js';
|
|
4
|
+
import type { BridgeStore } from '../store/database.js';
|
|
5
|
+
import type { Logger } from '../logger.js';
|
|
6
|
+
import type { CodexAppClient } from '../codex_app/client.js';
|
|
7
|
+
import type { ChannelInlineKeyboard } from '../core/channel_port.js';
|
|
8
|
+
export interface NativePanelUi {
|
|
9
|
+
sendMessage(scopeId: string, text: string, keyboard?: ChannelInlineKeyboard): Promise<number>;
|
|
10
|
+
editMessage(scopeId: string, messageId: number, text: string, keyboard?: ChannelInlineKeyboard): Promise<void>;
|
|
11
|
+
scheduleStalePanelDeletion(scopeId: string, messageId: number): void;
|
|
12
|
+
answerCallback(id: string, text: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare class CodexNativePanelService {
|
|
15
|
+
private readonly config;
|
|
16
|
+
private readonly store;
|
|
17
|
+
private readonly logger;
|
|
18
|
+
private readonly app;
|
|
19
|
+
private readonly ui;
|
|
20
|
+
constructor(config: AppConfig, store: BridgeStore, logger: Logger, app: CodexAppClient, ui: NativePanelUi);
|
|
21
|
+
handleLoadedCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
22
|
+
handleSkillsCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
23
|
+
handleSkillCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
24
|
+
handleSkillConfigCommand(scopeId: string, locale: AppLocale, args: string[], enabled: boolean): Promise<void>;
|
|
25
|
+
handleHooksCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
26
|
+
handlePluginsCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
27
|
+
handlePluginCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
28
|
+
handlePluginSkillCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
29
|
+
handleAppsCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
30
|
+
handleFeaturesCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
31
|
+
handleConfigCommand(scopeId: string, locale: AppLocale, args?: string[]): Promise<void>;
|
|
32
|
+
handleConfigToggleCallback(event: TelegramCallbackEvent, key: 'auth_auto_delete' | 'delete_tool_details', enabled: boolean, locale: AppLocale): Promise<void>;
|
|
33
|
+
setFoxClawBooleanConfig(key: 'auth_auto_delete' | 'delete_tool_details', enabled: boolean): Promise<{
|
|
34
|
+
key: 'auth_auto_delete' | 'delete_tool_details';
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
envKey: string;
|
|
37
|
+
envPath: string | null;
|
|
38
|
+
envUpdated: boolean;
|
|
39
|
+
envError: string | null;
|
|
40
|
+
}>;
|
|
41
|
+
formatConfigToggleUpdate(locale: AppLocale, update: {
|
|
42
|
+
key: 'auth_auto_delete' | 'delete_tool_details';
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
envPath: string | null;
|
|
45
|
+
envUpdated: boolean;
|
|
46
|
+
envError: string | null;
|
|
47
|
+
}): string;
|
|
48
|
+
handleRequirementsCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
49
|
+
handleProviderCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
50
|
+
handleMcpCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
51
|
+
handleMcpReloadCommand(scopeId: string, locale: AppLocale): Promise<void>;
|
|
52
|
+
handleMcpLoginCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
53
|
+
handleMcpResourceCommand(scopeId: string, locale: AppLocale, args: string[]): Promise<void>;
|
|
54
|
+
listSkillsForScope(scopeId: string, forceReload: boolean): Promise<CodexSkillsListEntry[]>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { formatLoadedThreadsMessage, formatSkillsMessage, findSkill, formatSkillDetailMessage, formatHooksMessage, formatPluginsMessage, formatPluginDetailMessage, formatPluginSkillMessage, formatAppsMessage, formatFeaturesMessage, parseConfigBooleanArg, formatConfigMessage, configKeyboard, writeEnvBoolean, formatRequirementsMessage, formatProviderMessage, formatMcpStatusMessage, formatMcpResourceMessage, } from './native_panels.js';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { toErrorMeta, formatUserError } from './shared_helpers.js';
|
|
4
|
+
export class CodexNativePanelService {
|
|
5
|
+
config;
|
|
6
|
+
store;
|
|
7
|
+
logger;
|
|
8
|
+
app;
|
|
9
|
+
ui;
|
|
10
|
+
constructor(config, store, logger, app, ui) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.store = store;
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
this.app = app;
|
|
15
|
+
this.ui = ui;
|
|
16
|
+
}
|
|
17
|
+
async handleLoadedCommand(scopeId, locale) {
|
|
18
|
+
const threadIds = await this.app.listLoadedThreads();
|
|
19
|
+
await this.ui.sendMessage(scopeId, formatLoadedThreadsMessage(locale, threadIds));
|
|
20
|
+
}
|
|
21
|
+
async handleSkillsCommand(scopeId, locale, args) {
|
|
22
|
+
const forceReload = args[0]?.toLowerCase() === 'reload';
|
|
23
|
+
const query = (forceReload ? args.slice(1) : args).join(' ').trim();
|
|
24
|
+
const entries = await this.listSkillsForScope(scopeId, forceReload);
|
|
25
|
+
await this.ui.sendMessage(scopeId, formatSkillsMessage(locale, entries, query || null, forceReload));
|
|
26
|
+
}
|
|
27
|
+
async handleSkillCommand(scopeId, locale, args) {
|
|
28
|
+
const name = args.join(' ').trim();
|
|
29
|
+
if (!name) {
|
|
30
|
+
await this.ui.sendMessage(scopeId, t(locale, 'usage_skill'));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const skill = findSkill(await this.listSkillsForScope(scopeId, false), name);
|
|
34
|
+
if (!skill) {
|
|
35
|
+
await this.ui.sendMessage(scopeId, t(locale, 'skill_not_found', { name }));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await this.ui.sendMessage(scopeId, formatSkillDetailMessage(locale, skill));
|
|
39
|
+
}
|
|
40
|
+
async handleSkillConfigCommand(scopeId, locale, args, enabled) {
|
|
41
|
+
const name = args.join(' ').trim();
|
|
42
|
+
if (!name) {
|
|
43
|
+
await this.ui.sendMessage(scopeId, enabled ? t(locale, 'usage_skill_enable') : t(locale, 'usage_skill_disable'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await this.app.writeSkillConfig({ name }, enabled);
|
|
47
|
+
await this.ui.sendMessage(scopeId, t(locale, enabled ? 'skill_enabled' : 'skill_disabled', { name }));
|
|
48
|
+
}
|
|
49
|
+
async handleHooksCommand(scopeId, locale) {
|
|
50
|
+
const binding = this.store.getBinding(scopeId);
|
|
51
|
+
const entries = await this.app.listHooks(binding?.cwd ?? this.config.defaultCwd);
|
|
52
|
+
await this.ui.sendMessage(scopeId, formatHooksMessage(locale, entries));
|
|
53
|
+
}
|
|
54
|
+
async handlePluginsCommand(scopeId, locale, args) {
|
|
55
|
+
const query = args.join(' ').trim() || null;
|
|
56
|
+
const binding = this.store.getBinding(scopeId);
|
|
57
|
+
const marketplaces = await this.app.listPlugins(binding?.cwd ?? this.config.defaultCwd);
|
|
58
|
+
await this.ui.sendMessage(scopeId, formatPluginsMessage(locale, marketplaces, query));
|
|
59
|
+
}
|
|
60
|
+
async handlePluginCommand(scopeId, locale, args) {
|
|
61
|
+
const name = args.join(' ').trim();
|
|
62
|
+
if (!name) {
|
|
63
|
+
await this.ui.sendMessage(scopeId, t(locale, 'usage_plugin'));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const plugin = await this.app.readPlugin(name);
|
|
67
|
+
if (!plugin) {
|
|
68
|
+
await this.ui.sendMessage(scopeId, t(locale, 'plugin_not_found', { name }));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
await this.ui.sendMessage(scopeId, formatPluginDetailMessage(locale, plugin));
|
|
72
|
+
}
|
|
73
|
+
async handlePluginSkillCommand(scopeId, locale, args) {
|
|
74
|
+
const [marketplace, plugin, ...skillParts] = args;
|
|
75
|
+
const skill = skillParts.join(' ').trim();
|
|
76
|
+
if (!marketplace || !plugin || !skill) {
|
|
77
|
+
await this.ui.sendMessage(scopeId, t(locale, 'usage_plugin_skill'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const contents = await this.app.readPluginSkill(marketplace, plugin, skill);
|
|
81
|
+
await this.ui.sendMessage(scopeId, formatPluginSkillMessage(locale, marketplace, plugin, skill, contents));
|
|
82
|
+
}
|
|
83
|
+
async handleAppsCommand(scopeId, locale, args) {
|
|
84
|
+
const forceRefetch = args[0]?.toLowerCase() === 'reload';
|
|
85
|
+
const binding = this.store.getBinding(scopeId);
|
|
86
|
+
const apps = await this.app.listApps(binding?.threadId ?? null, forceRefetch);
|
|
87
|
+
await this.ui.sendMessage(scopeId, formatAppsMessage(locale, apps, forceRefetch));
|
|
88
|
+
}
|
|
89
|
+
async handleFeaturesCommand(scopeId, locale) {
|
|
90
|
+
const features = await this.app.listExperimentalFeatures();
|
|
91
|
+
await this.ui.sendMessage(scopeId, formatFeaturesMessage(locale, features));
|
|
92
|
+
}
|
|
93
|
+
async handleConfigCommand(scopeId, locale, args = []) {
|
|
94
|
+
const action = args[0]?.toLowerCase() ?? '';
|
|
95
|
+
if (['auth_auto_delete', 'auth-auto-delete', 'auto_delete_needs_repair', 'auto-delete-needs-repair'].includes(action)) {
|
|
96
|
+
const enabled = parseConfigBooleanArg(args[1]);
|
|
97
|
+
if (enabled === null) {
|
|
98
|
+
await this.ui.sendMessage(scopeId, t(locale, 'config_auth_auto_delete_usage'));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const update = await this.setFoxClawBooleanConfig('auth_auto_delete', enabled);
|
|
102
|
+
const binding = this.store.getBinding(scopeId);
|
|
103
|
+
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
104
|
+
const sentMessageId = await this.ui.sendMessage(scopeId, `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`, configKeyboard(locale, this.config));
|
|
105
|
+
this.ui.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (['delete_tool_details', 'delete-tool-details', 'tool_details', 'tool-details'].includes(action)) {
|
|
109
|
+
const enabled = parseConfigBooleanArg(args[1]);
|
|
110
|
+
if (enabled === null) {
|
|
111
|
+
await this.ui.sendMessage(scopeId, t(locale, 'config_delete_tool_details_usage'));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const update = await this.setFoxClawBooleanConfig('delete_tool_details', enabled);
|
|
115
|
+
const binding = this.store.getBinding(scopeId);
|
|
116
|
+
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
117
|
+
const sentMessageId = await this.ui.sendMessage(scopeId, `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`, configKeyboard(locale, this.config));
|
|
118
|
+
this.ui.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const binding = this.store.getBinding(scopeId);
|
|
122
|
+
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
123
|
+
const sentMessageId = await this.ui.sendMessage(scopeId, formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats()), configKeyboard(locale, this.config));
|
|
124
|
+
this.ui.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
125
|
+
}
|
|
126
|
+
async handleConfigToggleCallback(event, key, enabled, locale) {
|
|
127
|
+
const update = await this.setFoxClawBooleanConfig(key, enabled);
|
|
128
|
+
await this.ui.answerCallback(event.callbackQueryId, t(locale, 'decision_recorded'));
|
|
129
|
+
const binding = this.store.getBinding(event.scopeId);
|
|
130
|
+
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
131
|
+
const message = `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`;
|
|
132
|
+
if (event.messageId !== null) {
|
|
133
|
+
await this.ui.editMessage(event.scopeId, event.messageId, message, configKeyboard(locale, this.config));
|
|
134
|
+
this.ui.scheduleStalePanelDeletion(event.scopeId, event.messageId);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const sentMessageId = await this.ui.sendMessage(event.scopeId, message, configKeyboard(locale, this.config));
|
|
138
|
+
this.ui.scheduleStalePanelDeletion(event.scopeId, sentMessageId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async setFoxClawBooleanConfig(key, enabled) {
|
|
142
|
+
const envKey = key === 'auth_auto_delete'
|
|
143
|
+
? 'AUTH_AUTO_DELETE_NEEDS_REPAIR'
|
|
144
|
+
: 'TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL';
|
|
145
|
+
if (key === 'auth_auto_delete') {
|
|
146
|
+
this.config.authAutoDeleteNeedsRepair = enabled;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this.config.telegramDeleteToolDetailsAfterFinal = enabled;
|
|
150
|
+
}
|
|
151
|
+
const envPath = this.config.envPath;
|
|
152
|
+
if (!envPath) {
|
|
153
|
+
return { key, enabled, envKey, envPath: null, envUpdated: false, envError: null };
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
await writeEnvBoolean(envPath, envKey, enabled);
|
|
157
|
+
return { key, enabled, envKey, envPath, envUpdated: true, envError: null };
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
this.logger.warn('config.env_update_failed', { key: envKey, envPath, error: toErrorMeta(error) });
|
|
161
|
+
return { key, enabled, envKey, envPath, envUpdated: false, envError: formatUserError(error) };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
formatConfigToggleUpdate(locale, update) {
|
|
165
|
+
const lines = [t(locale, update.key === 'auth_auto_delete' ? 'config_auth_auto_delete_updated' : 'config_delete_tool_details_updated', {
|
|
166
|
+
value: t(locale, update.enabled ? 'yes' : 'no'),
|
|
167
|
+
})];
|
|
168
|
+
if (update.envError) {
|
|
169
|
+
lines.push(t(locale, 'config_env_update_failed', { value: update.envPath ?? t(locale, 'unknown'), error: update.envError }));
|
|
170
|
+
}
|
|
171
|
+
return lines.join('\n');
|
|
172
|
+
}
|
|
173
|
+
async handleRequirementsCommand(scopeId, locale) {
|
|
174
|
+
const requirements = await this.app.readConfigRequirements();
|
|
175
|
+
await this.ui.sendMessage(scopeId, formatRequirementsMessage(locale, requirements));
|
|
176
|
+
}
|
|
177
|
+
async handleProviderCommand(scopeId, locale) {
|
|
178
|
+
const capabilities = await this.app.readModelProviderCapabilities();
|
|
179
|
+
await this.ui.sendMessage(scopeId, formatProviderMessage(locale, capabilities));
|
|
180
|
+
}
|
|
181
|
+
async handleMcpCommand(scopeId, locale, args) {
|
|
182
|
+
const detail = args[0]?.toLowerCase() === 'brief' ? 'toolsAndAuthOnly' : 'full';
|
|
183
|
+
const statuses = await this.app.listMcpServerStatus(detail);
|
|
184
|
+
await this.ui.sendMessage(scopeId, formatMcpStatusMessage(locale, statuses));
|
|
185
|
+
}
|
|
186
|
+
async handleMcpReloadCommand(scopeId, locale) {
|
|
187
|
+
await this.app.reloadMcpServers();
|
|
188
|
+
await this.ui.sendMessage(scopeId, t(locale, 'mcp_reload_done'));
|
|
189
|
+
}
|
|
190
|
+
async handleMcpLoginCommand(scopeId, locale, args) {
|
|
191
|
+
const name = args.join(' ').trim();
|
|
192
|
+
if (!name) {
|
|
193
|
+
await this.ui.sendMessage(scopeId, t(locale, 'usage_mcp_login'));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const url = await this.app.loginMcpServer(name);
|
|
197
|
+
await this.ui.sendMessage(scopeId, t(locale, 'mcp_login_started', { name, url: url || t(locale, 'unknown') }));
|
|
198
|
+
}
|
|
199
|
+
async handleMcpResourceCommand(scopeId, locale, args) {
|
|
200
|
+
const [server, ...uriParts] = args;
|
|
201
|
+
const uri = uriParts.join(' ').trim();
|
|
202
|
+
if (!server || !uri) {
|
|
203
|
+
await this.ui.sendMessage(scopeId, t(locale, 'usage_mcp_resource'));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const binding = this.store.getBinding(scopeId);
|
|
207
|
+
const contents = await this.app.readMcpResource(server, uri, binding?.threadId ?? null);
|
|
208
|
+
await this.ui.sendMessage(scopeId, formatMcpResourceMessage(locale, server, uri, contents));
|
|
209
|
+
}
|
|
210
|
+
async listSkillsForScope(scopeId, forceReload) {
|
|
211
|
+
const binding = this.store.getBinding(scopeId);
|
|
212
|
+
return this.app.listSkills(binding?.cwd ?? this.config.defaultCwd, forceReload);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AppLocale, CodexAppInfo, CodexConfigRequirements, CodexExperimentalFeature, CodexFuzzyFileResult, CodexHooksListEntry, CodexMcpResourceContent, CodexMcpServerStatus, CodexModelProviderCapabilities, CodexPluginDetail, CodexPluginMarketplace, CodexSkillMetadata, CodexSkillsListEntry, CodexThreadGoal, AppTurnSnapshot, ThreadGoalStatusValue } from '../types.js';
|
|
2
|
+
import type { SelfUpdateStatus } from '../update.js';
|
|
3
|
+
import type { AppConfig } from '../config.js';
|
|
4
|
+
import type { CodexAuthPoolStats } from '../store/database.js';
|
|
5
|
+
import { RichAuthCandidateRow, SelfUpdateBroadcastSummary, RemoteControlStatusState } from './state_types.js';
|
|
6
|
+
export declare function findSkill(entries: CodexSkillsListEntry[], name: string): CodexSkillMetadata | null;
|
|
7
|
+
export declare function formatSkillsMessage(locale: AppLocale, entries: CodexSkillsListEntry[], query: string | null, forceReload: boolean): string;
|
|
8
|
+
export declare function formatSkillDetailMessage(locale: AppLocale, skill: CodexSkillMetadata): string;
|
|
9
|
+
export declare function formatMcpStatusMessage(locale: AppLocale, statuses: CodexMcpServerStatus[]): string;
|
|
10
|
+
export declare function formatMcpResourceMessage(locale: AppLocale, server: string, uri: string, contents: CodexMcpResourceContent[]): string;
|
|
11
|
+
export declare function formatDiffMessage(locale: AppLocale, diff: string): string;
|
|
12
|
+
export declare function formatRichDiffMessage(locale: AppLocale, diff: string): string;
|
|
13
|
+
export declare function formatRichDemoMessage(locale: AppLocale): string;
|
|
14
|
+
export declare function formatRichDemoFallbackMessage(locale: AppLocale): string;
|
|
15
|
+
export declare function formatRichInternalMessage(title: string, text: string): string;
|
|
16
|
+
export declare function splitRichInternalSections(text: string): string[][];
|
|
17
|
+
export declare function formatRichInternalSection(lines: string[]): string;
|
|
18
|
+
export declare function formatRichInternalSectionWithoutCandidates(lines: string[]): string;
|
|
19
|
+
export declare function parseRichAuthCandidateRow(line: string): RichAuthCandidateRow | null;
|
|
20
|
+
export declare function formatRichAuthCandidateTable(rows: RichAuthCandidateRow[]): string;
|
|
21
|
+
export declare function splitRichAuthStatus(status: string): Pick<RichAuthCandidateRow, 'plan' | 'health' | 'refresh' | 'expiry' | 'risk'>;
|
|
22
|
+
export declare function formatRichAuthRisk(health: string): string;
|
|
23
|
+
export declare function parseRichAuthQuotaCell(value: string): {
|
|
24
|
+
value: string;
|
|
25
|
+
reset: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function formatRichAuthCommandCell(row: RichAuthCandidateRow): string;
|
|
28
|
+
export declare function formatRichAuthCommandLink(command: string, label: string): string;
|
|
29
|
+
export declare function parseRichInternalKeyValue(line: string): [string, string] | null;
|
|
30
|
+
export declare function formatRichInternalValue(value: string): string;
|
|
31
|
+
export declare function renderTelegramTable(headers: string[], rows: string[][]): string;
|
|
32
|
+
export declare function formatSelfUpdateVersionTransition(fromVersion: string | null | undefined, toVersion: string | null | undefined, locale: AppLocale): string;
|
|
33
|
+
export declare function formatCodexUpdateState(status: SelfUpdateStatus): string;
|
|
34
|
+
export declare function formatSelfUpdateBroadcastLine(locale: AppLocale, targetVersion: string | null, broadcast: SelfUpdateBroadcastSummary): string;
|
|
35
|
+
export declare function clipRichMessageText(value: string, limit: number): string;
|
|
36
|
+
export declare function formatLoadedThreadsMessage(locale: AppLocale, threadIds: string[]): string;
|
|
37
|
+
export declare function formatHooksMessage(locale: AppLocale, entries: CodexHooksListEntry[]): string;
|
|
38
|
+
export declare function formatPluginsMessage(locale: AppLocale, marketplaces: CodexPluginMarketplace[], query: string | null): string;
|
|
39
|
+
export declare function formatPluginDetailMessage(locale: AppLocale, plugin: CodexPluginDetail): string;
|
|
40
|
+
export declare function formatPluginSkillMessage(locale: AppLocale, marketplace: string, plugin: string, skill: string, contents: string | null): string;
|
|
41
|
+
export declare function formatAppsMessage(locale: AppLocale, apps: CodexAppInfo[], forceRefetch: boolean): string;
|
|
42
|
+
export declare function formatFeaturesMessage(locale: AppLocale, features: CodexExperimentalFeature[]): string;
|
|
43
|
+
export declare function formatConfigMessage(locale: AppLocale, result: Record<string, unknown>, appConfig: AppConfig, authPoolStats: CodexAuthPoolStats): string;
|
|
44
|
+
export declare function formatCodexApiProviderConfigLines(locale: AppLocale, appConfig: AppConfig): string[];
|
|
45
|
+
export declare function formatCodexAuthPoolSummary(locale: AppLocale, stats: CodexAuthPoolStats): string;
|
|
46
|
+
export declare function isInvalidCodexAuthDeleteReason(reason: string | null | undefined): boolean;
|
|
47
|
+
export declare function configKeyboard(locale: AppLocale, appConfig: AppConfig): Array<Array<{
|
|
48
|
+
text: string;
|
|
49
|
+
callback_data: string;
|
|
50
|
+
}>>;
|
|
51
|
+
export declare function formatDurationMs(locale: AppLocale, value: number): string;
|
|
52
|
+
export declare function parseConfigBooleanArg(value: string | undefined): boolean | null;
|
|
53
|
+
export declare function writeEnvBoolean(envPath: string, key: string, enabled: boolean): Promise<void>;
|
|
54
|
+
export declare function escapeRegExp(value: string): string;
|
|
55
|
+
export declare function formatRequirementsMessage(locale: AppLocale, requirements: CodexConfigRequirements | null): string;
|
|
56
|
+
export declare function formatProviderMessage(locale: AppLocale, capabilities: CodexModelProviderCapabilities): string;
|
|
57
|
+
export declare function formatGoalMessage(locale: AppLocale, goal: CodexThreadGoal | null, prefix?: string): string;
|
|
58
|
+
export declare function formatHistoryMessage(locale: AppLocale, threadId: string, turns: AppTurnSnapshot[]): string;
|
|
59
|
+
export declare function formatFuzzyFilesMessage(locale: AppLocale, query: string, root: string, files: CodexFuzzyFileResult[]): string;
|
|
60
|
+
export declare function formatRemoteStatusMessage(locale: AppLocale, status: RemoteControlStatusState | null): string;
|
|
61
|
+
export declare function formatGoalStatus(locale: AppLocale, status: ThreadGoalStatusValue): string;
|