feique 1.3.3 → 1.5.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.
Files changed (69) hide show
  1. package/README.en.md +3 -2
  2. package/README.md +3 -2
  3. package/dist/backend/claude.d.ts +2 -0
  4. package/dist/backend/claude.js +57 -54
  5. package/dist/backend/claude.js.map +1 -1
  6. package/dist/backend/codex.d.ts +2 -0
  7. package/dist/backend/codex.js +27 -0
  8. package/dist/backend/codex.js.map +1 -1
  9. package/dist/backend/factory.d.ts +43 -0
  10. package/dist/backend/factory.js +109 -29
  11. package/dist/backend/factory.js.map +1 -1
  12. package/dist/backend/probe.d.ts +27 -0
  13. package/dist/backend/probe.js +85 -0
  14. package/dist/backend/probe.js.map +1 -0
  15. package/dist/backend/qwen.d.ts +59 -0
  16. package/dist/backend/qwen.js +372 -0
  17. package/dist/backend/qwen.js.map +1 -0
  18. package/dist/backend/registry.d.ts +58 -0
  19. package/dist/backend/registry.js +23 -0
  20. package/dist/backend/registry.js.map +1 -0
  21. package/dist/backend/types.d.ts +6 -1
  22. package/dist/bridge/admin-config.d.ts +47 -0
  23. package/dist/bridge/admin-config.js +141 -0
  24. package/dist/bridge/admin-config.js.map +1 -0
  25. package/dist/bridge/collab-commands.d.ts +42 -0
  26. package/dist/bridge/collab-commands.js +254 -0
  27. package/dist/bridge/collab-commands.js.map +1 -0
  28. package/dist/bridge/commands.d.ts +1 -1
  29. package/dist/bridge/commands.js +10 -6
  30. package/dist/bridge/commands.js.map +1 -1
  31. package/dist/bridge/feishu-commands.d.ts +27 -0
  32. package/dist/bridge/feishu-commands.js +462 -0
  33. package/dist/bridge/feishu-commands.js.map +1 -0
  34. package/dist/bridge/intent-classifier.d.ts +7 -2
  35. package/dist/bridge/intent-classifier.js +1 -1
  36. package/dist/bridge/intent-classifier.js.map +1 -1
  37. package/dist/bridge/lifecycle.d.ts +46 -0
  38. package/dist/bridge/lifecycle.js +228 -0
  39. package/dist/bridge/lifecycle.js.map +1 -0
  40. package/dist/bridge/memory-commands.d.ts +26 -0
  41. package/dist/bridge/memory-commands.js +330 -0
  42. package/dist/bridge/memory-commands.js.map +1 -0
  43. package/dist/bridge/reply-builders.d.ts +30 -0
  44. package/dist/bridge/reply-builders.js +72 -0
  45. package/dist/bridge/reply-builders.js.map +1 -0
  46. package/dist/bridge/run-pipeline.d.ts +86 -0
  47. package/dist/bridge/run-pipeline.js +453 -0
  48. package/dist/bridge/run-pipeline.js.map +1 -0
  49. package/dist/bridge/run-scheduler.d.ts +47 -0
  50. package/dist/bridge/run-scheduler.js +121 -0
  51. package/dist/bridge/run-scheduler.js.map +1 -0
  52. package/dist/bridge/service-utils.d.ts +47 -0
  53. package/dist/bridge/service-utils.js +309 -0
  54. package/dist/bridge/service-utils.js.map +1 -0
  55. package/dist/bridge/service.d.ts +114 -66
  56. package/dist/bridge/service.js +230 -2199
  57. package/dist/bridge/service.js.map +1 -1
  58. package/dist/config/load.js +1 -1
  59. package/dist/config/load.js.map +1 -1
  60. package/dist/config/paths.js +1 -20
  61. package/dist/config/paths.js.map +1 -1
  62. package/dist/config/schema.d.ts +50 -16
  63. package/dist/config/schema.js +41 -2
  64. package/dist/config/schema.js.map +1 -1
  65. package/dist/feishu/long-connection.js +1 -0
  66. package/dist/feishu/long-connection.js.map +1 -1
  67. package/dist/feishu/webhook.js +1 -0
  68. package/dist/feishu/webhook.js.map +1 -1
  69. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-scheduler.js","sourceRoot":"","sources":["../../src/bridge/run-scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { BridgeConfig } from '../config/schema.js';
