orchestrix-yuri 4.1.0 → 4.1.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.
@@ -21,16 +21,20 @@ class FeishuAdapter {
21
21
  throw new Error('Feishu App ID and App Secret are required. Run: orchestrix-yuri start --feishu-id ID --feishu-secret SECRET');
22
22
  }
23
23
 
24
+ // Suppress SDK's own info/warn logs — only show errors
25
+ const sdkLogOpts = { loggerLevel: lark.LoggerLevel.ERROR };
26
+
24
27
  // REST API client (token auto-managed by SDK)
25
28
  this.client = new lark.Client({
26
29
  appId: this.appId,
27
30
  appSecret: this.appSecret,
28
31
  appType: lark.AppType.SelfBuild,
29
32
  domain: lark.Domain.Feishu,
33
+ ...sdkLogOpts,
30
34
  });
31
35
 
32
36
  // Event dispatcher — register message handler
33
- const dispatcher = new lark.EventDispatcher({}).register({
37
+ const dispatcher = new lark.EventDispatcher(sdkLogOpts).register({
34
38
  'im.message.receive_v1': async (data) => {
35
39
  await this._handleMessage(data);
36
40
  },
@@ -52,7 +52,8 @@ class Router {
52
52
  this.processing = new Set();
53
53
  this._ownerChatId = null;
54
54
  this._ownerChannelType = null;
55
- this._sendCallbacks = {}; // keyed by channelType
55
+ this._sendCallbacks = {}; // keyed by channelType
56
+ this._ownerChatIds = {}; // keyed by channelType → chatId (for broadcast)
56
57
 
57
58
  // Phase orchestrator — runs long operations in background
58
59
  this.orchestrator = new PhaseOrchestrator({
@@ -70,13 +71,8 @@ class Router {
70
71
  }
71
72
  }
72
73
 
73
- /**
74
- * Set the callback for proactive Telegram messages.
75
- * Called by index.js after the Telegram adapter starts.
76
- */
77
74
  /**
78
75
  * Register a proactive send callback for a channel type.
79
- * Multiple channels can be registered; the owner's channel is used for sending.
80
76
  */
81
77
  setSendCallback(channelType, callback) {
82
78
  if (channelType) {
@@ -87,31 +83,49 @@ class Router {
87
83
  }
88
84
  }
89
85
 
90
- _getSendCallback() {
91
- if (this._ownerChannelType && this._sendCallbacks[this._ownerChannelType]) {
92
- return this._sendCallbacks[this._ownerChannelType];
86
+ /**
87
+ * Broadcast a proactive message to ALL bound channels.
88
+ * Used for progress reports, phase completion, errors.
89
+ */
90
+ _sendProactive(text) {
91
+ for (const [channelType, cb] of Object.entries(this._sendCallbacks)) {
92
+ const chatId = this._ownerChatIds[channelType];
93
+ if (cb && chatId) {
94
+ cb(chatId, text).catch((err) => {
95
+ log.warn(`Proactive send to ${channelType} failed: ${err.message}`);
96
+ });
97
+ }
93
98
  }
94
- return this._sendCallbacks._default || null;
95
99
  }
96
100
 
97
- _sendProactive(text) {
98
- const cb = this._getSendCallback();
99
- if (cb && this._ownerChatId) {
100
- cb(this._ownerChatId, text).catch((err) => {
101
+ /**
102
+ * Send a proactive message to the PRIMARY channel and return { messageId }.
103
+ * Used for agent question bridging (needs single messageId for reply-to tracking).
104
+ */
105
+ async _sendProactiveWithId(text) {
106
+ // Send to primary channel (for reply-to tracking)
107
+ const primaryCb = this._ownerChannelType && this._sendCallbacks[this._ownerChannelType];
108
+ const primaryChatId = this._ownerChatId;
109
+ let result = null;
110
+
111
+ if (primaryCb && primaryChatId) {
112
+ try {
113
+ result = await primaryCb(primaryChatId, text);
114
+ } catch (err) {
101
115
  log.warn(`Proactive send failed: ${err.message}`);
102
- });
116
+ }
103
117
  }
104
- }
105
118
 
106
- async _sendProactiveWithId(text) {
107
- const cb = this._getSendCallback();
108
- if (!cb || !this._ownerChatId) return null;
109
- try {
110
- return await cb(this._ownerChatId, text);
111
- } catch (err) {
112
- log.warn(`Proactive send failed: ${err.message}`);
113
- return null;
119
+ // Also broadcast to other channels (no messageId needed)
120
+ for (const [channelType, cb] of Object.entries(this._sendCallbacks)) {
121
+ if (channelType === this._ownerChannelType) continue;
122
+ const chatId = this._ownerChatIds[channelType];
123
+ if (cb && chatId) {
124
+ cb(chatId, text).catch(() => {});
125
+ }
114
126
  }
127
+
128
+ return result;
115
129
  }
116
130
 
117
131
  /**
@@ -129,7 +143,10 @@ class Router {
129
143
  log.router(`First bind: ${msg.channelType} chat ${msg.chatId} (${msg.userName})`);
130
144
  }
131
145
 
132
- // Store owner info for proactive messaging
146
+ // Store owner info for proactive messaging (per channel for broadcast)
147
+ if (!this._ownerChatIds[msg.channelType]) {
148
+ this._ownerChatIds[msg.channelType] = msg.chatId;
149
+ }
133
150
  if (!this._ownerChatId) {
134
151
  this._ownerChatId = msg.chatId;
135
152
  this._ownerChannelType = msg.channelType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrix-yuri",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Yuri — Meta-Orchestrator for Orchestrix. Drive your entire project lifecycle with natural language.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {