feique 1.3.3 → 1.4.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 (55) hide show
  1. package/README.en.md +3 -2
  2. package/README.md +3 -2
  3. package/dist/backend/claude.js +28 -54
  4. package/dist/backend/claude.js.map +1 -1
  5. package/dist/backend/factory.d.ts +28 -0
  6. package/dist/backend/factory.js +61 -0
  7. package/dist/backend/factory.js.map +1 -1
  8. package/dist/backend/probe.d.ts +29 -0
  9. package/dist/backend/probe.js +99 -0
  10. package/dist/backend/probe.js.map +1 -0
  11. package/dist/bridge/admin-config.d.ts +47 -0
  12. package/dist/bridge/admin-config.js +141 -0
  13. package/dist/bridge/admin-config.js.map +1 -0
  14. package/dist/bridge/collab-commands.d.ts +42 -0
  15. package/dist/bridge/collab-commands.js +254 -0
  16. package/dist/bridge/collab-commands.js.map +1 -0
  17. package/dist/bridge/commands.d.ts +1 -1
  18. package/dist/bridge/commands.js +3 -0
  19. package/dist/bridge/commands.js.map +1 -1
  20. package/dist/bridge/feishu-commands.d.ts +27 -0
  21. package/dist/bridge/feishu-commands.js +462 -0
  22. package/dist/bridge/feishu-commands.js.map +1 -0
  23. package/dist/bridge/lifecycle.d.ts +46 -0
  24. package/dist/bridge/lifecycle.js +228 -0
  25. package/dist/bridge/lifecycle.js.map +1 -0
  26. package/dist/bridge/memory-commands.d.ts +26 -0
  27. package/dist/bridge/memory-commands.js +330 -0
  28. package/dist/bridge/memory-commands.js.map +1 -0
  29. package/dist/bridge/reply-builders.d.ts +30 -0
  30. package/dist/bridge/reply-builders.js +72 -0
  31. package/dist/bridge/reply-builders.js.map +1 -0
  32. package/dist/bridge/run-pipeline.d.ts +86 -0
  33. package/dist/bridge/run-pipeline.js +442 -0
  34. package/dist/bridge/run-pipeline.js.map +1 -0
  35. package/dist/bridge/run-scheduler.d.ts +47 -0
  36. package/dist/bridge/run-scheduler.js +121 -0
  37. package/dist/bridge/run-scheduler.js.map +1 -0
  38. package/dist/bridge/service-utils.d.ts +47 -0
  39. package/dist/bridge/service-utils.js +309 -0
  40. package/dist/bridge/service-utils.js.map +1 -0
  41. package/dist/bridge/service.d.ts +114 -66
  42. package/dist/bridge/service.js +225 -2196
  43. package/dist/bridge/service.js.map +1 -1
  44. package/dist/config/load.js +1 -1
  45. package/dist/config/load.js.map +1 -1
  46. package/dist/config/paths.js +1 -20
  47. package/dist/config/paths.js.map +1 -1
  48. package/dist/config/schema.d.ts +3 -0
  49. package/dist/config/schema.js +3 -1
  50. package/dist/config/schema.js.map +1 -1
  51. package/dist/feishu/long-connection.js +1 -0
  52. package/dist/feishu/long-connection.js.map +1 -1
  53. package/dist/feishu/webhook.js +1 -0
  54. package/dist/feishu/webhook.js.map +1 -1
  55. package/package.json +1 -1
@@ -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';