@rynx-ai/plugin-channel-lark 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-mirror/mirror-index.d.ts +46 -0
- package/dist/cli-mirror/mirror-index.js +48 -0
- package/dist/cli-mirror/rollout-mirror.d.ts +85 -0
- package/dist/cli-mirror/rollout-mirror.js +333 -0
- package/dist/cli-mirror/rollout-watcher.d.ts +109 -0
- package/dist/cli-mirror/rollout-watcher.js +347 -0
- package/dist/host-adapters.d.ts +82 -0
- package/dist/host-adapters.js +404 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/lark-card-stream.d.ts +363 -0
- package/dist/lark-card-stream.js +1335 -0
- package/dist/lark-content.d.ts +30 -0
- package/dist/lark-content.js +138 -0
- package/dist/lark-conversation-directory.d.ts +65 -0
- package/dist/lark-conversation-directory.js +106 -0
- package/dist/lark-diff-card.d.ts +25 -0
- package/dist/lark-diff-card.js +58 -0
- package/dist/lark-fork-transcript.d.ts +16 -0
- package/dist/lark-fork-transcript.js +141 -0
- package/dist/lark-resume-card.d.ts +31 -0
- package/dist/lark-resume-card.js +105 -0
- package/dist/lark-sdk/client.d.ts +8 -0
- package/dist/lark-sdk/client.js +32 -0
- package/dist/lark-sdk/index.d.ts +1 -0
- package/dist/lark-sdk/index.js +1 -0
- package/dist/lark-sender.d.ts +114 -0
- package/dist/lark-sender.js +323 -0
- package/dist/lark-session-store.d.ts +13 -0
- package/dist/lark-session-store.js +14 -0
- package/dist/lark-settings-card.d.ts +55 -0
- package/dist/lark-settings-card.js +158 -0
- package/dist/lark-setup.d.ts +17 -0
- package/dist/lark-setup.js +86 -0
- package/dist/lark.d.ts +500 -0
- package/dist/lark.js +2010 -0
- package/dist/runtime.d.ts +16 -0
- package/dist/runtime.js +157 -0
- package/dist/runtime.mjs +130863 -0
- package/package.json +35 -0
- package/rynx-plugin.json +42 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PluginRuntimeContext, PluginRuntimeHandle, PluginStartContributionRequest } from "@rynx-ai/plugin-sdk";
|
|
2
|
+
import { type LarkBotRuntime } from "./lark.js";
|
|
3
|
+
export declare const LARK_CHANNEL_ID = "lark";
|
|
4
|
+
export interface LarkPluginRuntimeOptions {
|
|
5
|
+
createBot?: (input: {
|
|
6
|
+
context: PluginRuntimeContext;
|
|
7
|
+
request: Extract<PluginStartContributionRequest, {
|
|
8
|
+
kind: "chat-channel";
|
|
9
|
+
}>;
|
|
10
|
+
instanceDataDir: string;
|
|
11
|
+
}) => Promise<LarkBotRuntime> | LarkBotRuntime;
|
|
12
|
+
}
|
|
13
|
+
/** Runtime-module entry loaded only inside the isolated plugin runner process. */
|
|
14
|
+
export declare function activate(context: PluginRuntimeContext): PluginRuntimeHandle;
|
|
15
|
+
/** Exported separately so lifecycle behavior can be tested without opening Lark WebSocket. */
|
|
16
|
+
export declare function createLarkPluginRuntime(context: PluginRuntimeContext, options?: LarkPluginRuntimeOptions): PluginRuntimeHandle;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { HostAgentCatalog, HostAgentCapabilities, HostConversationRuntime, HostProvisionedLarkSessionStore, HostSessionProvisioner, } from "./host-adapters.js";
|
|
4
|
+
import { FileLarkConversationDirectory } from "./lark-conversation-directory.js";
|
|
5
|
+
import { LocalLarkBotRuntime } from "./lark.js";
|
|
6
|
+
import { authorizeLark } from "./lark-setup.js";
|
|
7
|
+
export const LARK_CHANNEL_ID = "lark";
|
|
8
|
+
/** Runtime-module entry loaded only inside the isolated plugin runner process. */
|
|
9
|
+
export function activate(context) {
|
|
10
|
+
return createLarkPluginRuntime(context);
|
|
11
|
+
}
|
|
12
|
+
/** Exported separately so lifecycle behavior can be tested without opening Lark WebSocket. */
|
|
13
|
+
export function createLarkPluginRuntime(context, options = {}) {
|
|
14
|
+
const instances = new Map();
|
|
15
|
+
const createBot = options.createBot ?? createDefaultBot;
|
|
16
|
+
let disposed = false;
|
|
17
|
+
return {
|
|
18
|
+
async startContribution(request) {
|
|
19
|
+
assertLarkChatRequest(request);
|
|
20
|
+
if (disposed)
|
|
21
|
+
throw new Error("Lark plugin runtime is disposed");
|
|
22
|
+
if (instances.has(request.instanceId)) {
|
|
23
|
+
throw new Error(`Lark channel instance is already running: ${request.instanceId}`);
|
|
24
|
+
}
|
|
25
|
+
const instanceDataDir = path.join(context.dataDir, "instances", request.instanceId);
|
|
26
|
+
await mkdir(instanceDataDir, { recursive: true });
|
|
27
|
+
const entry = {
|
|
28
|
+
bot: await createBot({ context, request, instanceDataDir }),
|
|
29
|
+
status: { state: "starting", connected: false, lastError: null, lastEventAt: null },
|
|
30
|
+
};
|
|
31
|
+
instances.set(request.instanceId, entry);
|
|
32
|
+
try {
|
|
33
|
+
await entry.bot.start();
|
|
34
|
+
entry.status = botStatus(entry.bot, "running");
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
entry.status = {
|
|
38
|
+
...botStatus(entry.bot, "failed"),
|
|
39
|
+
lastError: error instanceof Error ? error.message : String(error),
|
|
40
|
+
};
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
async stopContribution(target) {
|
|
45
|
+
assertLarkChatTarget(target);
|
|
46
|
+
const entry = instances.get(target.instanceId);
|
|
47
|
+
if (!entry)
|
|
48
|
+
return;
|
|
49
|
+
entry.status = { ...entry.status, state: "stopping" };
|
|
50
|
+
try {
|
|
51
|
+
await entry.bot.stop();
|
|
52
|
+
entry.status = botStatus(entry.bot, "stopped");
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
instances.delete(target.instanceId);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
async status(target) {
|
|
59
|
+
assertLarkChatTarget(target);
|
|
60
|
+
const entry = instances.get(target.instanceId);
|
|
61
|
+
return entry ? botStatus(entry.bot, entry.status.state) : { state: "stopped", connected: false };
|
|
62
|
+
},
|
|
63
|
+
async authorize(request, emit, signal) {
|
|
64
|
+
assertLarkAuthorizeRequest(request);
|
|
65
|
+
const result = await authorizeLark(emit, signal);
|
|
66
|
+
return result;
|
|
67
|
+
},
|
|
68
|
+
async dispose() {
|
|
69
|
+
if (disposed)
|
|
70
|
+
return;
|
|
71
|
+
disposed = true;
|
|
72
|
+
const stopping = [...instances.values()].map((entry) => entry.bot.stop());
|
|
73
|
+
instances.clear();
|
|
74
|
+
const results = await Promise.allSettled(stopping);
|
|
75
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
76
|
+
if (failure)
|
|
77
|
+
throw failure.reason;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function createDefaultBot({ context, request, instanceDataDir, }) {
|
|
82
|
+
const conversationRuntime = new HostConversationRuntime(context.host);
|
|
83
|
+
const capabilities = new HostAgentCapabilities(context.host);
|
|
84
|
+
const agentCatalog = new HostAgentCatalog(context.host);
|
|
85
|
+
const provisioner = new HostSessionProvisioner(context.host, request.instanceId);
|
|
86
|
+
const activeSessionStore = new HostProvisionedLarkSessionStore({
|
|
87
|
+
filePath: path.join(instanceDataDir, "sessions.json"),
|
|
88
|
+
provisioner,
|
|
89
|
+
defaultAgent: request.defaultAgent ?? request.executionDefaults.defaultAgent,
|
|
90
|
+
});
|
|
91
|
+
const conversationDirectory = new FileLarkConversationDirectory({
|
|
92
|
+
filePath: path.join(instanceDataDir, "conversations.json"),
|
|
93
|
+
});
|
|
94
|
+
return new LocalLarkBotRuntime({
|
|
95
|
+
executionDefaults: request.executionDefaults,
|
|
96
|
+
agentCatalog,
|
|
97
|
+
conversationRuntime,
|
|
98
|
+
capabilities,
|
|
99
|
+
options: { ...request.config },
|
|
100
|
+
defaultAgent: request.defaultAgent,
|
|
101
|
+
activeSessionStore,
|
|
102
|
+
conversationDirectory,
|
|
103
|
+
sessionTitleWriter: (sessionId, title) => provisioner.setTitle(sessionId, title),
|
|
104
|
+
sessionProvisioner: async ({ sessionKey, fromSessionId }) => provisioner.provision(provisioner.forkOperationId(fromSessionId, sessionKey)),
|
|
105
|
+
logger: {
|
|
106
|
+
log(entry) {
|
|
107
|
+
context.logger.info("Lark channel event", jsonFields(entry));
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function botStatus(bot, state) {
|
|
113
|
+
const value = bot.getStatus();
|
|
114
|
+
return {
|
|
115
|
+
state,
|
|
116
|
+
connected: value.connected,
|
|
117
|
+
lastError: value.last_error,
|
|
118
|
+
lastEventAt: value.last_event_at,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function assertLarkChatRequest(request) {
|
|
122
|
+
if (request.kind !== "chat-channel" || request.contributionId !== LARK_CHANNEL_ID) {
|
|
123
|
+
throw new Error("Lark runtime only implements the lark chat-channel contribution");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function assertLarkChatTarget(target) {
|
|
127
|
+
if (target.kind !== "chat-channel" || target.contributionId !== LARK_CHANNEL_ID) {
|
|
128
|
+
throw new Error("Lark runtime only implements the lark chat-channel contribution");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function assertLarkAuthorizeRequest(request) {
|
|
132
|
+
if (request.kind !== "chat-channel" || request.contributionId !== LARK_CHANNEL_ID) {
|
|
133
|
+
throw new Error("Lark runtime only authorizes the lark chat-channel contribution");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function jsonFields(value) {
|
|
137
|
+
const fields = {};
|
|
138
|
+
for (const [key, item] of Object.entries(value)) {
|
|
139
|
+
const normalized = jsonValue(item);
|
|
140
|
+
if (normalized !== undefined)
|
|
141
|
+
fields[key] = normalized;
|
|
142
|
+
}
|
|
143
|
+
return fields;
|
|
144
|
+
}
|
|
145
|
+
function jsonValue(value) {
|
|
146
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
147
|
+
return value;
|
|
148
|
+
if (typeof value === "number")
|
|
149
|
+
return Number.isFinite(value) ? value : String(value);
|
|
150
|
+
if (Array.isArray(value)) {
|
|
151
|
+
return value.map((item) => jsonValue(item) ?? null);
|
|
152
|
+
}
|
|
153
|
+
if (typeof value === "object") {
|
|
154
|
+
return jsonFields(value);
|
|
155
|
+
}
|
|
156
|
+
return value === undefined ? undefined : String(value);
|
|
157
|
+
}
|