openclaw-zulip 0.1.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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/dist/actions.d.ts +3 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +149 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/agent-prompt.d.ts +3 -0
  8. package/dist/agent-prompt.d.ts.map +1 -0
  9. package/dist/agent-prompt.js +21 -0
  10. package/dist/agent-prompt.js.map +1 -0
  11. package/dist/allowlist.d.ts +3 -0
  12. package/dist/allowlist.d.ts.map +1 -0
  13. package/dist/allowlist.js +50 -0
  14. package/dist/allowlist.js.map +1 -0
  15. package/dist/bindings.d.ts +24 -0
  16. package/dist/bindings.d.ts.map +1 -0
  17. package/dist/bindings.js +281 -0
  18. package/dist/bindings.js.map +1 -0
  19. package/dist/commands.d.ts +3 -0
  20. package/dist/commands.d.ts.map +1 -0
  21. package/dist/commands.js +7 -0
  22. package/dist/commands.js.map +1 -0
  23. package/dist/config-schema.d.ts +2 -0
  24. package/dist/config-schema.d.ts.map +1 -0
  25. package/dist/config-schema.js +34 -0
  26. package/dist/config-schema.js.map +1 -0
  27. package/dist/config.d.ts +5 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +53 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/directory.d.ts +3 -0
  32. package/dist/directory.d.ts.map +1 -0
  33. package/dist/directory.js +68 -0
  34. package/dist/directory.js.map +1 -0
  35. package/dist/gateway.d.ts +4 -0
  36. package/dist/gateway.d.ts.map +1 -0
  37. package/dist/gateway.js +324 -0
  38. package/dist/gateway.js.map +1 -0
  39. package/dist/groups.d.ts +3 -0
  40. package/dist/groups.d.ts.map +1 -0
  41. package/dist/groups.js +28 -0
  42. package/dist/groups.js.map +1 -0
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +9 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/messaging.d.ts +3 -0
  48. package/dist/messaging.d.ts.map +1 -0
  49. package/dist/messaging.js +47 -0
  50. package/dist/messaging.js.map +1 -0
  51. package/dist/outbound.d.ts +24 -0
  52. package/dist/outbound.d.ts.map +1 -0
  53. package/dist/outbound.js +114 -0
  54. package/dist/outbound.js.map +1 -0
  55. package/dist/plugin.d.ts +5 -0
  56. package/dist/plugin.d.ts.map +1 -0
  57. package/dist/plugin.js +66 -0
  58. package/dist/plugin.js.map +1 -0
  59. package/dist/resolver.d.ts +3 -0
  60. package/dist/resolver.d.ts.map +1 -0
  61. package/dist/resolver.js +39 -0
  62. package/dist/resolver.js.map +1 -0
  63. package/dist/security.d.ts +4 -0
  64. package/dist/security.d.ts.map +1 -0
  65. package/dist/security.js +15 -0
  66. package/dist/security.js.map +1 -0
  67. package/dist/setup.d.ts +2 -0
  68. package/dist/setup.d.ts.map +1 -0
  69. package/dist/setup.js +25 -0
  70. package/dist/setup.js.map +1 -0
  71. package/dist/status.d.ts +14 -0
  72. package/dist/status.d.ts.map +1 -0
  73. package/dist/status.js +74 -0
  74. package/dist/status.js.map +1 -0
  75. package/dist/threading.d.ts +3 -0
  76. package/dist/threading.d.ts.map +1 -0
  77. package/dist/threading.js +25 -0
  78. package/dist/threading.js.map +1 -0
  79. package/dist/types.d.ts +42 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +4 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/zulip-client.d.ts +115 -0
  84. package/dist/zulip-client.d.ts.map +1 -0
  85. package/dist/zulip-client.js +232 -0
  86. package/dist/zulip-client.js.map +1 -0
  87. package/openclaw.plugin.json +33 -0
  88. package/package.json +53 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 whizzlefred
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # openclaw-zulip
2
+
3
+ A clean-room [OpenClaw](https://github.com/openclaw/openclaw) channel plugin for [Zulip](https://zulip.com), built from scratch with the OpenClaw Plugin SDK.
4
+
5
+ ## Features
6
+
7
+ - **Full Zulip messaging** — Streams, topics, DMs, reactions, media, edits, unsend
8
+ - **ACP topic bindings** — Bind ACP agent sessions to specific Zulip topics
9
+ - **Dual account modes** — Run as a bot or impersonate a user account
10
+ - **Stream-level controls** — Per-stream config (require mention, enable/disable)
11
+ - **Security** — DM policy enforcement, allow-from lists
12
+ - **Actions** — Channel list, channel info, member info queries
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ openclaw plugins install openclaw-zulip
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ Add a `channels.zulip` section to your OpenClaw config:
23
+
24
+ ```yaml
25
+ channels:
26
+ zulip:
27
+ serverUrl: https://your-org.zulipchat.com
28
+ email: bot@your-org.zulipchat.com
29
+ apiKey: your-bot-api-key
30
+ mode: bot # or "user"
31
+
32
+ # Optional: per-stream overrides
33
+ streams:
34
+ general:
35
+ requireMention: true
36
+ private-ops:
37
+ enabled: false
38
+
39
+ # Optional: multi-account setup
40
+ accounts:
41
+ work-bot:
42
+ serverUrl: https://work.zulipchat.com
43
+ email: bot@work.zulipchat.com
44
+ apiKey: ...
45
+ ```
46
+
47
+ ### Account modes
48
+
49
+ | Mode | Description |
50
+ |------|-------------|
51
+ | `bot` | Connects as a Zulip bot (default). Messages appear from the bot identity. |
52
+ | `user` | Connects as a regular Zulip user. Messages appear from that user's identity. |
53
+
54
+ ### Configuration fields
55
+
56
+ | Field | Required | Description |
57
+ |-------|----------|-------------|
58
+ | `serverUrl` | Yes | Zulip server URL |
59
+ | `email` | Yes | Bot or user email address |
60
+ | `apiKey` | Yes | Zulip API key |
61
+ | `mode` | No | `bot` (default) or `user` |
62
+ | `streams` | No | Per-stream config overrides |
63
+ | `dmPolicy` | No | DM handling policy |
64
+ | `allowFrom` | No | Allowed user IDs or emails |
65
+ | `replyToMode` | No | Reply targeting behavior |
66
+
67
+ ## Capabilities
68
+
69
+ | Feature | Supported |
70
+ |---------|-----------|
71
+ | Direct messages | Yes |
72
+ | Group conversations (streams) | Yes |
73
+ | Threads (topics) | Yes |
74
+ | Reactions | Yes |
75
+ | Message editing | Yes |
76
+ | Unsend | Yes |
77
+ | Reply | Yes |
78
+ | Media | Yes |
79
+ | ACP topic bindings | Yes |
80
+ | Native commands | No |
81
+ | Polls | No |
82
+
83
+ ## Migrating from openclaw-channel-zulip
84
+
85
+ If you're replacing the old `openclaw-channel-zulip` plugin, note these config changes:
86
+
87
+ ### Config field renames
88
+
89
+ | Old field | New field |
90
+ |-----------|-----------|
91
+ | `url` | `serverUrl` |
92
+
93
+ ### Streams format change
94
+
95
+ The old plugin used an array of stream names:
96
+
97
+ ```yaml
98
+ streams:
99
+ - "AI System"
100
+ - "Homelab"
101
+ ```
102
+
103
+ The new plugin uses an object with per-stream config:
104
+
105
+ ```yaml
106
+ streams:
107
+ AI System:
108
+ requireMention: true
109
+ Homelab:
110
+ enabled: true
111
+ ```
112
+
113
+ To migrate, convert each stream name to a key with `{}` (empty config) or add per-stream settings as needed.
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ git clone https://github.com/whizzlelabs/openclaw-zulip.git
119
+ cd openclaw-zulip
120
+ npm install
121
+ npm run build
122
+ npm test
123
+ ```
124
+
125
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow.
126
+
127
+ ## License
128
+
129
+ TBD
@@ -0,0 +1,3 @@
1
+ import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
2
+ export declare const zulipActionsAdapter: NonNullable<ChannelPlugin["actions"]>;
3
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAQ9D,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,CAyJrE,CAAC"}
@@ -0,0 +1,149 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { buildClient } from "./outbound.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Zulip message actions adapter
5
+ // ---------------------------------------------------------------------------
6
+ export const zulipActionsAdapter = {
7
+ describeMessageTool(_ctx) {
8
+ return {
9
+ actions: ["react", "edit", "unsend", "search", "topic-edit", "upload-file", "download-file", "channel-list", "channel-info", "member-info"],
10
+ schema: {
11
+ visibility: "current-channel",
12
+ properties: {
13
+ zulip_message_id: Type.Optional(Type.Number({ description: "Zulip message ID to act on (required for react, edit, unsend, topic-edit)" })),
14
+ zulip_emoji: Type.Optional(Type.String({ description: "Emoji name for the react action (e.g. 'thumbs_up', '+1')" })),
15
+ zulip_content: Type.Optional(Type.String({ description: "New message content for the edit action" })),
16
+ zulip_topic: Type.Optional(Type.String({ description: "Topic name for topic-edit or search narrow" })),
17
+ zulip_stream_id: Type.Optional(Type.Number({ description: "Stream ID for topic-edit or search narrow" })),
18
+ zulip_query: Type.Optional(Type.String({ description: "Full-text search query for the search action" })),
19
+ zulip_propagate_mode: Type.Optional(Type.String({
20
+ description: "Topic propagation mode for topic-edit: 'change_one', 'change_later', or 'change_all' (default)",
21
+ })),
22
+ zulip_file_path: Type.Optional(Type.String({ description: "Local file path for upload-file, or Zulip file URI for download-file" })),
23
+ zulip_limit: Type.Optional(Type.Number({ description: "Maximum number of messages to return from search (default 10)" })),
24
+ zulip_user_id: Type.Optional(Type.Number({ description: "Zulip user ID for the member-info action" })),
25
+ },
26
+ },
27
+ };
28
+ },
29
+ async handleAction(ctx) {
30
+ const client = buildClient(ctx.cfg, ctx.accountId);
31
+ const p = ctx.params;
32
+ const text = (s) => String(s ?? "");
33
+ const requireMessageId = () => {
34
+ const raw = p.zulip_message_id;
35
+ if (raw == null || raw === "")
36
+ return null;
37
+ const n = Number(raw);
38
+ if (!Number.isFinite(n))
39
+ return null;
40
+ return n;
41
+ };
42
+ switch (ctx.action) {
43
+ case "react": {
44
+ const messageId = requireMessageId();
45
+ if (messageId == null)
46
+ return err("zulip_message_id is required for react");
47
+ const emojiName = text(p.zulip_emoji) || "thumbs_up";
48
+ await client.addReaction(messageId, emojiName);
49
+ return ok(`Reacted with :${emojiName}: on message ${messageId}`);
50
+ }
51
+ case "edit": {
52
+ const messageId = requireMessageId();
53
+ if (messageId == null)
54
+ return err("zulip_message_id is required for edit");
55
+ const content = text(p.zulip_content);
56
+ if (!content)
57
+ return err("zulip_content is required for edit");
58
+ await client.editMessage(messageId, content);
59
+ return ok(`Edited message ${messageId}`);
60
+ }
61
+ case "unsend":
62
+ case "delete": {
63
+ const messageId = requireMessageId();
64
+ if (messageId == null)
65
+ return err("zulip_message_id is required for unsend");
66
+ await client.deleteMessage(messageId);
67
+ return ok(`Deleted message ${messageId}`);
68
+ }
69
+ case "search": {
70
+ const limit = p.zulip_limit ? Number(p.zulip_limit) || 10 : 10;
71
+ const narrow = [];
72
+ if (p.zulip_stream_id)
73
+ narrow.push({ operator: "stream", operand: text(p.zulip_stream_id) });
74
+ if (p.zulip_topic)
75
+ narrow.push({ operator: "topic", operand: text(p.zulip_topic) });
76
+ if (p.zulip_query)
77
+ narrow.push({ operator: "search", operand: text(p.zulip_query) });
78
+ const messages = await client.searchMessages({
79
+ anchor: "newest",
80
+ numBefore: limit,
81
+ numAfter: 0,
82
+ narrow,
83
+ });
84
+ return ok(JSON.stringify(messages, null, 2));
85
+ }
86
+ case "topic-edit": {
87
+ const messageId = requireMessageId();
88
+ if (messageId == null)
89
+ return err("zulip_message_id is required for topic-edit");
90
+ const topic = text(p.zulip_topic);
91
+ if (!topic)
92
+ return err("zulip_topic is required for topic-edit");
93
+ const propagateMode = text(p.zulip_propagate_mode) || "change_all";
94
+ const streamId = p.zulip_stream_id ? Number(p.zulip_stream_id) : undefined;
95
+ await client.updateMessageTopic(messageId, topic, propagateMode, streamId);
96
+ return ok(`Topic updated to "${topic}" (mode: ${propagateMode})`);
97
+ }
98
+ case "upload-file": {
99
+ const filePath = text(p.zulip_file_path);
100
+ if (!filePath)
101
+ return err("zulip_file_path is required for upload-file");
102
+ if (!ctx.mediaReadFile)
103
+ return err("File read access not available in this context");
104
+ const buffer = await ctx.mediaReadFile(filePath);
105
+ const filename = filePath.split("/").pop() ?? "file";
106
+ const result = await client.uploadFile(filename, buffer);
107
+ return ok(result.uri);
108
+ }
109
+ case "download-file": {
110
+ const fileUrl = text(p.zulip_file_path);
111
+ if (!fileUrl)
112
+ return err("zulip_file_path is required for download-file");
113
+ const buffer = await client.downloadFile(fileUrl);
114
+ const base64 = buffer.toString("base64");
115
+ return ok(`data:application/octet-stream;base64,${base64}`);
116
+ }
117
+ case "channel-list": {
118
+ const streams = await client.getStreams();
119
+ return ok(JSON.stringify(streams, null, 2));
120
+ }
121
+ case "channel-info": {
122
+ const streamId = p.zulip_stream_id ? Number(p.zulip_stream_id) : null;
123
+ if (streamId == null)
124
+ return err("zulip_stream_id is required for channel-info");
125
+ const [stream, members] = await Promise.all([
126
+ client.getStreamById(streamId),
127
+ client.getStreamMembers(streamId),
128
+ ]);
129
+ return ok(JSON.stringify({ ...stream, subscribers: members }, null, 2));
130
+ }
131
+ case "member-info": {
132
+ const userId = p.zulip_user_id ? Number(p.zulip_user_id) : null;
133
+ if (userId == null)
134
+ return err("zulip_user_id is required for member-info");
135
+ const user = await client.getUser(userId);
136
+ return ok(JSON.stringify(user, null, 2));
137
+ }
138
+ default:
139
+ return err(`Action "${ctx.action}" is not supported by the Zulip plugin`);
140
+ }
141
+ },
142
+ };
143
+ function ok(message) {
144
+ return { content: [{ type: "text", text: message }], details: { ok: true } };
145
+ }
146
+ function err(message) {
147
+ return { content: [{ type: "text", text: message }], details: { ok: false } };
148
+ }
149
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
2
+ export declare const zulipAgentPromptAdapter: NonNullable<ChannelPlugin["agentPrompt"]>;
3
+ //# sourceMappingURL=agent-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-prompt.d.ts","sourceRoot":"","sources":["../src/agent-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM9D,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,aAAa,CAAC,aAAa,CAAC,CAiB7E,CAAC"}
@@ -0,0 +1,21 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Agent prompt adapter — Zulip-specific hints for the AI agent
3
+ // ---------------------------------------------------------------------------
4
+ export const zulipAgentPromptAdapter = {
5
+ messageToolHints() {
6
+ return [
7
+ "Zulip uses Markdown for formatting (bold, italic, code blocks, links, lists).",
8
+ "Stream messages require a topic. Topics organize conversations within a stream.",
9
+ "Use @-mentions (@**Full Name**) to notify specific users.",
10
+ "Emoji syntax: :emoji_name: (e.g. :thumbs_up:, :heart:).",
11
+ "LaTeX math is supported: $$formula$$ for display, $formula$ for inline.",
12
+ ];
13
+ },
14
+ reactionGuidance() {
15
+ return {
16
+ level: "extensive",
17
+ channelLabel: "Zulip",
18
+ };
19
+ },
20
+ };
21
+ //# sourceMappingURL=agent-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-prompt.js","sourceRoot":"","sources":["../src/agent-prompt.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E,MAAM,CAAC,MAAM,uBAAuB,GAA8C;IAChF,gBAAgB;QACd,OAAO;YACL,+EAA+E;YAC/E,iFAAiF;YACjF,2DAA2D;YAC3D,yDAAyD;YACzD,yEAAyE;SAC1E,CAAC;IACJ,CAAC;IAED,gBAAgB;QACd,OAAO;YACL,KAAK,EAAE,WAAW;YAClB,YAAY,EAAE,OAAO;SACtB,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
2
+ export declare const zulipAllowlistAdapter: NonNullable<ChannelPlugin["allowlist"]>;
3
+ //# sourceMappingURL=allowlist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../src/allowlist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAU9D,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CA+CzE,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { resolveZulipAccount } from "./config.js";
2
+ const SECTION_KEY = "zulip";
3
+ // ---------------------------------------------------------------------------
4
+ // Allowlist adapter — DM allow-from management
5
+ // ---------------------------------------------------------------------------
6
+ export const zulipAllowlistAdapter = {
7
+ applyConfigEdit({ cfg, parsedConfig, accountId, scope, action, entry }) {
8
+ if (scope !== "dm")
9
+ return { kind: "invalid-entry" };
10
+ const id = accountId ?? "default";
11
+ const path = `channels.${SECTION_KEY}.accounts.${id}.allowFrom`;
12
+ // Read current allowFrom
13
+ const section = cfg.channels?.zulip;
14
+ const accountCfg = section?.accounts?.[id];
15
+ const current = accountCfg?.allowFrom ?? section?.allowFrom ?? [];
16
+ let next;
17
+ if (action === "add") {
18
+ if (current.includes(entry))
19
+ return { kind: "ok", changed: false, pathLabel: path, writeTarget: { kind: "global" } };
20
+ next = [...current, entry];
21
+ }
22
+ else {
23
+ next = current.filter((e) => e !== entry);
24
+ if (next.length === current.length)
25
+ return { kind: "ok", changed: false, pathLabel: path, writeTarget: { kind: "global" } };
26
+ }
27
+ // Apply to parsed config
28
+ const accounts = parsedConfig.accounts ?? {};
29
+ const acct = accounts[id] ?? {};
30
+ acct.allowFrom = next;
31
+ accounts[id] = acct;
32
+ parsedConfig.accounts = accounts;
33
+ return { kind: "ok", changed: true, pathLabel: path, writeTarget: { kind: "global" } };
34
+ },
35
+ readConfig({ cfg, accountId }) {
36
+ const account = resolveZulipAccount(cfg, accountId);
37
+ return {
38
+ dmAllowFrom: account.allowFrom,
39
+ dmPolicy: account.dmPolicy,
40
+ };
41
+ },
42
+ resolveNames({ entries }) {
43
+ // Zulip entries are emails or user IDs — no transformation needed
44
+ return entries.map((input) => ({ input, resolved: true, name: input }));
45
+ },
46
+ supportsScope({ scope }) {
47
+ return scope === "dm" || scope === "all";
48
+ },
49
+ };
50
+ //# sourceMappingURL=allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../src/allowlist.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,GAAG,OAAO,CAAC;AAE5B,8EAA8E;AAC9E,+CAA+C;AAC/C,8EAA8E;AAE9E,MAAM,CAAC,MAAM,qBAAqB,GAA4C;IAC5E,eAAe,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;QACpE,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QAErD,MAAM,EAAE,GAAG,SAAS,IAAI,SAAS,CAAC;QAClC,MAAM,IAAI,GAAG,YAAY,WAAW,aAAa,EAAE,YAAY,CAAC;QAEhE,yBAAyB;QACzB,MAAM,OAAO,GAAI,GAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC;QACpD,MAAM,UAAU,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,OAAO,GAA2B,UAAU,EAAE,SAAS,IAAI,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;QAE1F,IAAI,IAA4B,CAAC;QACjC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;YACrH,IAAI,GAAG,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;gBAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;QAC9H,CAAC;QAED,yBAAyB;QACzB,MAAM,QAAQ,GAAI,YAAwC,CAAC,QAA+D,IAAI,EAAE,CAAC;QACjI,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;QACnB,YAAwC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAE9D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;IACzF,CAAC;IAED,UAAU,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE;QAC3B,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAiB,EAAE,SAAS,CAAC,CAAC;QAClE,OAAO;YACL,WAAW,EAAE,OAAO,CAAC,SAAS;YAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,EAAE,OAAO,EAAE;QACtB,kEAAkE;QAClE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,aAAa,CAAC,EAAE,KAAK,EAAE;QACrB,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC;IAC3C,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { ChannelPlugin } from "openclaw/plugin-sdk";
2
+ import type { SessionBindingAdapter } from "openclaw/plugin-sdk/conversation-runtime";
3
+ type ChannelConfiguredBindingProvider = NonNullable<ChannelPlugin["bindings"]>;
4
+ type ChannelConversationBindingSupport = NonNullable<ChannelPlugin["conversationBindings"]>;
5
+ export type ZulipTopicBinding = {
6
+ bindingId: string;
7
+ accountId: string;
8
+ conversationId: string;
9
+ parentConversationId?: string;
10
+ targetSessionKey: string;
11
+ targetKind: "subagent" | "session";
12
+ boundAt: number;
13
+ lastActivityAt: number;
14
+ idleTimeoutMs?: number;
15
+ maxAgeMs?: number;
16
+ };
17
+ export declare function getZulipBindingStore(accountId: string): Map<string, ZulipTopicBinding>;
18
+ export declare function clearZulipBindingStore(accountId: string): void;
19
+ export declare function touchZulipBindingByConversation(accountId: string, conversationId: string, at?: number): void;
20
+ export declare function createZulipSessionBindingAdapter(accountId: string): SessionBindingAdapter;
21
+ export declare const zulipBindingsAdapter: ChannelConfiguredBindingProvider;
22
+ export declare const zulipConversationBindingsSupport: ChannelConversationBindingSupport;
23
+ export {};
24
+ //# sourceMappingURL=bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../src/bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACV,qBAAqB,EAItB,MAAM,0CAA0C,CAAC;AAElD,KAAK,gCAAgC,GAAG,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;AAC/E,KAAK,iCAAiC,GAAG,WAAW,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC,CAAC;AAM5F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAMF,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAOtF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CAQN;AAsCD,wBAAgB,gCAAgC,CAC9C,SAAS,EAAE,MAAM,GAChB,qBAAqB,CAsEvB;AAgBD,eAAO,MAAM,oBAAoB,EAAE,gCAwElC,CAAC;AAiCF,eAAO,MAAM,gCAAgC,EAAE,iCA4C9C,CAAC"}