2
+ import type { IncomingCardActionContext, IncomingMessageContext } from './types.js';
3
+ import { type ConversationState } from '../state/session-store.js';
4
+ import type { RunState } from '../state/run-state-store.js';
5
+ export declare function buildQueueKey(conversationKey: string, projectAlias: string): string;
6
+ export declare function buildProjectRootQueueKey(projectRoot: string): string;
7
+ export declare function isExecutionRunStatus(status: RunState['status']): boolean;
8
+ export declare function isVisibleRunStatus(status: RunState['status']): boolean;
9
+ export declare function mapRunStatusToPhase(status: RunState['status']): string;
10
+ export declare function buildMessageDedupeKey(context: IncomingMessageContext): string;
11
+ export declare function buildCardDedupeKey(context: IncomingCardActionContext, action: string): string | null;
12
+ /**
13
+ * Extract [SEND_FILE:/path/to/file] markers from AI response text.
14
+ * Returns cleaned text (markers removed) and list of file paths.
15
+ */
16
+ export declare function extractFileMarkers(text: string): {
17
+ cleanText: string;
18
+ filePaths: string[];
19
+ };
20
+ /**
21
+ * Shallow diff two BridgeConfig objects, returning human-readable change descriptions.
22
+ */
23
+ export declare function diffConfigs(oldConfig: BridgeConfig, newConfig: BridgeConfig): string[];
24
+ export declare function truncateExcerpt(text: string, limit?: number): string;
25
+ /** Map raw error strings to user-friendly Chinese messages. */
26
+ export declare function friendlyErrorMessage(error: string): string;
27
+ export declare function splitCommaSeparatedValues(value: string): string[];
28
+ export declare function resolveAdminListTarget(resource: 'viewer' | 'operator' | 'admin' | 'service-observer' | 'service-restart' | 'config-admin' | 'group' | 'chat'): {
29
+ section: 'security' | 'feishu';
30
+ key: string;
31
+ };
32
+ export declare function buildConversationKeyForConversation(conversation: ConversationState): string;
33
+ export declare function renderMemorySection(title: string, items: Array<{
34
+ title: string;
35
+ content: string;
36
+ pinned?: boolean;
37
+ }>, budget: number): string[];
38
+ export declare function formatAgeFromNow(isoTimestamp: string): string;
39
+ export declare function parseJsonObject(input: string): Record<string, unknown>;
40
+ export declare function clampListLimit(input: string | undefined, fallback: number, max: number): number;
41
+ export declare function replaceObject(target: Record<string, unknown>, next: Record<string, unknown>): void;
42
+ export declare function replaceProjects(target: BridgeConfig['projects'], next: BridgeConfig['projects']): void;
43
+ export declare function createDeferred<T>(): {
44
+ promise: Promise<T>;
45
+ resolve: (value: T) => void;
46
+ reject: (error: unknown) => void;
47
+ };
@@ -0,0 +1,309 @@
1
+ import path from 'node:path';
2
+ import { buildConversationKey } from '../state/session-store.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Queue keys
5
+ // ---------------------------------------------------------------------------
6
+ export function buildQueueKey(conversationKey, projectAlias) {
7
+ return `${conversationKey}::project::${projectAlias}`;
8
+ }
9
+ export function buildProjectRootQueueKey(projectRoot) {
10
+ return `root::${path.resolve(projectRoot)}`;
11
+ }
12
+ // ---------------------------------------------------------------------------
13
+ // Run status helpers
14
+ // ---------------------------------------------------------------------------
15
+ export function isExecutionRunStatus(status) {
16
+ return status === 'running' || status === 'orphaned';
17
+ }
18
+ export function isVisibleRunStatus(status) {
19
+ return status === 'queued' || isExecutionRunStatus(status);
20
+ }
21
+ export function mapRunStatusToPhase(status) {
22
+ switch (status) {
23
+ case 'queued':
24
+ return '排队中';
25
+ case 'running':
26
+ return '执行中';
27
+ case 'success':
28
+ return '已完成';
29
+ case 'failure':
30
+ return '失败';
31
+ case 'cancelled':
32
+ return '已取消';
33
+ case 'stale':
34
+ return '中断';
35
+ case 'orphaned':
36
+ return '恢复中';
37
+ default:
38
+ return status;
39
+ }
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // Idempotency dedupe keys
43
+ // ---------------------------------------------------------------------------
44
+ export function buildMessageDedupeKey(context) {
45
+ return ['message', context.tenant_key ?? 'tenant', context.chat_id, context.message_id].join('::');
46
+ }
47
+ export function buildCardDedupeKey(context, action) {
48
+ if (!context.open_message_id) {
49
+ return null;
50
+ }
51
+ return ['card', context.tenant_key ?? 'tenant', context.chat_id ?? 'chat', context.actor_id ?? 'actor', context.open_message_id, action].join('::');
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // File send markers in AI response text
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Extract [SEND_FILE:/path/to/file] markers from AI response text.
58
+ * Returns cleaned text (markers removed) and list of file paths.
59
+ */
60
+ export function extractFileMarkers(text) {
61
+ const FILE_MARKER_RE = /\[SEND_FILE:([^\]]+)\]/g;
62
+ const filePaths = [];
63
+ for (const match of text.matchAll(FILE_MARKER_RE)) {
64
+ const filePath = match[1]?.trim();
65
+ if (filePath) {
66
+ filePaths.push(filePath);
67
+ }
68
+ }
69
+ const cleanText = text.replace(FILE_MARKER_RE, '').replace(/\n{3,}/g, '\n\n').trim();
70
+ return { cleanText, filePaths };
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Config diff for hot reload notifications
74
+ // ---------------------------------------------------------------------------
75
+ /**
76
+ * Shallow diff two BridgeConfig objects, returning human-readable change descriptions.
77
+ */
78
+ export function diffConfigs(oldConfig, newConfig) {
79
+ const changes = [];
80
+ // Projects added/removed
81
+ const oldProjects = new Set(Object.keys(oldConfig.projects));
82
+ const newProjects = new Set(Object.keys(newConfig.projects));
83
+ for (const p of newProjects) {
84
+ if (!oldProjects.has(p))
85
+ changes.push(`项目新增: ${p}`);
86
+ }
87
+ for (const p of oldProjects) {
88
+ if (!newProjects.has(p))
89
+ changes.push(`项目移除: ${p}`);
90
+ }
91
+ // Project-level changes
92
+ for (const alias of newProjects) {
93
+ if (!oldProjects.has(alias))
94
+ continue;
95
+ const oldP = oldConfig.projects[alias];
96
+ const newP = newConfig.projects[alias];
97
+ if (!oldP || !newP)
98
+ continue;
99
+ const fields = ['root', 'backend', 'persona', 'codex_model', 'claude_model', 'mention_required', 'description', 'session_scope'];
100
+ for (const f of fields) {
101
+ const ov = String(oldP[f] ?? '');
102
+ const nv = String(newP[f] ?? '');
103
+ if (ov !== nv)
104
+ changes.push(`${alias}.${f}: ${ov || '(空)'} → ${nv || '(空)'}`);
105
+ }
106
+ // Array fields
107
+ const arrayFields = ['skills', 'admin_chat_ids', 'operator_chat_ids', 'notification_chat_ids'];
108
+ for (const f of arrayFields) {
109
+ const ov = JSON.stringify(oldP[f] ?? []);
110
+ const nv = JSON.stringify(newP[f] ?? []);
111
+ if (ov !== nv)
112
+ changes.push(`${alias}.${f} 变更`);
113
+ }
114
+ }
115
+ // Service-level changes
116
+ const serviceFields = ['default_project', 'reply_mode', 'persona', 'team_digest_enabled', 'intent_classifier_enabled'];
117
+ for (const f of serviceFields) {
118
+ const ov = String(oldConfig.service[f] ?? '');
119
+ const nv = String(newConfig.service[f] ?? '');
120
+ if (ov !== nv)
121
+ changes.push(`service.${f}: ${ov || '(空)'} → ${nv || '(空)'}`);
122
+ }
123
+ // Backend default
124
+ if (oldConfig.backend?.default !== newConfig.backend?.default) {
125
+ changes.push(`backend.default: ${oldConfig.backend?.default ?? 'codex'} → ${newConfig.backend?.default ?? 'codex'}`);
126
+ }
127
+ // Security admin changes
128
+ if (JSON.stringify(oldConfig.security.admin_chat_ids) !== JSON.stringify(newConfig.security.admin_chat_ids)) {
129
+ changes.push('security.admin_chat_ids 变更');
130
+ }
131
+ // Embedding provider
132
+ if (oldConfig.embedding.provider !== newConfig.embedding.provider) {
133
+ changes.push(`embedding.provider: ${oldConfig.embedding.provider} → ${newConfig.embedding.provider}`);
134
+ }
135
+ if (oldConfig.embedding.ollama_model !== newConfig.embedding.ollama_model) {
136
+ changes.push(`embedding.ollama_model: ${oldConfig.embedding.ollama_model} → ${newConfig.embedding.ollama_model}`);
137
+ }
138
+ return changes;
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Text helpers
142
+ // ---------------------------------------------------------------------------
143
+ export function truncateExcerpt(text, limit = 160) {
144
+ return text.length > limit ? `${text.slice(0, limit)}...` : text;
145
+ }
146
+ /** Map raw error strings to user-friendly Chinese messages. */
147
+ export function friendlyErrorMessage(error) {
148
+ const lower = error.toLowerCase();
149
+ if (lower.includes('econnrefused') || lower.includes('enotfound') || lower.includes('econnreset')) {
150
+ return '网络连接失败,请检查网络或稍后重试';
151
+ }
152
+ if (lower.includes('enoent') || lower.includes('enotdir')) {
153
+ return '文件路径不存在,请检查项目配置';
154
+ }
155
+ if (lower.includes('permission denied') || lower.includes('eacces')) {
156
+ return '权限不足,请检查文件权限';
157
+ }
158
+ if (lower.includes('timeout') || lower.includes('timed out') || lower.includes('etimedout')) {
159
+ return '执行超时,请尝试拆分为更小的任务';
160
+ }
161
+ if (lower.includes('rate limit') || lower.includes('429') || lower.includes('too many requests')) {
162
+ return 'API 频率限制,请稍后重试';
163
+ }
164
+ if (lower.includes('enomem') || lower.includes('out of memory')) {
165
+ return '内存不足,请关闭其他程序或减少并发任务';
166
+ }
167
+ // Default: show a truncated version of the raw error
168
+ const truncated = error.length > 100 ? error.slice(0, 100) + '...' : error;
169
+ return `执行异常: ${truncated}。如需帮助请联系管理员。`;
170
+ }
171
+ export function splitCommaSeparatedValues(value) {
172
+ return value
173
+ .split(',')
174
+ .map((item) => item.trim())
175
+ .filter(Boolean);
176
+ }
177
+ // ---------------------------------------------------------------------------
178
+ // Admin list resolution
179
+ // ---------------------------------------------------------------------------
180
+ export function resolveAdminListTarget(resource) {
181
+ switch (resource) {
182
+ case 'viewer':
183
+ return { section: 'security', key: 'viewer_chat_ids' };
184
+ case 'operator':
185
+ return { section: 'security', key: 'operator_chat_ids' };
186
+ case 'admin':
187
+ return { section: 'security', key: 'admin_chat_ids' };
188
+ case 'service-observer':
189
+ return { section: 'security', key: 'service_observer_chat_ids' };
190
+ case 'service-restart':
191
+ return { section: 'security', key: 'service_restart_chat_ids' };
192
+ case 'config-admin':
193
+ return { section: 'security', key: 'config_admin_chat_ids' };
194
+ case 'group':
195
+ return { section: 'feishu', key: 'allowed_group_ids' };
196
+ case 'chat':
197
+ return { section: 'feishu', key: 'allowed_chat_ids' };
198
+ }
199
+ }
200
+ // ---------------------------------------------------------------------------
201
+ // Conversation key
202
+ // ---------------------------------------------------------------------------
203
+ export function buildConversationKeyForConversation(conversation) {
204
+ return buildConversationKey({
205
+ tenantKey: conversation.tenant_key,
206
+ chatId: conversation.chat_id,
207
+ actorId: conversation.actor_id,
208
+ scope: conversation.scope,
209
+ });
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // Memory section rendering (used in prompt assembly)
213
+ // ---------------------------------------------------------------------------
214
+ export function renderMemorySection(title, items, budget) {
215
+ if (items.length === 0) {
216
+ return [];
217
+ }
218
+ const lines = ['', title];
219
+ let used = 0;
220
+ for (const item of items) {
221
+ const line = `- ${item.title}${item.pinned ? ' [pinned]' : ''}: ${item.content}`;
222
+ if (used + line.length > budget) {
223
+ break;
224
+ }
225
+ lines.push(truncateExcerpt(line, 280));
226
+ used += line.length;
227
+ }
228
+ return lines.length > 2 ? lines : [];
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // Time formatting
232
+ // ---------------------------------------------------------------------------
233
+ export function formatAgeFromNow(isoTimestamp) {
234
+ const deltaMs = Date.now() - Date.parse(isoTimestamp);
235
+ if (!Number.isFinite(deltaMs) || deltaMs < 0) {
236
+ return '0s';
237
+ }
238
+ const totalSeconds = Math.floor(deltaMs / 1000);
239
+ if (totalSeconds < 60) {
240
+ return `${totalSeconds}s`;
241
+ }
242
+ const totalMinutes = Math.floor(totalSeconds / 60);
243
+ if (totalMinutes < 60) {
244
+ return `${totalMinutes}m`;
245
+ }
246
+ const totalHours = Math.floor(totalMinutes / 60);
247
+ if (totalHours < 24) {
248
+ return `${totalHours}h`;
249
+ }
250
+ return `${Math.floor(totalHours / 24)}d`;
251
+ }
252
+ // ---------------------------------------------------------------------------
253
+ // Parsing helpers
254
+ // ---------------------------------------------------------------------------
255
+ export function parseJsonObject(input) {
256
+ try {
257
+ const parsed = JSON.parse(input);
258
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
259
+ throw new Error('JSON payload must be an object.');
260
+ }
261
+ return parsed;
262
+ }
263
+ catch (error) {
264
+ throw new Error(`JSON 解析失败: ${error instanceof Error ? error.message : String(error)}`);
265
+ }
266
+ }
267
+ export function clampListLimit(input, fallback, max) {
268
+ const parsed = Number(input ?? fallback);
269
+ if (!Number.isFinite(parsed) || parsed <= 0) {
270
+ return fallback;
271
+ }
272
+ return Math.min(Math.trunc(parsed), max);
273
+ }
274
+ // ---------------------------------------------------------------------------
275
+ // In-place object replacement (used by hot config reload)
276
+ // ---------------------------------------------------------------------------
277
+ export function replaceObject(target, next) {
278
+ for (const key of Object.keys(target)) {
279
+ if (!(key in next)) {
280
+ delete target[key];
281
+ }
282
+ }
283
+ for (const [key, value] of Object.entries(next)) {
284
+ target[key] = value;
285
+ }
286
+ }
287
+ export function replaceProjects(target, next) {
288
+ for (const key of Object.keys(target)) {
289
+ if (!(key in next)) {
290
+ delete target[key];
291
+ }
292
+ }
293
+ for (const [alias, project] of Object.entries(next)) {
294
+ target[alias] = project;
295
+ }
296
+ }
297
+ // ---------------------------------------------------------------------------
298
+ // Deferred promise primitive
299
+ // ---------------------------------------------------------------------------
300
+ export function createDeferred() {
301
+ let resolve;
302
+ let reject;
303
+ const promise = new Promise((innerResolve, innerReject) => {
304
+ resolve = innerResolve;
305
+ reject = innerReject;
306
+ });
307
+ return { promise, resolve, reject };
308
+ }
309
+ //# sourceMappingURL=service-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-utils.js","sourceRoot":"","sources":["../../src/bridge/service-utils.ts"],"names":[],"mappings":"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"}
@@ -1,42 +1,60 @@
1
- import type { BridgeConfig } from '../config/schema.js';
1
+ import type { BridgeConfig, ProjectConfig } from '../config/schema.js';
2
2
  import type { IncomingCardActionContext, IncomingMessageContext } from './types.js';
3
3
  import { SessionStore } from '../state/session-store.js';
4
4
  import type { Logger } from '../logging.js';
5
- import { FeishuClient } from '../feishu/client.js';
5
+ import { FeishuClient, type FeishuMessageResponse } from '../feishu/client.js';
6
+ import { TaskQueue } from './task-queue.js';
6
7
  import { AuditLog } from '../state/audit-log.js';
7
8
  import type { MetricsRegistry } from '../observability/metrics.js';
8
9
  import { IdempotencyStore } from '../state/idempotency-store.js';
9
10
  import { RunStateStore, type RunState } from '../state/run-state-store.js';
10
11
  import { MemoryStore } from '../state/memory-store.js';
12
+ import type { MemoryContext } from '../memory/retrieve.js';
11
13
  import { CodexSessionIndex } from '../codex/session-index.js';
12
- import { ConfigHistoryStore } from '../state/config-history-store.js';
14
+ import type { Backend, BackendName } from '../backend/types.js';
15
+ import { type FailoverInfo } from '../backend/factory.js';
16
+ import { ConfigHistoryStore, type ConfigSnapshot } from '../state/config-history-store.js';
13
17
  import { HandoffStore } from '../state/handoff-store.js';
14
18
  import { TrustStore } from '../state/trust-store.js';
19
+ export interface ActiveRunHandle {
20
+ runId: string;
21
+ controller: AbortController;
22
+ pid?: number;
23
+ cancelReason?: 'user' | 'timeout' | 'recovery';
24
+ }
15
25
  interface RuntimeControl {
16
26
  configPath?: string;
17
27
  restart?: () => Promise<void>;
18
28
  }
29
+ interface RunReplyTarget {
30
+ messageId?: string;
31
+ mode: BridgeConfig['service']['reply_mode'];
32
+ }
19
33
  export declare class FeiqueService {
20
- private config;
21
- private readonly feishuClient;
22
- private readonly sessionStore;
23
- private readonly auditLog;
24
- private readonly logger;
25
- private readonly metrics?;
34
+ config: BridgeConfig;
35
+ readonly feishuClient: FeishuClient;
36
+ readonly sessionStore: SessionStore;
37
+ readonly auditLog: AuditLog;
38
+ readonly logger: Logger;
39
+ readonly metrics?: MetricsRegistry | undefined;
26
40
  private readonly idempotencyStore;
27
- private readonly runStateStore;
28
- private readonly memoryStore;
29
- private readonly codexSessionIndex;
30
- private readonly runtimeControl?;
31
- private readonly adminAuditLog;
32
- private readonly configHistoryStore;
33
- private readonly handoffStore;
34
- private readonly trustStore;
35
- private readonly queue;
36
- private readonly projectRootQueue;
37
- private readonly activeRuns;
38
- private readonly runReplyTargets;
41
+ readonly runStateStore: RunStateStore;
42
+ readonly memoryStore: MemoryStore;
43
+ readonly codexSessionIndex: CodexSessionIndex;
44
+ readonly runtimeControl?: RuntimeControl | undefined;
45
+ readonly adminAuditLog: AuditLog;
46
+ readonly configHistoryStore: ConfigHistoryStore;
47
+ readonly handoffStore: HandoffStore;
48
+ readonly trustStore: TrustStore;
49
+ readonly queue: TaskQueue;
50
+ readonly projectRootQueue: TaskQueue;
51
+ readonly activeRuns: Map<string, ActiveRunHandle>;
52
+ readonly runReplyTargets: Map<string, RunReplyTarget>;
39
53
  private readonly chatRateWindows;
54
+ /** Dedupe admin notifications for backend failover: one alert per (from→to) direction per process lifetime. */
55
+ private readonly failoverNotified;
56
+ /** Dedupe rejected-chat notifications: one reply + one admin alert per chat_id per process lifetime. */
57
+ private readonly rejectedChatNotified;
40
58
  private maintenanceTimer?;
41
59
  private digestTimer?;
42
60
  private configWatcher?;
@@ -45,15 +63,6 @@ export declare class FeiqueService {
45
63
  private currentMessageContext?;
46
64
  constructor(config: BridgeConfig, feishuClient: FeishuClient, sessionStore: SessionStore, auditLog: AuditLog, logger: Logger, metrics?: MetricsRegistry | undefined, idempotencyStore?: IdempotencyStore, runStateStore?: RunStateStore, memoryStore?: MemoryStore, codexSessionIndex?: CodexSessionIndex, runtimeControl?: RuntimeControl | undefined, adminAuditLog?: AuditLog, configHistoryStore?: ConfigHistoryStore, handoffStore?: HandoffStore, trustStore?: TrustStore);
47
65
  recoverRuntimeState(): Promise<RunState[]>;
48
- /**
49
- * Reload config from disk with validation, diff, and admin notification.
50
- *
51
- * Flow:
52
- * 1. Parse new config — if invalid, reject and notify admin with error
53
- * 2. Diff against current config — identify what changed
54
- * 3. Apply new config to memory
55
- * 4. Notify admin chat(s) with change summary
56
- */
57
66
  reloadConfig(configPath: string): Promise<{
58
67
  ok: boolean;
59
68
  error?: string;
@@ -97,14 +106,13 @@ export declare class FeiqueService {
97
106
  private handleInsightsCommand;
98
107
  private handleTrustCommand;
99
108
  private handleDigestCommand;
100
- private checkAndSendAlerts;
109
+ checkAndSendAlerts(completedRun: RunState): Promise<void>;
101
110
  private handleGapsCommand;
102
111
  private handleTimelineCommand;
103
112
  private handleAdminCommand;
104
113
  private handleSessionAdoptCommand;
105
114
  private handleBackendCommand;
106
115
  private handleMemoryCommand;
107
- private renderMemoryFilterLines;
108
116
  private handleKnowledgeCommand;
109
117
  private handleDocCommand;
110
118
  private handleTaskCommand;
@@ -114,21 +122,15 @@ export declare class FeiqueService {
114
122
  private buildStatusText;
115
123
  private buildDetailedStatusText;
116
124
  private buildStatusCardFromConversation;
117
- private buildBridgePrompt;
125
+ buildBridgePrompt(projectAlias: string, project: ProjectConfig, incomingMessage: IncomingMessageContext, userPrompt: string, memoryContext: MemoryContext): Promise<string>;
118
126
  private requireProject;
119
127
  private resolveProjectAlias;
120
128
  private resolveProjectContext;
121
129
  private getSelectionConversationKey;
122
130
  private getSelectionScope;
123
131
  private shouldRequireMention;
124
- private resolveMemoryTarget;
125
- private buildMemoryExpiresAt;
126
132
  private cancelActiveRun;
127
133
  private scheduleProjectExecution;
128
- private prepareQueuedExecution;
129
- private buildAcknowledgedRunReply;
130
- private buildQueuedStatusDetail;
131
- private buildRunStatusSummary;
132
134
  private isAdminChat;
133
135
  private buildAdminStatusText;
134
136
  private buildAdminListText;
@@ -143,43 +145,89 @@ export declare class FeiqueService {
143
145
  private canObserveRuns;
144
146
  private canRestartService;
145
147
  private canMutateRuntimeConfig;
146
- private canReadConfigHistory;
147
148
  private canAccessAdminCommand;
148
149
  private commandRequiresWritableConfig;
149
150
  private handleAdminConfigCommand;
150
- private snapshotConfigForAdminMutation;
151
- private appendAdminAudit;
152
- private reloadRuntimeConfigFromDisk;
153
- private parseProjectPatch;
151
+ snapshotConfigForAdminMutation(context: IncomingMessageContext, action: string, summary?: string): Promise<ConfigSnapshot>;
152
+ appendAdminAudit(event: {
153
+ type: string;
154
+ [key: string]: unknown;
155
+ }): Promise<void>;
156
+ reloadRuntimeConfigFromDisk(configPath: string): Promise<void>;
154
157
  private resolveProjectDownloadDir;
155
- private resolveProjectTempDir;
156
- private resolveProjectCacheDir;
157
- private appendProjectAuditEvent;
158
- private notifyProjectChats;
159
- private listManagedAuditTargets;
158
+ resolveProjectTempDir(projectAlias: string, project: ProjectConfig): string;
159
+ resolveProjectCacheDir(projectAlias: string, project: ProjectConfig): string;
160
+ appendProjectAuditEvent(projectAlias: string, project: ProjectConfig, event: {
161
+ type: string;
162
+ [key: string]: unknown;
163
+ }): Promise<void>;
164
+ notifyProjectChats(projectAlias: string, text: string): Promise<void>;
160
165
  private checkAndConsumeChatRateLimit;
161
166
  private applyAdminListValues;
162
- private resolveProjectRoot;
163
- private resolveBackendByName;
164
- private enforceSessionHistoryLimit;
165
- private sendTextReply;
167
+ resolveBackendByName(projectAlias: string, sessionOverride?: BackendName): Backend;
168
+ /**
169
+ * Called when resolveProjectBackendWithFailover returns a non-null failover.
170
+ * Responsibilities:
171
+ * - Log a warning with structured context
172
+ * - Emit an audit event
173
+ * - Notify admin chats (deduped by from→to direction for the process lifetime)
174
+ * - Send a user-visible notice into the current chat so the user knows
175
+ * why their run is on a different backend than expected
176
+ */
177
+ handleBackendFailover(chatId: string, projectAlias: string, runId: string, info: FailoverInfo): Promise<void>;
178
+ /**
179
+ * Called by the transport layer when an incoming chat is rejected by the
180
+ * allowlist (`feishu.allowed_chat_ids` / `allowed_group_ids`).
181
+ *
182
+ * Replaces the previous "silent drop" behavior with a pairing-style
183
+ * experience: tell the user what their chat_id is so an admin can add it,
184
+ * notify admins that a new chat is knocking, and record the rejection in
185
+ * the audit log. Deduped per chat_id for the process lifetime so repeated
186
+ * attempts from the same unauthorized chat do not spam either side.
187
+ *
188
+ * This is best-effort: any send failure is swallowed. We never want a
189
+ * rejection flow to throw out of the transport dispatcher.
190
+ */
191
+ handleRejectedChat(chatId: string, chatType: 'p2p' | 'group' | 'unknown'): Promise<void>;
192
+ enforceSessionHistoryLimit(conversationKey: string, projectAlias: string): Promise<void>;
193
+ sendTextReply(chatId: string, body: string, replyToMessageId?: string, originalText?: string, presentation?: {
194
+ status?: string;
195
+ phase?: string;
196
+ projectAlias?: string;
197
+ }, mentionActor?: {
198
+ chat_type?: string;
199
+ actor_id?: string;
200
+ actor_name?: string;
201
+ }): Promise<FeishuMessageResponse>;
166
202
  private sendCardReply;
167
203
  private sendRunLifecycleReply;
168
204
  private buildInitialRunLifecycleReply;
169
205
  private sendInitialRunLifecycleReply;
170
206
  private rememberRunReplyTarget;
171
- private updateRunStartedReply;
172
- private updateRunProgressReply;
173
- private sendOrUpdateRunOutcome;
207
+ updateRunStartedReply(chatId: string, projectAlias: string, runId: string, backendLabel?: string): Promise<void>;
208
+ updateRunProgressReply(input: {
209
+ chatId: string;
210
+ projectAlias: string;
211
+ prompt: string;
212
+ sessionKey: string;
213
+ replyToMessageId?: string;
214
+ }, runId: string, progress: string, backendLabel?: string): Promise<void>;
215
+ sendOrUpdateRunOutcome(input: {
216
+ input: {
217
+ chatId: string;
218
+ projectAlias: string;
219
+ sessionKey: string;
220
+ prompt: string;
221
+ replyToMessageId?: string;
222
+ };
223
+ runId: string;
224
+ title: string;
225
+ body: string;
226
+ runStatus: 'success' | 'failure' | 'cancelled';
227
+ runPhase?: string;
228
+ cardSummary: string;
229
+ sessionId?: string;
230
+ }): Promise<void>;
174
231
  private updateRunLifecycleReply;
175
- private formatQuotedReply;
176
- private buildReplyTitle;
177
- private sanitizeUserVisibleReply;
178
- private supportsInteractiveCardActions;
179
- private resolveRunLifecycleReplyMode;
180
- private buildRunLifecycleCard;
181
- private stripLifecycleMetadata;
182
232
  }
183
- export declare function buildQueueKey(conversationKey: string, projectAlias: string): string;
184
- export declare function buildProjectRootQueueKey(projectRoot: string): string;
185
- export {};
233
+ export { buildQueueKey, buildProjectRootQueueKey } from './service-utils.js';