@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,141 @@
1
+ const TRANSCRIPT_MAX_BYTES = 80 * 1024;
2
+ /** Extract a human-readable line from a Feishu message body `content` (a JSON
3
+ * string whose shape depends on `msgType`). Non-text types become a short
4
+ * placeholder so the transcript stays readable. */
5
+ export function extractMessageText(msgType, content) {
6
+ try {
7
+ const parsed = JSON.parse(content);
8
+ if (msgType === "text") {
9
+ return typeof parsed.text === "string" ? parsed.text.trim() : "";
10
+ }
11
+ if (msgType === "post") {
12
+ return extractPostText(parsed);
13
+ }
14
+ if (msgType === "interactive") {
15
+ return extractCardText(parsed) || "[卡片]";
16
+ }
17
+ }
18
+ catch {
19
+ // fall through to placeholder
20
+ }
21
+ switch (msgType) {
22
+ case "image":
23
+ return "[图片]";
24
+ case "file":
25
+ return "[文件]";
26
+ case "audio":
27
+ return "[语音]";
28
+ case "media":
29
+ return "[视频]";
30
+ case "sticker":
31
+ return "[表情]";
32
+ case "interactive":
33
+ return "[卡片]";
34
+ default:
35
+ return msgType ? `[${msgType}]` : "";
36
+ }
37
+ }
38
+ const CARD_TEXT_KEYS = new Set([
39
+ "text",
40
+ "content",
41
+ "title",
42
+ "lines",
43
+ "elements",
44
+ "columns",
45
+ "plain_text",
46
+ "i18n",
47
+ "header",
48
+ "body",
49
+ ]);
50
+ const CARD_TEXT_MAX_CHARS = 400;
51
+ /** Best-effort visible-text extraction from an interactive card body. Returns
52
+ * "" when the card carries no inline text (e.g. a bare card_id reference), so
53
+ * the caller can fall back to a "[卡片]" placeholder. */
54
+ function extractCardText(parsed) {
55
+ const fragments = [];
56
+ collectCardText(parsed, fragments);
57
+ const seen = new Set();
58
+ const deduped = [];
59
+ for (const fragment of fragments) {
60
+ const normalized = fragment.replace(/\s+/g, " ").trim();
61
+ if (!normalized || seen.has(normalized)) {
62
+ continue;
63
+ }
64
+ seen.add(normalized);
65
+ deduped.push(normalized);
66
+ }
67
+ const joined = deduped.join(" ");
68
+ if (!joined) {
69
+ return "";
70
+ }
71
+ return joined.length > CARD_TEXT_MAX_CHARS
72
+ ? `${joined.slice(0, CARD_TEXT_MAX_CHARS)}…`
73
+ : joined;
74
+ }
75
+ function collectCardText(value, out) {
76
+ if (typeof value === "string") {
77
+ out.push(value);
78
+ return;
79
+ }
80
+ if (Array.isArray(value)) {
81
+ for (const item of value) {
82
+ collectCardText(item, out);
83
+ }
84
+ return;
85
+ }
86
+ if (!value || typeof value !== "object") {
87
+ return;
88
+ }
89
+ for (const [key, nested] of Object.entries(value)) {
90
+ if (CARD_TEXT_KEYS.has(key)) {
91
+ collectCardText(nested, out);
92
+ }
93
+ }
94
+ }
95
+ function extractPostText(parsed) {
96
+ // post content is { <locale>: { title, content: item[][] } } or already the
97
+ // locale object. Collect title + any text/link fragments.
98
+ const locale = Array.isArray(parsed.content)
99
+ ? parsed
100
+ : Object.values(parsed).find((value) => value && typeof value === "object" && Array.isArray(value.content));
101
+ if (!locale) {
102
+ return "[富文本]";
103
+ }
104
+ const parts = [];
105
+ if (typeof locale.title === "string" && locale.title.trim()) {
106
+ parts.push(locale.title.trim());
107
+ }
108
+ for (const block of locale.content ?? []) {
109
+ for (const item of block) {
110
+ if (typeof item.text === "string") {
111
+ parts.push(item.text);
112
+ }
113
+ else if (item.tag === "a" && typeof item.href === "string") {
114
+ parts.push(item.href);
115
+ }
116
+ }
117
+ }
118
+ return parts.join(" ").trim() || "[富文本]";
119
+ }
120
+ /**
121
+ * Render a conversation history as a transcript: one `名字:内容` line per
122
+ * message. `nameById` maps a user open_id to a display name; messages from the
123
+ * bot (sender_type !== "user") are labelled 机器人. Bounded to a sane size.
124
+ */
125
+ export function buildForkTranscript(messages, nameById) {
126
+ const lines = [];
127
+ for (const message of messages) {
128
+ const text = extractMessageText(message.msgType, message.content);
129
+ if (!text) {
130
+ continue;
131
+ }
132
+ const isBot = message.senderType !== "user" || !message.senderId;
133
+ const name = isBot ? "机器人" : nameById.get(message.senderId) || "用户";
134
+ lines.push(`${name}:${text}`);
135
+ }
136
+ let transcript = lines.join("\n");
137
+ if (Buffer.byteLength(transcript, "utf8") > TRANSCRIPT_MAX_BYTES) {
138
+ transcript = `${transcript.slice(0, TRANSCRIPT_MAX_BYTES)}\n…(记录过长已截断)`;
139
+ }
140
+ return transcript;
141
+ }
@@ -0,0 +1,31 @@
1
+ import type { LarkConversationRecord } from "./lark-conversation-directory.js";
2
+ /** applink that opens a chat (p2p or group) in the Feishu client. Topic
3
+ * threads have no deep-link, so those are forwarded instead (see the
4
+ * `resume_forward` card action). */
5
+ export declare function buildChatApplink(chatId: string): string;
6
+ /** A single-button card whose button opens `chatId` (used by /fork to give the
7
+ * user a one-tap entry into the new group from the current conversation). */
8
+ export declare function buildOpenChatCardJson(chatId: string, chatName: string): string;
9
+ /** Where /resume was invoked — the forward lands here. When `threadId` is
10
+ * set (invoked inside a topic thread) the forward targets that thread so it
11
+ * appears in-place; otherwise it targets the chat. */
12
+ export interface ResumeTarget {
13
+ chatId: string;
14
+ threadId?: string;
15
+ }
16
+ export interface ResumeForwardValue {
17
+ kind: "resume_forward";
18
+ shortId: string;
19
+ /** The topic thread being resumed (forwarded). */
20
+ sourceThreadId: string;
21
+ /** Current chat to forward into. */
22
+ targetChatId: string;
23
+ /** Current thread to forward into, when /resume was invoked inside one. */
24
+ targetThreadId?: string;
25
+ }
26
+ /**
27
+ * Build a CardKit 2.0 card listing recent conversations. Each row shows the
28
+ * title + short id, with a button that either opens the chat (applink) or
29
+ * forwards the topic thread into `targetChatId`.
30
+ */
31
+ export declare function buildResumeCardJson(records: LarkConversationRecord[], target: ResumeTarget): string;
@@ -0,0 +1,105 @@
1
+ /** applink that opens a chat (p2p or group) in the Feishu client. Topic
2
+ * threads have no deep-link, so those are forwarded instead (see the
3
+ * `resume_forward` card action). */
4
+ export function buildChatApplink(chatId) {
5
+ return `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
6
+ }
7
+ /** A single-button card whose button opens `chatId` (used by /fork to give the
8
+ * user a one-tap entry into the new group from the current conversation). */
9
+ export function buildOpenChatCardJson(chatId, chatName) {
10
+ const url = buildChatApplink(chatId);
11
+ const card = {
12
+ schema: "2.0",
13
+ header: {
14
+ title: { tag: "plain_text", content: "已 fork 到新群" },
15
+ template: "green",
16
+ },
17
+ body: {
18
+ elements: [
19
+ { tag: "markdown", content: `新群聊:**${chatName}**\n已搬运历史记录并带上当前会话上下文。` },
20
+ {
21
+ tag: "button",
22
+ text: { tag: "plain_text", content: "进入新群聊" },
23
+ type: "primary",
24
+ behaviors: [
25
+ { type: "open_url", default_url: url, pc_url: url, ios_url: url, android_url: url },
26
+ ],
27
+ },
28
+ ],
29
+ },
30
+ };
31
+ return JSON.stringify(card);
32
+ }
33
+ function buildResumeButton(record, target) {
34
+ if (record.kind === "thread" && record.threadId) {
35
+ return {
36
+ tag: "button",
37
+ text: { tag: "plain_text", content: "转发到此" },
38
+ type: "primary",
39
+ size: "small",
40
+ behaviors: [
41
+ {
42
+ type: "callback",
43
+ value: {
44
+ kind: "resume_forward",
45
+ shortId: record.shortId,
46
+ sourceThreadId: record.threadId,
47
+ targetChatId: target.chatId,
48
+ ...(target.threadId ? { targetThreadId: target.threadId } : {}),
49
+ },
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ const url = buildChatApplink(record.chatId);
55
+ return {
56
+ tag: "button",
57
+ text: { tag: "plain_text", content: "打开" },
58
+ type: "primary",
59
+ size: "small",
60
+ behaviors: [
61
+ { type: "open_url", default_url: url, pc_url: url, ios_url: url, android_url: url },
62
+ ],
63
+ };
64
+ }
65
+ /**
66
+ * Build a CardKit 2.0 card listing recent conversations. Each row shows the
67
+ * title + short id, with a button that either opens the chat (applink) or
68
+ * forwards the topic thread into `targetChatId`.
69
+ */
70
+ export function buildResumeCardJson(records, target) {
71
+ const elements = records.map((record, index) => ({
72
+ tag: "column_set",
73
+ flex_mode: "none",
74
+ horizontal_align: "left",
75
+ columns: [
76
+ {
77
+ tag: "column",
78
+ width: "weighted",
79
+ weight: 1,
80
+ vertical_align: "center",
81
+ elements: [
82
+ {
83
+ tag: "markdown",
84
+ content: `**${index + 1}.** ${record.title} <font color='grey'>\`${record.shortId}\`</font>`,
85
+ },
86
+ ],
87
+ },
88
+ {
89
+ tag: "column",
90
+ width: "auto",
91
+ vertical_align: "center",
92
+ elements: [buildResumeButton(record, target)],
93
+ },
94
+ ],
95
+ }));
96
+ const card = {
97
+ schema: "2.0",
98
+ header: {
99
+ title: { tag: "plain_text", content: "最近会话" },
100
+ template: "blue",
101
+ },
102
+ body: { elements },
103
+ };
104
+ return JSON.stringify(card);
105
+ }
@@ -0,0 +1,18 @@
1
+ import type { PluginHealth } from "@rynx-ai/plugin-sdk";
2
+ export interface LarkRuntimeInstanceState {
3
+ state: "starting" | "running" | "failed" | "stopping" | "stopped";
4
+ connected: boolean;
5
+ lastError: string | null;
6
+ lastEventAt: string | null;
7
+ }
8
+ export interface LarkRuntimeState {
9
+ active: boolean;
10
+ health: PluginHealth;
11
+ instances: Record<string, LarkRuntimeInstanceState>;
12
+ }
13
+ export declare class LarkRuntimeStateStore {
14
+ private readonly file;
15
+ constructor(dataDir: string);
16
+ read(): LarkRuntimeState;
17
+ write(state: LarkRuntimeState): void;
18
+ }
@@ -0,0 +1,95 @@
1
+ import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ export class LarkRuntimeStateStore {
5
+ file;
6
+ constructor(dataDir) {
7
+ mkdirSync(dataDir, { recursive: true, mode: 0o700 });
8
+ this.file = path.join(dataDir, "lark-runtime-state.json");
9
+ }
10
+ read() {
11
+ if (!existsSync(this.file)) {
12
+ return { active: false, health: { state: "running" }, instances: {} };
13
+ }
14
+ const info = lstatSync(this.file);
15
+ if (!info.isFile() || info.isSymbolicLink() || info.size > 1024 * 1024) {
16
+ return {
17
+ active: false,
18
+ health: { state: "degraded", message: "Runtime state is unavailable" },
19
+ instances: {},
20
+ };
21
+ }
22
+ try {
23
+ return parseState(JSON.parse(readFileSync(this.file, "utf8")));
24
+ }
25
+ catch {
26
+ return {
27
+ active: false,
28
+ health: { state: "degraded", message: "Runtime state is unavailable" },
29
+ instances: {},
30
+ };
31
+ }
32
+ }
33
+ write(state) {
34
+ const temporary = `${this.file}.tmp-${randomUUID()}`;
35
+ try {
36
+ writeFileSync(temporary, `${JSON.stringify(state)}\n`, {
37
+ encoding: "utf8",
38
+ mode: 0o600,
39
+ flag: "wx",
40
+ });
41
+ chmodSync(temporary, 0o600);
42
+ renameSync(temporary, this.file);
43
+ }
44
+ finally {
45
+ rmSync(temporary, { force: true });
46
+ }
47
+ }
48
+ }
49
+ function parseState(value) {
50
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
51
+ throw new Error("invalid runtime state");
52
+ }
53
+ const record = value;
54
+ if (typeof record.active !== "boolean")
55
+ throw new Error("invalid runtime activity");
56
+ const health = parseHealth(record.health);
57
+ if (typeof record.instances !== "object" || record.instances === null ||
58
+ Array.isArray(record.instances)) {
59
+ throw new Error("invalid runtime instances");
60
+ }
61
+ const instances = {};
62
+ for (const [id, raw] of Object.entries(record.instances)) {
63
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
64
+ throw new Error("invalid runtime instance");
65
+ }
66
+ const item = raw;
67
+ if (!["starting", "running", "failed", "stopping", "stopped"].includes(String(item.state)) ||
68
+ typeof item.connected !== "boolean" ||
69
+ (item.lastError !== null && typeof item.lastError !== "string") ||
70
+ (item.lastEventAt !== null && typeof item.lastEventAt !== "string")) {
71
+ throw new Error("invalid runtime instance");
72
+ }
73
+ instances[id] = {
74
+ state: item.state,
75
+ connected: item.connected,
76
+ lastError: item.lastError,
77
+ lastEventAt: item.lastEventAt,
78
+ };
79
+ }
80
+ return { active: record.active, health, instances };
81
+ }
82
+ function parseHealth(value) {
83
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
84
+ throw new Error("invalid runtime health");
85
+ }
86
+ const record = value;
87
+ if ((record.state !== "running" && record.state !== "degraded") ||
88
+ (record.message !== undefined && typeof record.message !== "string")) {
89
+ throw new Error("invalid runtime health");
90
+ }
91
+ return {
92
+ state: record.state,
93
+ ...(typeof record.message === "string" ? { message: record.message } : {}),
94
+ };
95
+ }
@@ -0,0 +1,8 @@
1
+ import * as Lark from "@larksuiteoapi/node-sdk";
2
+ export interface LarkSdkClientConfig {
3
+ appId?: string;
4
+ appSecret?: string;
5
+ }
6
+ export declare function createLarkSdkClientConfig(env?: NodeJS.ProcessEnv): LarkSdkClientConfig;
7
+ export declare function createLarkSdkClient(config?: LarkSdkClientConfig, logger?: Lark.Logger): Lark.Client;
8
+ export declare function createLarkWsClient(config?: LarkSdkClientConfig, logger?: Lark.Logger): Lark.WSClient;
@@ -0,0 +1,32 @@
1
+ import * as Lark from "@larksuiteoapi/node-sdk";
2
+ export function createLarkSdkClientConfig(env = process.env) {
3
+ return {
4
+ appId: env.LARK_APP_ID?.trim() || undefined,
5
+ appSecret: env.LARK_APP_SECRET?.trim() || undefined,
6
+ };
7
+ }
8
+ export function createLarkSdkClient(config = createLarkSdkClientConfig(), logger) {
9
+ return new Lark.Client({
10
+ appId: requireLarkConfig(config.appId, "LARK_APP_ID"),
11
+ appSecret: requireLarkConfig(config.appSecret, "LARK_APP_SECRET"),
12
+ appType: Lark.AppType.SelfBuild,
13
+ domain: Lark.Domain.Feishu,
14
+ loggerLevel: Lark.LoggerLevel.info,
15
+ ...(logger ? { logger } : {}),
16
+ });
17
+ }
18
+ export function createLarkWsClient(config = createLarkSdkClientConfig(), logger) {
19
+ return new Lark.WSClient({
20
+ appId: requireLarkConfig(config.appId, "LARK_APP_ID"),
21
+ appSecret: requireLarkConfig(config.appSecret, "LARK_APP_SECRET"),
22
+ autoReconnect: true,
23
+ loggerLevel: Lark.LoggerLevel.info,
24
+ ...(logger ? { logger } : {}),
25
+ });
26
+ }
27
+ function requireLarkConfig(value, key) {
28
+ if (!value) {
29
+ throw new Error(`Missing required configuration ${key}`);
30
+ }
31
+ return value;
32
+ }
@@ -0,0 +1 @@
1
+ export * from "./client.js";
@@ -0,0 +1 @@
1
+ export * from "./client.js";
@@ -0,0 +1,114 @@
1
+ import * as Lark from "@larksuiteoapi/node-sdk";
2
+ import type { LarkFetchedMessage, LarkMessageSender, LarkWsClientProvider, LarkWsClientStartOptions } from "./lark.js";
3
+ export declare class LarkSdkMessageSender implements LarkMessageSender {
4
+ private readonly client;
5
+ constructor(client: Lark.Client);
6
+ getMessage({ messageId }: {
7
+ messageId: string;
8
+ }): Promise<LarkFetchedMessage | null>;
9
+ createText({ chatId, text, uuid, }: {
10
+ chatId: string;
11
+ text: string;
12
+ uuid: string;
13
+ }): Promise<void>;
14
+ createReaction({ messageId, emojiType, }: {
15
+ messageId: string;
16
+ emojiType: string;
17
+ }): Promise<string | undefined>;
18
+ deleteReaction({ messageId, reactionId, }: {
19
+ messageId: string;
20
+ reactionId: string;
21
+ }): Promise<void>;
22
+ replyText({ messageId, text, uuid, replyInThread, }: {
23
+ messageId: string;
24
+ text: string;
25
+ uuid: string;
26
+ replyInThread: boolean;
27
+ }): Promise<void>;
28
+ createCard({ cardJson }: {
29
+ cardJson: string;
30
+ }): Promise<{
31
+ cardId: string;
32
+ }>;
33
+ batchUpdateCard({ cardId, sequence, actions, uuid, }: {
34
+ cardId: string;
35
+ sequence: number;
36
+ actions: string;
37
+ uuid?: string;
38
+ }): Promise<void>;
39
+ sendInteractive({ chatId, cardId, uuid, }: {
40
+ chatId: string;
41
+ cardId: string;
42
+ uuid: string;
43
+ }): Promise<{
44
+ messageId: string;
45
+ }>;
46
+ replyInteractive({ messageId, cardId, uuid, replyInThread, }: {
47
+ messageId: string;
48
+ cardId: string;
49
+ uuid: string;
50
+ replyInThread: boolean;
51
+ }): Promise<{
52
+ messageId: string;
53
+ }>;
54
+ forwardThread({ threadId, receiveId, receiveIdType, uuid, }: {
55
+ /** Source thread being forwarded. */
56
+ threadId: string;
57
+ /** Target id: a chat_id, or a thread_id to land inside that thread. */
58
+ receiveId: string;
59
+ receiveIdType: "chat_id" | "thread_id";
60
+ uuid: string;
61
+ }): Promise<void>;
62
+ sendText({ chatId, text, uuid, }: {
63
+ chatId: string;
64
+ text: string;
65
+ uuid: string;
66
+ }): Promise<{
67
+ messageId: string;
68
+ threadId?: string;
69
+ }>;
70
+ createChat({ name, userIdList, uuid, }: {
71
+ name: string;
72
+ userIdList: string[];
73
+ uuid: string;
74
+ }): Promise<{
75
+ chatId: string;
76
+ }>;
77
+ getChat({ chatId }: {
78
+ chatId: string;
79
+ }): Promise<{
80
+ name: string;
81
+ }>;
82
+ listChatMembers({ chatId, }: {
83
+ chatId: string;
84
+ }): Promise<Array<{
85
+ memberId: string;
86
+ name: string;
87
+ }>>;
88
+ listMessages({ containerIdType, containerId, pageSize, }: {
89
+ containerIdType: "chat" | "thread";
90
+ containerId: string;
91
+ pageSize?: number;
92
+ }): Promise<Array<{
93
+ msgType: string;
94
+ senderId?: string;
95
+ senderType?: string;
96
+ content: string;
97
+ }>>;
98
+ }
99
+ export declare class LarkClientProvider implements LarkWsClientProvider {
100
+ readonly client: Lark.Client;
101
+ private readonly wsClient;
102
+ private botOpenIdPromise?;
103
+ constructor(options?: Record<string, unknown>, logger?: Lark.Logger);
104
+ getMessageSender(): LarkMessageSender;
105
+ /**
106
+ * This bot's own `open_id`, fetched once from the bot info API and memoized.
107
+ * Lets the ingestor tell, in a group hosting multiple bots, whether an
108
+ * incoming `@` actually targets us. Returns `null` if the lookup fails so the
109
+ * caller can fall back to its legacy behavior rather than going silent.
110
+ */
111
+ getBotOpenId(): Promise<string | null>;
112
+ start({ onMessage, onCardAction }: LarkWsClientStartOptions): Promise<void>;
113
+ stop(): Promise<void>;
114
+ }