opencode-lark 0.1.1

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 (138) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +21 -0
  3. package/README.md +322 -0
  4. package/README.zh-CN.md +324 -0
  5. package/bin/opencode-lark.js +2 -0
  6. package/dist/channel/base-plugin.d.ts +31 -0
  7. package/dist/channel/base-plugin.d.ts.map +1 -0
  8. package/dist/channel/base-plugin.js +42 -0
  9. package/dist/channel/base-plugin.js.map +1 -0
  10. package/dist/channel/feishu/feishu-plugin.d.ts +36 -0
  11. package/dist/channel/feishu/feishu-plugin.d.ts.map +1 -0
  12. package/dist/channel/feishu/feishu-plugin.js +149 -0
  13. package/dist/channel/feishu/feishu-plugin.js.map +1 -0
  14. package/dist/channel/feishu/index.d.ts +2 -0
  15. package/dist/channel/feishu/index.d.ts.map +1 -0
  16. package/dist/channel/feishu/index.js +2 -0
  17. package/dist/channel/feishu/index.js.map +1 -0
  18. package/dist/channel/index.d.ts +4 -0
  19. package/dist/channel/index.d.ts.map +1 -0
  20. package/dist/channel/index.js +4 -0
  21. package/dist/channel/index.js.map +1 -0
  22. package/dist/channel/manager.d.ts +37 -0
  23. package/dist/channel/manager.d.ts.map +1 -0
  24. package/dist/channel/manager.js +68 -0
  25. package/dist/channel/manager.js.map +1 -0
  26. package/dist/channel/mock/mock-plugin.d.ts +24 -0
  27. package/dist/channel/mock/mock-plugin.d.ts.map +1 -0
  28. package/dist/channel/mock/mock-plugin.js +42 -0
  29. package/dist/channel/mock/mock-plugin.js.map +1 -0
  30. package/dist/channel/types.d.ts +226 -0
  31. package/dist/channel/types.d.ts.map +1 -0
  32. package/dist/channel/types.js +7 -0
  33. package/dist/channel/types.js.map +1 -0
  34. package/dist/cron/cron-service.d.ts +40 -0
  35. package/dist/cron/cron-service.d.ts.map +1 -0
  36. package/dist/cron/cron-service.js +140 -0
  37. package/dist/cron/cron-service.js.map +1 -0
  38. package/dist/cron/heartbeat.d.ts +30 -0
  39. package/dist/cron/heartbeat.d.ts.map +1 -0
  40. package/dist/cron/heartbeat.js +76 -0
  41. package/dist/cron/heartbeat.js.map +1 -0
  42. package/dist/feishu/api-client.d.ts +19 -0
  43. package/dist/feishu/api-client.d.ts.map +1 -0
  44. package/dist/feishu/api-client.js +98 -0
  45. package/dist/feishu/api-client.js.map +1 -0
  46. package/dist/feishu/card-builder.d.ts +10 -0
  47. package/dist/feishu/card-builder.d.ts.map +1 -0
  48. package/dist/feishu/card-builder.js +74 -0
  49. package/dist/feishu/card-builder.js.map +1 -0
  50. package/dist/feishu/cardkit-client.d.ts +48 -0
  51. package/dist/feishu/cardkit-client.d.ts.map +1 -0
  52. package/dist/feishu/cardkit-client.js +97 -0
  53. package/dist/feishu/cardkit-client.js.map +1 -0
  54. package/dist/feishu/message-dedup.d.ts +28 -0
  55. package/dist/feishu/message-dedup.d.ts.map +1 -0
  56. package/dist/feishu/message-dedup.js +58 -0
  57. package/dist/feishu/message-dedup.js.map +1 -0
  58. package/dist/feishu/webhook-server.d.ts +20 -0
  59. package/dist/feishu/webhook-server.d.ts.map +1 -0
  60. package/dist/feishu/webhook-server.js +111 -0
  61. package/dist/feishu/webhook-server.js.map +1 -0
  62. package/dist/feishu/ws-client.d.ts +17 -0
  63. package/dist/feishu/ws-client.d.ts.map +1 -0
  64. package/dist/feishu/ws-client.js +158 -0
  65. package/dist/feishu/ws-client.js.map +1 -0
  66. package/dist/handler/interactive-handler.d.ts +16 -0
  67. package/dist/handler/interactive-handler.d.ts.map +1 -0
  68. package/dist/handler/interactive-handler.js +86 -0
  69. package/dist/handler/interactive-handler.js.map +1 -0
  70. package/dist/handler/interactive-poller.d.ts +16 -0
  71. package/dist/handler/interactive-poller.d.ts.map +1 -0
  72. package/dist/handler/interactive-poller.js +147 -0
  73. package/dist/handler/interactive-poller.js.map +1 -0
  74. package/dist/handler/message-handler.d.ts +34 -0
  75. package/dist/handler/message-handler.d.ts.map +1 -0
  76. package/dist/handler/message-handler.js +305 -0
  77. package/dist/handler/message-handler.js.map +1 -0
  78. package/dist/handler/streaming-integration.d.ts +21 -0
  79. package/dist/handler/streaming-integration.d.ts.map +1 -0
  80. package/dist/handler/streaming-integration.js +325 -0
  81. package/dist/handler/streaming-integration.js.map +1 -0
  82. package/dist/index.d.ts +16 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +281 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/memory/memory-manager.d.ts +16 -0
  87. package/dist/memory/memory-manager.d.ts.map +1 -0
  88. package/dist/memory/memory-manager.js +58 -0
  89. package/dist/memory/memory-manager.js.map +1 -0
  90. package/dist/session/progress-tracker.d.ts +12 -0
  91. package/dist/session/progress-tracker.d.ts.map +1 -0
  92. package/dist/session/progress-tracker.js +46 -0
  93. package/dist/session/progress-tracker.js.map +1 -0
  94. package/dist/session/session-manager.d.ts +15 -0
  95. package/dist/session/session-manager.d.ts.map +1 -0
  96. package/dist/session/session-manager.js +91 -0
  97. package/dist/session/session-manager.js.map +1 -0
  98. package/dist/streaming/event-processor.d.ts +74 -0
  99. package/dist/streaming/event-processor.d.ts.map +1 -0
  100. package/dist/streaming/event-processor.js +240 -0
  101. package/dist/streaming/event-processor.js.map +1 -0
  102. package/dist/streaming/session-observer.d.ts +19 -0
  103. package/dist/streaming/session-observer.d.ts.map +1 -0
  104. package/dist/streaming/session-observer.js +140 -0
  105. package/dist/streaming/session-observer.js.map +1 -0
  106. package/dist/streaming/streaming-card.d.ts +37 -0
  107. package/dist/streaming/streaming-card.d.ts.map +1 -0
  108. package/dist/streaming/streaming-card.js +139 -0
  109. package/dist/streaming/streaming-card.js.map +1 -0
  110. package/dist/streaming/subagent-card.d.ts +32 -0
  111. package/dist/streaming/subagent-card.d.ts.map +1 -0
  112. package/dist/streaming/subagent-card.js +103 -0
  113. package/dist/streaming/subagent-card.js.map +1 -0
  114. package/dist/streaming/subagent-tracker.d.ts +45 -0
  115. package/dist/streaming/subagent-tracker.d.ts.map +1 -0
  116. package/dist/streaming/subagent-tracker.js +118 -0
  117. package/dist/streaming/subagent-tracker.js.map +1 -0
  118. package/dist/types.d.ts +55 -0
  119. package/dist/types.d.ts.map +1 -0
  120. package/dist/types.js +5 -0
  121. package/dist/types.js.map +1 -0
  122. package/dist/utils/config.d.ts +197 -0
  123. package/dist/utils/config.d.ts.map +1 -0
  124. package/dist/utils/config.js +87 -0
  125. package/dist/utils/config.js.map +1 -0
  126. package/dist/utils/db.d.ts +12 -0
  127. package/dist/utils/db.d.ts.map +1 -0
  128. package/dist/utils/db.js +35 -0
  129. package/dist/utils/db.js.map +1 -0
  130. package/dist/utils/event-listeners.d.ts +12 -0
  131. package/dist/utils/event-listeners.d.ts.map +1 -0
  132. package/dist/utils/event-listeners.js +21 -0
  133. package/dist/utils/event-listeners.js.map +1 -0
  134. package/dist/utils/logger.d.ts +11 -0
  135. package/dist/utils/logger.d.ts.map +1 -0
  136. package/dist/utils/logger.js +38 -0
  137. package/dist/utils/logger.js.map +1 -0
  138. package/package.json +41 -0
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ChannelManager — manages registered channel plugins and their lifecycles.
3
+ * Provides register, startAll, stopAll, getChannel, listChannels.
4
+ */
5
+ import type { ChannelPlugin, ChannelId } from "./types.js";
6
+ import type { Logger } from "../utils/logger.js";
7
+ export interface ChannelManagerOptions {
8
+ logger: Logger;
9
+ }
10
+ export declare class ChannelManager {
11
+ private readonly channels;
12
+ private readonly logger;
13
+ constructor(options: ChannelManagerOptions);
14
+ /**
15
+ * Register a channel plugin by its id.
16
+ */
17
+ register(plugin: ChannelPlugin): void;
18
+ /**
19
+ * Start all registered channels that have a gateway adapter.
20
+ * Error isolation: one channel failing does not prevent others from starting.
21
+ */
22
+ startAll(signal: AbortSignal): Promise<void>;
23
+ /**
24
+ * Stop all registered channels that have a gateway adapter.
25
+ * Error isolation: one channel failing does not prevent others from stopping.
26
+ */
27
+ stopAll(): Promise<void>;
28
+ /**
29
+ * Get a channel plugin by id.
30
+ */
31
+ getChannel(id: ChannelId): ChannelPlugin | undefined;
32
+ /**
33
+ * List all registered channel plugins.
34
+ */
35
+ listChannels(): ChannelPlugin[];
36
+ }
37
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/channel/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,OAAO,EAAE,qBAAqB;IAI1C;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAKrC;;;OAGG;IACG,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAelD;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAc9B;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS;IAIpD;;OAEG;IACH,YAAY,IAAI,aAAa,EAAE;CAGhC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * ChannelManager — manages registered channel plugins and their lifecycles.
3
+ * Provides register, startAll, stopAll, getChannel, listChannels.
4
+ */
5
+ export class ChannelManager {
6
+ channels = new Map();
7
+ logger;
8
+ constructor(options) {
9
+ this.logger = options.logger;
10
+ }
11
+ /**
12
+ * Register a channel plugin by its id.
13
+ */
14
+ register(plugin) {
15
+ this.channels.set(plugin.id, plugin);
16
+ this.logger.info(`Channel registered: ${plugin.id}`);
17
+ }
18
+ /**
19
+ * Start all registered channels that have a gateway adapter.
20
+ * Error isolation: one channel failing does not prevent others from starting.
21
+ */
22
+ async startAll(signal) {
23
+ for (const plugin of this.channels.values()) {
24
+ if (!plugin.gateway) {
25
+ this.logger.info(`Channel ${plugin.id} has no gateway, skipping start`);
26
+ continue;
27
+ }
28
+ try {
29
+ await plugin.gateway.startAccount("default", signal);
30
+ this.logger.info(`Channel ${plugin.id} started`);
31
+ }
32
+ catch (err) {
33
+ this.logger.error(`Channel ${plugin.id} failed to start`, err);
34
+ }
35
+ }
36
+ }
37
+ /**
38
+ * Stop all registered channels that have a gateway adapter.
39
+ * Error isolation: one channel failing does not prevent others from stopping.
40
+ */
41
+ async stopAll() {
42
+ for (const plugin of this.channels.values()) {
43
+ if (!plugin.gateway?.stopAccount) {
44
+ continue;
45
+ }
46
+ try {
47
+ await plugin.gateway.stopAccount("default");
48
+ this.logger.info(`Channel ${plugin.id} stopped`);
49
+ }
50
+ catch (err) {
51
+ this.logger.error(`Channel ${plugin.id} failed to stop`, err);
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Get a channel plugin by id.
57
+ */
58
+ getChannel(id) {
59
+ return this.channels.get(id);
60
+ }
61
+ /**
62
+ * List all registered channel plugins.
63
+ */
64
+ listChannels() {
65
+ return [...this.channels.values()];
66
+ }
67
+ }
68
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/channel/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,OAAO,cAAc;IACR,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAA;IAC9C,MAAM,CAAQ;IAE/B,YAAY,OAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC9B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,MAAqB;QAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;IACtD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAmB;QAChC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,EAAE,iCAAiC,CAAC,CAAA;gBACvE,SAAQ;YACV,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;gBACpD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;YAClD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAA;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;gBACjC,SAAQ;YACV,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;gBAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;YAClD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAA;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,EAAa;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC9B,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IACpC,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * MockPlugin — minimal channel plugin for testing the ChannelPlugin abstraction.
3
+ * Uses an in-memory message queue to record sent messages.
4
+ * NOT for production use.
5
+ */
6
+ import { BaseChannelPlugin } from "../base-plugin.js";
7
+ import type { ChannelId, ChannelMeta, ChannelConfigAdapter, ChannelGatewayAdapter, ChannelOutboundAdapter, OutboundTarget } from "../types.js";
8
+ export interface MockSentMessage {
9
+ target: OutboundTarget;
10
+ text: string;
11
+ }
12
+ export declare class MockPlugin extends BaseChannelPlugin {
13
+ id: ChannelId;
14
+ meta: ChannelMeta;
15
+ /** Public record of all messages sent through outbound */
16
+ readonly sentMessages: MockSentMessage[];
17
+ /** Track gateway startAccount calls */
18
+ readonly startedAccounts: string[];
19
+ config: ChannelConfigAdapter;
20
+ gateway: ChannelGatewayAdapter;
21
+ outbound: ChannelOutboundAdapter;
22
+ constructor();
23
+ }
24
+ //# sourceMappingURL=mock-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-plugin.d.ts","sourceRoot":"","sources":["../../../src/channel/mock/mock-plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACf,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,UAAW,SAAQ,iBAAiB;IACtC,EAAE,EAAa,SAAS,CAAA;IACxB,IAAI,EAAE,WAAW,CAIzB;IAED,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,eAAe,EAAE,CAAK;IAE7C,uCAAuC;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAK;IAE9B,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,EAAE,qBAAqB,CAAA;IAC9B,QAAQ,EAAE,sBAAsB,CAAA;;CAyB1C"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * MockPlugin — minimal channel plugin for testing the ChannelPlugin abstraction.
3
+ * Uses an in-memory message queue to record sent messages.
4
+ * NOT for production use.
5
+ */
6
+ import { BaseChannelPlugin } from "../base-plugin.js";
7
+ export class MockPlugin extends BaseChannelPlugin {
8
+ id = "mock";
9
+ meta = {
10
+ id: "mock",
11
+ label: "Mock Channel",
12
+ description: "In-memory mock channel for testing",
13
+ };
14
+ /** Public record of all messages sent through outbound */
15
+ sentMessages = [];
16
+ /** Track gateway startAccount calls */
17
+ startedAccounts = [];
18
+ config;
19
+ gateway;
20
+ outbound;
21
+ constructor() {
22
+ super();
23
+ this.config = {
24
+ listAccountIds: () => ["test-acct"],
25
+ resolveAccount: (id) => ({ id, type: "mock" }),
26
+ };
27
+ this.gateway = {
28
+ startAccount: async (accountId, _signal) => {
29
+ this.startedAccounts.push(accountId);
30
+ },
31
+ stopAccount: async (accountId) => {
32
+ // no-op for mock
33
+ },
34
+ };
35
+ this.outbound = {
36
+ sendText: async (target, text) => {
37
+ this.sentMessages.push({ target, text });
38
+ },
39
+ };
40
+ }
41
+ }
42
+ //# sourceMappingURL=mock-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-plugin.js","sourceRoot":"","sources":["../../../src/channel/mock/mock-plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAerD,MAAM,OAAO,UAAW,SAAQ,iBAAiB;IACtC,EAAE,GAAG,MAAmB,CAAA;IACxB,IAAI,GAAgB;QAC3B,EAAE,EAAE,MAAmB;QACvB,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,oCAAoC;KAClD,CAAA;IAED,0DAA0D;IACjD,YAAY,GAAsB,EAAE,CAAA;IAE7C,uCAAuC;IAC9B,eAAe,GAAa,EAAE,CAAA;IAE9B,MAAM,CAAsB;IAC5B,OAAO,CAAuB;IAC9B,QAAQ,CAAwB;IAEzC;QACE,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,MAAM,GAAG;YACZ,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC;YACnC,cAAc,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;SACvD,CAAA;QAED,IAAI,CAAC,OAAO,GAAG;YACb,YAAY,EAAE,KAAK,EAAE,SAAiB,EAAE,OAAoB,EAAiB,EAAE;gBAC7E,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACtC,CAAC;YACD,WAAW,EAAE,KAAK,EAAE,SAAiB,EAAiB,EAAE;gBACtD,iBAAiB;YACnB,CAAC;SACF,CAAA;QAED,IAAI,CAAC,QAAQ,GAAG;YACd,QAAQ,EAAE,KAAK,EAAE,MAAsB,EAAE,IAAY,EAAiB,EAAE;gBACtE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;YAC1C,CAAC;SACF,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * ChannelPlugin type definitions for opencode-lark
3
+ * Defines the core plugin contract for channel integrations.
4
+ * Inspired by openclaw but independently defined.
5
+ */
6
+ /** Unique identifier for a channel provider (e.g., "feishu", "slack", "discord") */
7
+ export type ChannelId = string & {
8
+ readonly __brand: "ChannelId";
9
+ };
10
+ /**
11
+ * Metadata describing a channel plugin
12
+ */
13
+ export interface ChannelMeta {
14
+ /** Unique channel identifier */
15
+ id: ChannelId;
16
+ /** Human-readable label (e.g., "Feishu") */
17
+ label: string;
18
+ /** Long-form description of the channel */
19
+ description: string;
20
+ }
21
+ /**
22
+ * Normalized representation of an inbound message from a channel
23
+ */
24
+ export interface NormalizedMessage {
25
+ /** Unique message ID in the channel */
26
+ messageId: string;
27
+ /** Sender's unique identifier */
28
+ senderId: string;
29
+ /** Human-readable sender name */
30
+ senderName?: string;
31
+ /** Message text content */
32
+ text: string;
33
+ /** Chat/thread/group identifier */
34
+ chatId: string;
35
+ /** Optional: unique identifier for a thread this message belongs to */
36
+ threadId?: string;
37
+ /** Unix timestamp when message was sent */
38
+ timestamp: number;
39
+ /** Optional: ID of a message this one replies to */
40
+ replyToId?: string;
41
+ }
42
+ /**
43
+ * Message prepared for sending to a channel
44
+ */
45
+ export interface OutboundMessage {
46
+ /** Target recipient/channel ID */
47
+ target: string;
48
+ /** Message text content */
49
+ text: string;
50
+ /** Optional: formatted card/rich content (channel-specific format) */
51
+ card?: unknown;
52
+ /** Optional: reply-to message ID */
53
+ replyToId?: string;
54
+ /** Optional: thread ID for threaded channels */
55
+ threadId?: string;
56
+ }
57
+ /**
58
+ * Destination specification for an outbound message
59
+ */
60
+ export interface OutboundTarget {
61
+ /** Target address (user ID, channel ID, etc.) */
62
+ address: string;
63
+ /** Optional: channel/group ID if different from address */
64
+ channelId?: string;
65
+ /** Optional: thread ID for threaded messaging */
66
+ threadId?: string;
67
+ }
68
+ /**
69
+ * Destination for streaming operations
70
+ */
71
+ export interface StreamTarget {
72
+ /** Target address for streaming updates */
73
+ address: string;
74
+ /** Optional: context metadata */
75
+ context?: Record<string, unknown>;
76
+ }
77
+ /**
78
+ * Active streaming session for coalesced updates
79
+ */
80
+ export interface StreamingSession {
81
+ /** Unique session identifier */
82
+ sessionId: string;
83
+ /** Target for this streaming session */
84
+ target: StreamTarget;
85
+ /** Accumulated updates pending send */
86
+ pendingUpdates: string[];
87
+ /** Timestamp when session was created */
88
+ createdAt: number;
89
+ /** Function to flush accumulated updates */
90
+ flush: () => Promise<void>;
91
+ }
92
+ /**
93
+ * Key identifying a thread for message threading operations
94
+ */
95
+ export type ThreadKey = string & {
96
+ readonly __brand: "ThreadKey";
97
+ };
98
+ /**
99
+ * Adapter for configuring channel accounts and resolving credentials
100
+ */
101
+ export interface ChannelConfigAdapter {
102
+ /**
103
+ * List all configured account IDs for this channel
104
+ */
105
+ listAccountIds(): string[];
106
+ /**
107
+ * Resolve a channel account to its full configuration/credentials
108
+ * @param id Account ID to resolve
109
+ * @returns Resolved account object (channel-specific structure)
110
+ */
111
+ resolveAccount(id: string): unknown;
112
+ }
113
+ /**
114
+ * Adapter for channel gateway connection lifecycle
115
+ */
116
+ export interface ChannelGatewayAdapter {
117
+ /**
118
+ * Start a channel account connection
119
+ * @param accountId Account ID to start
120
+ * @param signal Abort signal to stop the operation
121
+ */
122
+ startAccount(accountId: string, signal: AbortSignal): Promise<void>;
123
+ /**
124
+ * Optional: Stop a channel account connection
125
+ * @param accountId Account ID to stop
126
+ */
127
+ stopAccount?(accountId: string): Promise<void>;
128
+ }
129
+ /**
130
+ * Adapter for message normalization and formatting between inbound/outbound
131
+ */
132
+ export interface ChannelMessagingAdapter {
133
+ /**
134
+ * Normalize a raw channel message to standard format
135
+ * @param raw Raw message object from channel provider
136
+ * @returns Normalized message
137
+ */
138
+ normalizeInbound(raw: unknown): NormalizedMessage;
139
+ /**
140
+ * Format an outbound message to channel-specific format
141
+ * @param msg Message to format
142
+ * @returns Channel-specific message object
143
+ */
144
+ formatOutbound(msg: OutboundMessage): unknown;
145
+ }
146
+ /**
147
+ * Adapter for sending messages to a channel
148
+ */
149
+ export interface ChannelOutboundAdapter {
150
+ /**
151
+ * Send text message to a target
152
+ * @param target Destination specification
153
+ * @param text Message text to send
154
+ */
155
+ sendText(target: OutboundTarget, text: string): Promise<void>;
156
+ /**
157
+ * Optional: Send rich card/formatted message
158
+ * @param target Destination specification
159
+ * @param card Card object (channel-specific format)
160
+ */
161
+ sendCard?(target: OutboundTarget, card: unknown): Promise<void>;
162
+ }
163
+ /**
164
+ * Adapter for streaming message updates with optional coalescing
165
+ */
166
+ export interface ChannelStreamingAdapter {
167
+ /**
168
+ * Create a new streaming session for a target
169
+ * @param target Target to stream to
170
+ * @returns Active streaming session
171
+ */
172
+ createStreamingSession(target: StreamTarget): StreamingSession;
173
+ /**
174
+ * Optional: Coalesce multiple updates into a single message
175
+ * @param updates Array of update strings
176
+ * @param intervalMs Time window for coalescing
177
+ * @returns Coalesced update string
178
+ */
179
+ coalesceUpdates?(updates: string[], intervalMs: number): string;
180
+ }
181
+ /**
182
+ * Adapter for thread/conversation tracking
183
+ */
184
+ export interface ChannelThreadingAdapter {
185
+ /**
186
+ * Resolve a thread key from an inbound message
187
+ * @param inbound Normalized inbound message
188
+ * @returns Unique thread key
189
+ */
190
+ resolveThread(inbound: NormalizedMessage): ThreadKey;
191
+ /**
192
+ * Map a thread key to a session ID
193
+ * @param threadKey Thread key to map
194
+ * @param sessionId Agent session ID
195
+ */
196
+ mapSession(threadKey: ThreadKey, sessionId: string): void;
197
+ /**
198
+ * Get the session ID for a thread
199
+ * @param threadKey Thread key to look up
200
+ * @returns Session ID if mapped, null otherwise
201
+ */
202
+ getSession(threadKey: ThreadKey): string | null;
203
+ }
204
+ /**
205
+ * Main ChannelPlugin contract
206
+ * Defines required and optional adapters for a channel integration
207
+ */
208
+ export interface ChannelPlugin {
209
+ /** Unique channel identifier */
210
+ id: ChannelId;
211
+ /** Channel metadata */
212
+ meta: ChannelMeta;
213
+ /** Configuration adapter (REQUIRED) */
214
+ config: ChannelConfigAdapter;
215
+ /** Gateway adapter for connection lifecycle (OPTIONAL) */
216
+ gateway?: ChannelGatewayAdapter;
217
+ /** Message normalization and formatting (OPTIONAL) */
218
+ messaging?: ChannelMessagingAdapter;
219
+ /** Outbound message sending (OPTIONAL) */
220
+ outbound?: ChannelOutboundAdapter;
221
+ /** Streaming update delivery (OPTIONAL) */
222
+ streaming?: ChannelStreamingAdapter;
223
+ /** Thread/conversation tracking (OPTIONAL) */
224
+ threading?: ChannelThreadingAdapter;
225
+ }
226
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/channel/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ChannelPlugin type definitions for opencode-lark
3
+ * Defines the core plugin contract for channel integrations.
4
+ * Inspired by openclaw but independently defined.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/channel/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,40 @@
1
+ import type { CronConfig } from "../utils/config.js";
2
+ import type { SessionManager } from "../session/session-manager.js";
3
+ import type { FeishuApiClient } from "../feishu/api-client.js";
4
+ import type { Logger } from "../utils/logger.js";
5
+ export interface CronServiceOptions {
6
+ config: CronConfig;
7
+ sessionManager: SessionManager;
8
+ feishuClient: FeishuApiClient;
9
+ serverUrl: string;
10
+ logger: Logger;
11
+ }
12
+ interface ParsedSchedule {
13
+ type: "interval" | "daily";
14
+ intervalMs?: number;
15
+ hour?: number;
16
+ minute?: number;
17
+ }
18
+ /**
19
+ * Supported formats:
20
+ * "every Nm" → interval of N minutes
21
+ * "every Nh" → interval of N hours
22
+ * "daily HH:MM" → execute once per day at HH:MM
23
+ *
24
+ * @throws Error on invalid format
25
+ */
26
+ export declare function parseSchedule(schedule: string): ParsedSchedule;
27
+ export declare class CronService {
28
+ private readonly options;
29
+ private readonly intervals;
30
+ private running;
31
+ private lastDailyRun;
32
+ constructor(options: CronServiceOptions);
33
+ /** @throws Error if any job has an invalid schedule */
34
+ start(): void;
35
+ stop(): void;
36
+ private executeJob;
37
+ private waitForResponse;
38
+ }
39
+ export {};
40
+ //# sourceMappingURL=cron-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-service.d.ts","sourceRoot":"","sources":["../../src/cron/cron-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,oBAAoB,CAAA;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,CAAA;IAClB,cAAc,EAAE,cAAc,CAAA;IAC9B,YAAY,EAAE,eAAe,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,UAAU,GAAG,OAAO,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CA6B9D;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;IACjE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,YAAY,CAA4B;gBAEpC,OAAO,EAAE,kBAAkB;IAIvC,uDAAuD;IACvD,KAAK,IAAI,IAAI;IAsCb,IAAI,IAAI,IAAI;YAYE,UAAU;YAmCV,eAAe;CAyB9B"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Supported formats:
3
+ * "every Nm" → interval of N minutes
4
+ * "every Nh" → interval of N hours
5
+ * "daily HH:MM" → execute once per day at HH:MM
6
+ *
7
+ * @throws Error on invalid format
8
+ */
9
+ export function parseSchedule(schedule) {
10
+ const trimmed = schedule.trim();
11
+ // "every Nm" or "every Nh" → regex: digit(s) + unit letter
12
+ const intervalMatch = trimmed.match(/^every\s+(\d+)\s*([mh])$/i);
13
+ if (intervalMatch) {
14
+ const value = Number(intervalMatch[1]);
15
+ const unit = intervalMatch[2].toLowerCase();
16
+ if (value <= 0) {
17
+ throw new Error(`Invalid schedule "${schedule}": interval must be positive`);
18
+ }
19
+ const multiplier = unit === "m" ? 60_000 : 3_600_000;
20
+ return { type: "interval", intervalMs: value * multiplier };
21
+ }
22
+ // "daily HH:MM" → regex: 1-2 digit hour + 2 digit minute
23
+ const dailyMatch = trimmed.match(/^daily\s+(\d{1,2}):(\d{2})$/i);
24
+ if (dailyMatch) {
25
+ const hour = Number(dailyMatch[1]);
26
+ const minute = Number(dailyMatch[2]);
27
+ if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
28
+ throw new Error(`Invalid schedule "${schedule}": invalid time (expected HH:MM with 0-23:0-59)`);
29
+ }
30
+ return { type: "daily", hour, minute };
31
+ }
32
+ throw new Error(`Invalid schedule format "${schedule}". Supported: "every Nm", "every Nh", "daily HH:MM"`);
33
+ }
34
+ export class CronService {
35
+ options;
36
+ intervals = [];
37
+ running = false;
38
+ lastDailyRun = new Map();
39
+ constructor(options) {
40
+ this.options = options;
41
+ }
42
+ /** @throws Error if any job has an invalid schedule */
43
+ start() {
44
+ if (this.running)
45
+ return;
46
+ const { config, logger } = this.options;
47
+ const jobs = config.jobs;
48
+ const parsed = jobs.map((job) => ({
49
+ job,
50
+ schedule: parseSchedule(job.schedule),
51
+ }));
52
+ for (const { job, schedule } of parsed) {
53
+ if (schedule.type === "interval") {
54
+ logger.info(`Cron job "${job.name}": every ${schedule.intervalMs}ms`);
55
+ const id = setInterval(() => {
56
+ void this.executeJob(job);
57
+ }, schedule.intervalMs);
58
+ this.intervals.push(id);
59
+ }
60
+ else if (schedule.type === "daily") {
61
+ logger.info(`Cron job "${job.name}": daily at ${String(schedule.hour).padStart(2, "0")}:${String(schedule.minute).padStart(2, "0")}`);
62
+ const id = setInterval(() => {
63
+ const now = new Date();
64
+ if (now.getHours() === schedule.hour && now.getMinutes() === schedule.minute) {
65
+ const dateKey = `${job.name}:${now.toISOString().slice(0, 10)}`;
66
+ if (!this.lastDailyRun.has(dateKey)) {
67
+ this.lastDailyRun.set(dateKey, now.toISOString());
68
+ void this.executeJob(job);
69
+ }
70
+ }
71
+ }, 60_000);
72
+ this.intervals.push(id);
73
+ }
74
+ }
75
+ this.running = true;
76
+ logger.info(`Cron service started with ${jobs.length} job(s)`);
77
+ }
78
+ stop() {
79
+ if (!this.running)
80
+ return;
81
+ for (const id of this.intervals) {
82
+ clearInterval(id);
83
+ }
84
+ this.intervals.length = 0;
85
+ this.lastDailyRun.clear();
86
+ this.running = false;
87
+ this.options.logger.info("Cron service stopped");
88
+ }
89
+ async executeJob(job) {
90
+ const { sessionManager, feishuClient, serverUrl, logger } = this.options;
91
+ const cronKey = `cron:${job.name}`;
92
+ try {
93
+ logger.info(`Executing cron job "${job.name}"...`);
94
+ const sessionId = await sessionManager.getOrCreate(cronKey);
95
+ const resp = await fetch(`${serverUrl}/session/${sessionId}/message`, {
96
+ method: "POST",
97
+ headers: { "Content-Type": "application/json" },
98
+ body: JSON.stringify({
99
+ parts: [{ type: "text", text: job.prompt }],
100
+ }),
101
+ });
102
+ if (!resp.ok) {
103
+ logger.error(`Cron job "${job.name}": POST failed with HTTP ${resp.status}`);
104
+ return;
105
+ }
106
+ const result = await this.waitForResponse(sessionId);
107
+ await feishuClient.sendMessage(job.chatId, {
108
+ msg_type: "text",
109
+ content: JSON.stringify({ text: result }),
110
+ });
111
+ logger.info(`Cron job "${job.name}" completed`);
112
+ }
113
+ catch (err) {
114
+ logger.error(`Cron job "${job.name}" failed:`, err);
115
+ }
116
+ }
117
+ async waitForResponse(sessionId, maxWaitMs = 300_000) {
118
+ const { serverUrl } = this.options;
119
+ const start = Date.now();
120
+ const pollInterval = 2_000;
121
+ while (Date.now() - start < maxWaitMs) {
122
+ await new Promise((r) => setTimeout(r, pollInterval));
123
+ const statusResp = await fetch(`${serverUrl}/session/${sessionId}`);
124
+ if (!statusResp.ok)
125
+ continue;
126
+ const session = (await statusResp.json());
127
+ if (session.status?.type === "idle") {
128
+ const msgResp = await fetch(`${serverUrl}/session/${sessionId}/message?limit=1`);
129
+ if (msgResp.ok) {
130
+ const messages = (await msgResp.json());
131
+ const last = messages.find((m) => m.role === "assistant");
132
+ return last?.text ?? "(no response)";
133
+ }
134
+ return "(failed to retrieve response)";
135
+ }
136
+ }
137
+ return "(timed out waiting for response)";
138
+ }
139
+ }
140
+ //# sourceMappingURL=cron-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-service.js","sourceRoot":"","sources":["../../src/cron/cron-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { Logger } from "../utils/logger.js";
2
+ import type { FeishuApiClient } from "../feishu/api-client.js";
3
+ export interface HeartbeatOptions {
4
+ intervalMs: number;
5
+ serverUrl: string;
6
+ feishuClient?: FeishuApiClient;
7
+ statusChatId?: string;
8
+ logger: Logger;
9
+ }
10
+ /**
11
+ * Periodic health check service.
12
+ * Pings server at intervals and reports status via Feishu on failure.
13
+ */
14
+ export declare class HeartbeatService {
15
+ private readonly options;
16
+ private intervalId;
17
+ private running;
18
+ private successCount;
19
+ private failCount;
20
+ constructor(options: HeartbeatOptions);
21
+ start(): void;
22
+ stop(): void;
23
+ private tick;
24
+ private sendAlert;
25
+ getStats(): {
26
+ successCount: number;
27
+ failCount: number;
28
+ };
29
+ }
30
+ //# sourceMappingURL=heartbeat.d.ts.map