@rynx-ai/daemon 0.1.10 → 0.1.11-beta.2

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 (117) hide show
  1. package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
  2. package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -0
  3. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
  4. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +54 -0
  5. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
  6. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
  7. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
  8. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
  9. package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
  10. package/bundled-plugins/plugins/lark/dist/host-adapters.js +504 -0
  11. package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
  12. package/bundled-plugins/plugins/lark/dist/index.js +7 -0
  13. package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
  14. package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
  15. package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
  16. package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
  17. package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
  18. package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
  19. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
  20. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
  21. package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
  22. package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
  23. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
  24. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
  25. package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
  26. package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
  27. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
  28. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
  29. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
  30. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
  31. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
  32. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
  33. package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
  34. package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
  35. package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
  36. package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
  37. package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
  38. package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
  39. package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
  40. package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
  41. package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
  42. package/bundled-plugins/plugins/lark/dist/lark.js +1977 -0
  43. package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
  44. package/bundled-plugins/plugins/lark/dist/runtime.js +131316 -0
  45. package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
  46. package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
  47. package/bundled-plugins/plugins/lark/package.json +57 -0
  48. package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
  49. package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.js +201 -0
  50. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  51. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  52. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  53. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  54. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  55. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  56. package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  57. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  58. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  59. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  60. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  61. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  62. package/bundled-plugins/plugins/lark/ui/index.html +13 -0
  63. package/dist/bundled-plugins.d.ts +15 -0
  64. package/dist/bundled-plugins.js +134 -0
  65. package/dist/cli.js +26 -208
  66. package/dist/control-deps.js +2 -79
  67. package/dist/daemon-server.d.ts +4 -1
  68. package/dist/daemon-server.js +167 -57
  69. package/dist/db.js +145 -124
  70. package/dist/index-daemon.js +25 -4
  71. package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
  72. package/dist/migrations/cleanup-legacy-sessions.js +33 -15
  73. package/dist/official-plugins.d.ts +2 -0
  74. package/dist/official-plugins.js +2 -0
  75. package/dist/plugin-cli.d.ts +1 -3
  76. package/dist/plugin-cli.js +56 -45
  77. package/dist/plugin-host-leases.d.ts +4 -0
  78. package/dist/plugin-host-leases.js +7 -0
  79. package/dist/plugin-host-rpc.d.ts +42 -4
  80. package/dist/plugin-host-rpc.js +144 -34
  81. package/dist/plugin-installer.d.ts +24 -55
  82. package/dist/plugin-installer.js +202 -415
  83. package/dist/plugin-management-service.d.ts +30 -23
  84. package/dist/plugin-management-service.js +290 -105
  85. package/dist/plugin-marketplace.d.ts +35 -0
  86. package/dist/plugin-marketplace.js +299 -0
  87. package/dist/plugin-package.d.ts +22 -24
  88. package/dist/plugin-package.js +520 -571
  89. package/dist/plugin-skill-context.d.ts +4 -0
  90. package/dist/plugin-skill-context.js +35 -0
  91. package/dist/plugin-store.d.ts +36 -37
  92. package/dist/plugin-store.js +140 -92
  93. package/dist/plugin-supervisor.d.ts +45 -125
  94. package/dist/plugin-supervisor.js +516 -1053
  95. package/dist/pm2.js +15 -10
  96. package/dist/runtime-project-store.d.ts +9 -0
  97. package/dist/runtime-project-store.js +83 -0
  98. package/dist/session-fallback-workspace.d.ts +22 -0
  99. package/dist/session-fallback-workspace.js +120 -0
  100. package/dist/session-fork-store.d.ts +41 -0
  101. package/dist/session-fork-store.js +288 -0
  102. package/dist/session-launch-operations.d.ts +14 -2
  103. package/dist/session-launch-operations.js +34 -2
  104. package/dist/session-meta-store.d.ts +7 -9
  105. package/dist/session-meta-store.js +28 -49
  106. package/dist/setup.js +26 -14
  107. package/package.json +14 -11
  108. package/dist/channel-store.d.ts +0 -22
  109. package/dist/channel-store.js +0 -65
  110. package/dist/instance-store.d.ts +0 -38
  111. package/dist/instance-store.js +0 -85
  112. package/dist/plugin-install-restart.d.ts +0 -13
  113. package/dist/plugin-install-restart.js +0 -24
  114. package/dist/plugin-runtime-control.d.ts +0 -2
  115. package/dist/plugin-runtime-control.js +0 -37
  116. package/dist/registry.d.ts +0 -10
  117. package/dist/registry.js +0 -52
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Lark (Feishu) authorization flow + its credential form schema.
3
+ *
4
+ * Two setup modes the Lark plugin can offer from its own UI or command:
5
+ * 1. **Form** ({@link larkConfigSchema}) — paste an existing app's App ID /
6
+ * App Secret.
7
+ * 2. **Authorize** ({@link authorizeLark}) — the SDK's `registerApp` device
8
+ * flow (RFC 8628-shaped, Feishu-proprietary provisioning): the user scans a
9
+ * QR (or opens the link) in Feishu, an app is created/authorized with the
10
+ * bot scopes + message-receive event pre-filled, and the SDK returns the
11
+ * App ID / App Secret.
12
+ *
13
+ * `authorizeLark` is transport-neutral: it translates the SDK's callbacks into
14
+ * the plugin's own {@link LarkAuthorizationMaterial} stream and resolves with
15
+ * the values to persist.
16
+ */
17
+ import { registerApp } from "@larksuiteoapi/node-sdk";
18
+ import { createLarkSdkClient } from "./lark-sdk/client.js";
19
+ /**
20
+ * Minimal tenant (app-identity) scopes the Lark channel needs: receive/send
21
+ * messages, add reactions, read chat + members, upload/download resources, and
22
+ * resolve user display info. Pre-filled into the scan-confirm page; editable.
23
+ */
24
+ export const LARK_BOT_SCOPES = [
25
+ "im:message",
26
+ "im:message:send_as_bot",
27
+ "im:message.group_at_msg:readonly",
28
+ "im:message.p2p_msg:readonly",
29
+ "im:message.reactions:write_only",
30
+ "im:chat:read",
31
+ "im:chat.members:read",
32
+ "im:resource",
33
+ "contact:user.base:readonly",
34
+ ];
35
+ /** The bot only needs to be told when a message arrives. */
36
+ export const LARK_BOT_EVENTS = ["im.message.receive_v1"];
37
+ /** Config mode 1: paste an existing app's credentials. */
38
+ export const larkConfigSchema = [
39
+ {
40
+ key: "LARK_APP_ID",
41
+ label: "App ID",
42
+ type: "string",
43
+ required: true,
44
+ help: "形如 cli_xxx,在开放平台「凭证与基础信息」获取",
45
+ },
46
+ { key: "LARK_APP_SECRET", label: "App Secret", type: "secret", required: true },
47
+ ];
48
+ const STATUS_TEXT = {
49
+ polling: "等待在飞书中扫码确认…",
50
+ slow_down: "服务器繁忙,正在放慢轮询…",
51
+ domain_switched: "识别到国际版租户,已切换到 larksuite.com 继续。",
52
+ };
53
+ /**
54
+ * Scan-to-create/authorize. Emits a `qr` material and `status` updates, then
55
+ * resolves with the App ID / App Secret to persist. Aborts via `signal`.
56
+ */
57
+ export async function authorizeLark(emit, signal) {
58
+ let result;
59
+ try {
60
+ result = await registerApp({
61
+ source: "rynx",
62
+ signal,
63
+ // One-scan provisioning: pre-fill the scopes + event this channel needs.
64
+ addons: {
65
+ scopes: { tenant: LARK_BOT_SCOPES },
66
+ events: { items: { tenant: LARK_BOT_EVENTS } },
67
+ },
68
+ onQRCodeReady: ({ url, expireIn }) => emit({ kind: "qr", url, expireIn }),
69
+ onStatusChange: ({ status }) => emit({ kind: "status", text: STATUS_TEXT[status] ?? status }),
70
+ });
71
+ }
72
+ catch (error) {
73
+ throw new Error(scrubSecret(messageOf(error)));
74
+ }
75
+ if (!result.client_id || !result.client_secret) {
76
+ throw new Error("扫码返回的凭据为空,请改用手动填写 App ID / App Secret。");
77
+ }
78
+ const botName = await resolveBotName(result.client_id, result.client_secret);
79
+ return {
80
+ LARK_APP_ID: result.client_id,
81
+ LARK_APP_SECRET: result.client_secret,
82
+ ...(botName ? { botName } : {}),
83
+ };
84
+ }
85
+ async function resolveBotName(appId, appSecret) {
86
+ try {
87
+ const response = await createLarkSdkClient({ appId, appSecret }).request({
88
+ method: "GET",
89
+ url: "/open-apis/bot/v3/info",
90
+ });
91
+ return response?.bot?.app_name?.trim() || undefined;
92
+ }
93
+ catch {
94
+ return undefined;
95
+ }
96
+ }
97
+ function messageOf(err) {
98
+ return err instanceof Error ? err.message : String(err);
99
+ }
100
+ /** Defensively mask any long token-like substring so a secret can't leak. */
101
+ function scrubSecret(text) {
102
+ return text.replace(/[A-Za-z0-9_-]{30,}/g, "***");
103
+ }
@@ -0,0 +1,507 @@
1
+ import { type CodexCapabilities } from "@rynx-ai/core";
2
+ import type { PluginAgentSummary, PluginExecutionDefaults, PluginResolvedSessionExecution, PluginSessionExecutionSnapshot } from "@rynx-ai/plugin-sdk";
3
+ import { chunkLarkReplyText, extractLarkTextPrompt, isLarkNewSessionCommand, isLarkStopCommand } from "./lark-content.js";
4
+ import { type LarkConversationDirectory } from "./lark-conversation-directory.js";
5
+ import { LarkClientProvider, LarkSdkMessageSender } from "./lark-sender.js";
6
+ import { type LarkActiveSessionStore } from "./lark-session-store.js";
7
+ import type { ConversationProvider, ConversationStreamRequest, StartedLiveExecution } from "@rynx-ai/core";
8
+ export { chunkLarkReplyText, extractLarkTextPrompt, isLarkNewSessionCommand, isLarkStopCommand, };
9
+ export { LarkClientProvider, LarkSdkMessageSender };
10
+ export interface LarkUserIdentifier {
11
+ union_id?: string;
12
+ user_id?: string;
13
+ open_id?: string;
14
+ }
15
+ export interface LarkMessageMention {
16
+ key: string;
17
+ id: LarkUserIdentifier;
18
+ name: string;
19
+ tenant_key?: string;
20
+ }
21
+ export interface LarkMessageReceiveEvent {
22
+ tenant_key?: string;
23
+ sender: {
24
+ sender_id?: LarkUserIdentifier;
25
+ sender_type: string;
26
+ tenant_key?: string;
27
+ };
28
+ message: {
29
+ message_id: string;
30
+ root_id?: string;
31
+ parent_id?: string;
32
+ create_time: string;
33
+ update_time?: string;
34
+ chat_id: string;
35
+ thread_id?: string;
36
+ chat_type: string;
37
+ message_type: string;
38
+ content: string;
39
+ mentions?: LarkMessageMention[];
40
+ user_agent?: string;
41
+ };
42
+ }
43
+ export interface LarkBotStatus {
44
+ connected: boolean;
45
+ mode: "ws";
46
+ last_event_at: string | null;
47
+ last_error: string | null;
48
+ }
49
+ export interface LarkBotRuntime {
50
+ start(): Promise<void>;
51
+ stop(): Promise<void>;
52
+ getStatus(): LarkBotStatus;
53
+ }
54
+ interface LarkLogEntry {
55
+ event: string;
56
+ tenant_key?: string;
57
+ chat_id?: string;
58
+ thread_id?: string;
59
+ message_id?: string;
60
+ session_key?: string;
61
+ session_id?: string;
62
+ previous_session_id?: string;
63
+ provider?: ConversationProvider;
64
+ model?: string;
65
+ error?: string;
66
+ emoji_type?: string;
67
+ reason?: string;
68
+ kind?: unknown;
69
+ source?: string;
70
+ command?: string;
71
+ reasoning_effort?: string | null;
72
+ rotated?: boolean;
73
+ }
74
+ interface LarkLogger {
75
+ log(entry: LarkLogEntry): void;
76
+ }
77
+ export declare class LarkConversationKeyResolver {
78
+ resolve(event: LarkMessageReceiveEvent): string;
79
+ }
80
+ export declare class PerThreadQueue {
81
+ private readonly tails;
82
+ enqueue(key: string, task: () => Promise<void>): Promise<void>;
83
+ }
84
+ export declare class LarkMessageDeduper {
85
+ private readonly ttlMs;
86
+ private readonly entries;
87
+ constructor(ttlMs?: number);
88
+ markIfNew(messageId: string, now?: number): boolean;
89
+ private prune;
90
+ }
91
+ export interface LarkMessageSender {
92
+ createText(args: {
93
+ chatId: string;
94
+ text: string;
95
+ uuid: string;
96
+ }): Promise<void>;
97
+ getMessage?(args: {
98
+ messageId: string;
99
+ }): Promise<LarkFetchedMessage | null>;
100
+ createReaction(args: {
101
+ messageId: string;
102
+ emojiType: string;
103
+ }): Promise<string | undefined>;
104
+ deleteReaction(args: {
105
+ messageId: string;
106
+ reactionId: string;
107
+ }): Promise<void>;
108
+ replyText(args: {
109
+ messageId: string;
110
+ text: string;
111
+ uuid: string;
112
+ replyInThread: boolean;
113
+ }): Promise<void>;
114
+ createCard?(args: {
115
+ cardJson: string;
116
+ }): Promise<{
117
+ cardId: string;
118
+ }>;
119
+ batchUpdateCard?(args: {
120
+ cardId: string;
121
+ sequence: number;
122
+ actions: string;
123
+ uuid?: string;
124
+ }): Promise<void>;
125
+ sendInteractive?(args: {
126
+ chatId: string;
127
+ cardId: string;
128
+ uuid: string;
129
+ }): Promise<{
130
+ messageId: string;
131
+ }>;
132
+ replyInteractive?(args: {
133
+ messageId: string;
134
+ cardId: string;
135
+ uuid: string;
136
+ replyInThread: boolean;
137
+ }): Promise<{
138
+ messageId: string;
139
+ }>;
140
+ forwardThread?(args: {
141
+ threadId: string;
142
+ receiveId: string;
143
+ receiveIdType: "chat_id" | "thread_id";
144
+ uuid: string;
145
+ }): Promise<void>;
146
+ sendText?(args: {
147
+ chatId: string;
148
+ text: string;
149
+ uuid: string;
150
+ }): Promise<{
151
+ messageId: string;
152
+ threadId?: string;
153
+ }>;
154
+ createChat?(args: {
155
+ name: string;
156
+ userIdList: string[];
157
+ uuid: string;
158
+ }): Promise<{
159
+ chatId: string;
160
+ }>;
161
+ getChat?(args: {
162
+ chatId: string;
163
+ }): Promise<{
164
+ name: string;
165
+ }>;
166
+ listChatMembers?(args: {
167
+ chatId: string;
168
+ }): Promise<Array<{
169
+ memberId: string;
170
+ name: string;
171
+ }>>;
172
+ listMessages?(args: {
173
+ containerIdType: "chat" | "thread";
174
+ containerId: string;
175
+ pageSize?: number;
176
+ }): Promise<Array<{
177
+ msgType: string;
178
+ senderId?: string;
179
+ senderType?: string;
180
+ content: string;
181
+ }>>;
182
+ }
183
+ export interface LarkFetchedMessage {
184
+ messageId?: string;
185
+ msgType?: string;
186
+ content?: string;
187
+ body?: {
188
+ content?: string;
189
+ };
190
+ }
191
+ export interface LarkCardActionEvent {
192
+ /** Whatever we put in the button's/select's `behaviors[0].value` payload. */
193
+ value: Record<string, unknown> | null;
194
+ /** Selected option value for a `select_static` change (Feishu `action.option`). */
195
+ option?: string | null;
196
+ /** Form field values for a `form_submit` button (Feishu `action.form_value`). */
197
+ formValue?: Record<string, unknown> | null;
198
+ /** open_message_id of the card carrying the control, if Lark surfaced it. */
199
+ messageId?: string;
200
+ }
201
+ /**
202
+ * Shape Feishu expects in response to a card.action.trigger callback. At
203
+ * minimum a `toast` is enough to acknowledge the click and surface UI
204
+ * feedback to the user without a partial card update.
205
+ */
206
+ export interface LarkCardActionResponse {
207
+ toast?: {
208
+ type: "info" | "success" | "warning" | "error";
209
+ content: string;
210
+ };
211
+ /**
212
+ * Replace the card that triggered the action, atomically, as part of the
213
+ * callback response. For raw schema-2.0 cards: `{ type: "raw", data: <card> }`.
214
+ * Preferred over an out-of-band `card.update` (which can briefly flash the new
215
+ * card and then revert to the original form).
216
+ */
217
+ card?: {
218
+ type: "raw";
219
+ data: Record<string, unknown>;
220
+ };
221
+ }
222
+ export interface LarkWsClientStartOptions {
223
+ onMessage: (event: LarkMessageReceiveEvent) => void;
224
+ onCardAction?: (event: LarkCardActionEvent) => LarkCardActionResponse | void | Promise<LarkCardActionResponse | void>;
225
+ }
226
+ export interface LarkWsClientProvider {
227
+ getMessageSender(): LarkMessageSender;
228
+ /**
229
+ * Resolve this bot's own `open_id` (via the bot info API). Used to tell, in a
230
+ * group with several bots, whether an incoming `@` actually targets us.
231
+ * Returns `null` when it cannot be determined.
232
+ */
233
+ getBotOpenId?(): Promise<string | null>;
234
+ start(options: LarkWsClientStartOptions): Promise<void>;
235
+ stop(): Promise<void>;
236
+ }
237
+ /** Plugin-facing run contract. The daemon-backed adapter sends only the
238
+ * provisioned Session id and message over Host RPC; the daemon loads that
239
+ * Session's immutable workspace/execution snapshots. */
240
+ export interface LarkConversationRuntime {
241
+ runLive(input: ConversationStreamRequest): Promise<StartedLiveExecution>;
242
+ }
243
+ interface LarkMessageIngestorOptions {
244
+ conversationRuntime: LarkConversationRuntime;
245
+ messageSender: LarkMessageSender;
246
+ cwd?: string;
247
+ /** Default runtime for conversations without a `/runtime` choice. */
248
+ defaultRuntime?: ConversationProvider;
249
+ /** Default declarative agent for conversations without an `/agent` choice. */
250
+ defaultAgent?: string;
251
+ /** Host-backed agent catalog and first-turn execution resolver. */
252
+ agentCatalog?: LarkAgentCatalog;
253
+ activeSessionStore: LarkActiveSessionStore;
254
+ conversationKeyResolver?: LarkConversationKeyResolver;
255
+ deduper?: LarkMessageDeduper;
256
+ queue?: PerThreadQueue;
257
+ logger?: LarkLogger;
258
+ cardThrottleMs?: number;
259
+ /** Read-only Codex capabilities powering `/models` and `/search`. */
260
+ capabilities?: CodexCapabilities;
261
+ /** Conversation directory powering `/resume`. */
262
+ conversationDirectory?: LarkConversationDirectory;
263
+ /** Allowlist of roots a `/cwd` target must live under. */
264
+ allowedRoots?: string[];
265
+ /**
266
+ * This bot's own `open_id`. In a group hosting several bots, only a message
267
+ * that `@`-mentions this `open_id` triggers a run. When unset, any mention
268
+ * triggers (legacy single-bot behavior).
269
+ */
270
+ botOpenId?: string | null;
271
+ /** When true, private (p2p) chats are rejected — the bot is group-only. */
272
+ disableP2p?: boolean;
273
+ /** When true, only groups in `groupAllowlist` may use the bot. */
274
+ groupAllowlistEnabled?: boolean;
275
+ /** Group `chat_id`s allowed when `groupAllowlistEnabled` is true. */
276
+ groupAllowlist?: string[];
277
+ /** Optional CLI-takeover mirror; receives Codex-thread bindings and turn
278
+ * completions so it can mirror terminal-driven turns back into Feishu. */
279
+ mirror?: LarkCliMirror;
280
+ /** Host-RPC backed title updater for daemon-owned machine sessions. */
281
+ sessionTitleWriter?: (sessionId: string, title: string) => Promise<void>;
282
+ /** Host-RPC backed allocator used by `/fork` before binding the new chat. */
283
+ sessionProvisioner?: (input: {
284
+ sessionKey: string;
285
+ fromSessionId: string;
286
+ title?: string;
287
+ }) => Promise<string>;
288
+ }
289
+ export interface LarkAgentCatalog {
290
+ list(): Promise<PluginAgentSummary[]>;
291
+ get(id: string): Promise<PluginAgentSummary | null>;
292
+ resolveExecution(input: {
293
+ defaultAgent?: string;
294
+ session: PluginSessionExecutionSnapshot;
295
+ }): Promise<PluginResolvedSessionExecution>;
296
+ }
297
+ /**
298
+ * Collaborator that mirrors CLI-driven Codex turns back into Feishu. The
299
+ * ingestor only needs to (a) register a session's Codex thread as it becomes
300
+ * bound, and (b) let the mirror claim the lines the bridge itself wrote so they
301
+ * aren't mirrored twice.
302
+ */
303
+ export interface LarkCliMirror {
304
+ noteBoundSession(codexSessionId: string): Promise<void>;
305
+ claimToEof(codexSessionId: string): Promise<void>;
306
+ }
307
+ export declare class LarkMessageIngestor {
308
+ private readonly conversationRuntime;
309
+ private readonly messageSender;
310
+ /** Default runtime for this bot; per-conversation choices override it. */
311
+ private readonly provider;
312
+ /** Default declarative agent for this bot; per-conversation `/agent` overrides it. */
313
+ private readonly defaultAgent?;
314
+ /** Host-backed agent catalog for `/agent` and execution freezing. */
315
+ private readonly agentCatalog?;
316
+ /** Transient per-conversation settings-card selections, keyed by sessionKey. */
317
+ private readonly pendingSettings;
318
+ private readonly cwd?;
319
+ private readonly activeSessionStore;
320
+ private readonly conversationKeyResolver;
321
+ private readonly deduper;
322
+ private readonly queue;
323
+ private readonly logger;
324
+ private readonly cardThrottleMs;
325
+ private readonly capabilities?;
326
+ private readonly conversationDirectory;
327
+ private readonly allowedRoots;
328
+ private botOpenId;
329
+ private readonly disableP2p;
330
+ private readonly groupAllowlistEnabled;
331
+ private readonly groupAllowlist;
332
+ private readonly mirror?;
333
+ private readonly sessionTitleWriter?;
334
+ private readonly sessionProvisioner?;
335
+ private readonly inFlight;
336
+ constructor({ conversationRuntime, messageSender, cwd, defaultRuntime, defaultAgent, agentCatalog, activeSessionStore, conversationKeyResolver, deduper, queue, logger, cardThrottleMs, capabilities, conversationDirectory, allowedRoots, botOpenId, disableP2p, groupAllowlistEnabled, groupAllowlist, mirror, sessionTitleWriter, sessionProvisioner, }: LarkMessageIngestorOptions);
337
+ /** Best-effort title update for the daemon-owned machine-session record. */
338
+ private registerSession;
339
+ /**
340
+ * Set this bot's own `open_id` once it has been resolved asynchronously
341
+ * (the runtime fetches it from the bot info API at startup).
342
+ */
343
+ setBotOpenId(openId: string | null): void;
344
+ /** Whether a bridge-driven turn is currently running for `sessionKey`. The
345
+ * CLI mirror reads this to skip turns already shown live in Feishu. */
346
+ isInFlight(sessionKey: string): boolean;
347
+ /**
348
+ * Whether a group message is addressed to *this* bot. With a known
349
+ * `botOpenId`, that means one of the `@`-mentions carries our `open_id` —
350
+ * so in a group hosting several bots, only the one actually mentioned runs.
351
+ * When `botOpenId` is unknown, fall back to "any mention" (legacy single-bot
352
+ * behavior) rather than going silent.
353
+ */
354
+ private isAddressedToBot;
355
+ /**
356
+ * Handle a Feishu CardKit button click. Supported actions:
357
+ * - `{ kind: "stop_turn", sessionKey }` — the in-card "停止" button.
358
+ * - `{ kind: "resume_forward", threadId, chatId }` — forward a topic thread
359
+ * into `chatId` (from the `/resume` card).
360
+ * Anything else is logged and ignored.
361
+ */
362
+ ingestCardAction(event: LarkCardActionEvent): Promise<LarkCardActionResponse>;
363
+ private handleResumeForwardAction;
364
+ /** Where a forward should land for the conversation `event` arrived in:
365
+ * inside the current topic thread when present, else the chat. */
366
+ private forwardTargetOf;
367
+ /**
368
+ * Cancel the in-flight turn for `sessionKey`, if any. Returns true if a
369
+ * turn was actually aborted. Safe to call from outside the per-session
370
+ * queue (that's the whole point — the queue is serialized but interrupt
371
+ * must bypass it).
372
+ */
373
+ interruptSession(sessionKey: string): boolean;
374
+ private registerInFlight;
375
+ private clearInFlight;
376
+ ingest(event: LarkMessageReceiveEvent): Promise<void>;
377
+ private handleStopCommand;
378
+ private handleInfoCommand;
379
+ private handleActionCommand;
380
+ /**
381
+ * Render the working-tree diff as a CardKit card (summary + per-file stats +
382
+ * a collapsed full diff). Falls back to a plain-text reply when the sender
383
+ * has no card capability or the card send fails.
384
+ */
385
+ private handleDiffCommand;
386
+ private collectGitDiff;
387
+ private renderGoalReply;
388
+ private capabilityErrorText;
389
+ private conversationKindOf;
390
+ private recordConversation;
391
+ private handleCwdCommand;
392
+ private handleResumeCommand;
393
+ private resumeList;
394
+ private resumeByShortId;
395
+ private sendStandaloneCard;
396
+ private handleForkCommand;
397
+ /**
398
+ * Send the `/runtime` (or `/model`) settings card and seed the pending
399
+ * selection state with the conversation's current settings.
400
+ */
401
+ private handleSettingsCommand;
402
+ /**
403
+ * `/agent` — list declarative agents, or select one for this conversation.
404
+ * Selecting rotates to a fresh session (so sandbox/persona/tools don't change
405
+ * mid-thread) and drops explicit runtime/model overrides so the agent drives them.
406
+ */
407
+ private handleAgentCommand;
408
+ /**
409
+ * Label shown for the model in the turn card. An empty model means the
410
+ * runtime follows its own configured default (e.g. traex with no
411
+ * `TRAEX_MODEL`); show a placeholder so the status row isn't blank (the
412
+ * runtime itself is shown separately).
413
+ */
414
+ private displayModel;
415
+ private renderSettingsSummary;
416
+ /** Assemble the settings-card input from the current pending selection. */
417
+ private settingsCardInput;
418
+ private fetchModelOptions;
419
+ /**
420
+ * Handle a settings-card dropdown change. A runtime change re-scopes the
421
+ * model list (and resets model/effort); a model change re-scopes the effort
422
+ * list — both re-render the card in place via the callback response so the
423
+ * dependent dropdowns update. Effort changes just update pending state.
424
+ */
425
+ private handleSettingsSelect;
426
+ /** Card-action response that re-renders the open settings card in place. */
427
+ private settingsCardResponse;
428
+ /** Apply the pending settings-card selections to the conversation. */
429
+ private handleSettingsApply;
430
+ /** Cancel an open settings card without changing anything. */
431
+ private handleSettingsCancel;
432
+ /**
433
+ * Build a card-action response that swaps the settings card for a static
434
+ * result card. Returning the card in the callback response replaces it
435
+ * atomically; an out-of-band `card.update` would briefly show the result and
436
+ * then revert to the form.
437
+ */
438
+ private settingsResultCard;
439
+ private renderModelsReply;
440
+ private handleNewSessionCommand;
441
+ private logMessageReceived;
442
+ private tryCreateReaction;
443
+ private tryDeleteReaction;
444
+ /**
445
+ * If this turn replies to a Lark message card, fetch the parent card and wrap
446
+ * the prompt so the agent receives the card content as context. Generic: it
447
+ * forwards any interactive (card) parent and names no specific skill — the
448
+ * agent decides how to act on the card. Returns null when the parent is not a
449
+ * card (or cannot be fetched), so the caller falls back to the raw prompt.
450
+ */
451
+ private tryBuildCardReplyPrompt;
452
+ /**
453
+ * Map a session to the {@link TurnSettings} a turn runs with. Already-frozen
454
+ * sessions are resolved locally; first-turn defaults and named-agent lookup
455
+ * are delegated to the capability-gated host and then persisted exactly once.
456
+ */
457
+ private resolveTurnExecution;
458
+ private buildReply;
459
+ private canUseCardSender;
460
+ private tryBuildReplyWithCard;
461
+ /**
462
+ * On the turn's first `session.status` carrying a runtime session id, bind it
463
+ * to the in-flight turn and register it with the CLI mirror (so the mirror
464
+ * watches that rollout file, and the bridge's own lines are later claimed).
465
+ */
466
+ private noteRuntimeSession;
467
+ private buildReplyDrain;
468
+ private sendReplyText;
469
+ }
470
+ interface LocalLarkBotRuntimeOptions {
471
+ /** Host-computed defaults carried on the explicit contribution start request. */
472
+ executionDefaults?: PluginExecutionDefaults;
473
+ /** Capability-gated host view of agent metadata and execution resolution. */
474
+ agentCatalog?: LarkAgentCatalog;
475
+ conversationRuntime: LarkConversationRuntime;
476
+ clientProvider?: LarkWsClientProvider;
477
+ messageIngestor?: LarkMessageIngestor;
478
+ logger?: LarkLogger;
479
+ /** Read-only agent capabilities for `/models` and `/search`. */
480
+ capabilities?: CodexCapabilities;
481
+ /** Per-instance options (credentials + knobs) overriding global config. */
482
+ options?: Record<string, unknown>;
483
+ /** Per-instance default declarative agent. */
484
+ defaultAgent?: string;
485
+ /** Explicit plugin-scoped state files. Runtime entries always supply both. */
486
+ activeSessionStore?: LarkActiveSessionStore;
487
+ conversationDirectory?: LarkConversationDirectory;
488
+ /** Host RPC seams; no daemon object crosses into this process. */
489
+ sessionTitleWriter?: (sessionId: string, title: string) => Promise<void>;
490
+ sessionProvisioner?: (input: {
491
+ sessionKey: string;
492
+ fromSessionId: string;
493
+ title?: string;
494
+ }) => Promise<string>;
495
+ }
496
+ export declare class LocalLarkBotRuntime implements LarkBotRuntime {
497
+ private readonly clientProvider?;
498
+ private readonly messageIngestor?;
499
+ private readonly logger;
500
+ private connected;
501
+ private lastEventAt;
502
+ private lastError;
503
+ constructor({ executionDefaults, agentCatalog, conversationRuntime, options, defaultAgent, logger, clientProvider, messageIngestor, capabilities, activeSessionStore: injectedActiveSessionStore, conversationDirectory: injectedConversationDirectory, sessionTitleWriter, sessionProvisioner, }: LocalLarkBotRuntimeOptions);
504
+ getStatus(): LarkBotStatus;
505
+ start(): Promise<void>;
506
+ stop(): Promise<void>;
507
+ }