orchestrix-yuri 2.3.1 → 2.3.3
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.
|
@@ -83,16 +83,11 @@ class TelegramAdapter {
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
// Force-disconnect any stale polling connection before starting.
|
|
86
|
-
// deleteWebhook clears webhooks
|
|
87
|
-
//
|
|
88
|
-
//
|
|
86
|
+
// deleteWebhook only clears webhooks, NOT existing long-polling connections.
|
|
87
|
+
// A direct getUpdates call with timeout=0 "steals" the polling slot,
|
|
88
|
+
// terminating any other instance's connection.
|
|
89
89
|
log.telegram('Connecting...');
|
|
90
|
-
|
|
91
|
-
await this.bot.api.deleteWebhook({ drop_pending_updates: true });
|
|
92
|
-
await this.bot.api.raw.getUpdates({ offset: -1, limit: 1, timeout: 0 });
|
|
93
|
-
} catch {
|
|
94
|
-
// ignore — best effort cleanup
|
|
95
|
-
}
|
|
90
|
+
await forceDisconnectPolling(this.token);
|
|
96
91
|
|
|
97
92
|
// Start polling
|
|
98
93
|
await this.bot.start({
|
|
@@ -144,4 +139,38 @@ function splitMessage(text, maxLength) {
|
|
|
144
139
|
return chunks;
|
|
145
140
|
}
|
|
146
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Force-disconnect any stale polling session via direct Telegram API calls.
|
|
144
|
+
* Uses native https to avoid grammy API quirks.
|
|
145
|
+
*/
|
|
146
|
+
function forceDisconnectPolling(token) {
|
|
147
|
+
const https = require('https');
|
|
148
|
+
|
|
149
|
+
const call = (method, body) => new Promise((resolve) => {
|
|
150
|
+
const data = JSON.stringify(body);
|
|
151
|
+
const req = https.request({
|
|
152
|
+
hostname: 'api.telegram.org',
|
|
153
|
+
path: `/bot${token}/${method}`,
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
|
156
|
+
timeout: 10000,
|
|
157
|
+
}, (res) => {
|
|
158
|
+
let buf = '';
|
|
159
|
+
res.on('data', (d) => { buf += d; });
|
|
160
|
+
res.on('end', () => resolve(buf));
|
|
161
|
+
});
|
|
162
|
+
req.on('error', () => resolve(null));
|
|
163
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
164
|
+
req.write(data);
|
|
165
|
+
req.end();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return (async () => {
|
|
169
|
+
await call('deleteWebhook', { drop_pending_updates: true });
|
|
170
|
+
await call('getUpdates', { offset: -1, limit: 1, timeout: 0 });
|
|
171
|
+
// Brief pause to let Telegram release the polling slot
|
|
172
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
173
|
+
})();
|
|
174
|
+
}
|
|
175
|
+
|
|
147
176
|
module.exports = { TelegramAdapter };
|
|
@@ -162,7 +162,6 @@ const BRAILLE_SPINNER = /[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/;
|
|
|
162
162
|
const COMPLETION_RE = /[A-Z][a-z]*ed for \d+/;
|
|
163
163
|
const IDLE_RE = /○/;
|
|
164
164
|
const PROCESSING_RE = /●/;
|
|
165
|
-
const APPROVAL_RE = /◐/;
|
|
166
165
|
|
|
167
166
|
/**
|
|
168
167
|
* Strip TUI chrome from captured pane output.
|
|
@@ -203,7 +202,11 @@ function paneTail(name, n) {
|
|
|
203
202
|
/**
|
|
204
203
|
* Detect Claude Code's current state from pane output.
|
|
205
204
|
*
|
|
206
|
-
*
|
|
205
|
+
* Note: We launch with --dangerously-skip-permissions, so approval prompts (◐)
|
|
206
|
+
* should never appear. The detection is kept for robustness but no auto-approve
|
|
207
|
+
* action is taken — sending blind 'y' keystrokes is dangerous.
|
|
208
|
+
*
|
|
209
|
+
* @returns {'idle'|'processing'|'complete'|'unknown'}
|
|
207
210
|
*/
|
|
208
211
|
function detectState(name) {
|
|
209
212
|
const tail = paneTail(name, 15);
|
|
@@ -214,17 +217,12 @@ function detectState(name) {
|
|
|
214
217
|
return 'complete';
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
// Priority 2:
|
|
218
|
-
if (APPROVAL_RE.test(tail)) {
|
|
219
|
-
return 'approval';
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Priority 3: Idle indicator — waiting for input
|
|
220
|
+
// Priority 2: Idle indicator — waiting for input
|
|
223
221
|
if (IDLE_RE.test(tail)) {
|
|
224
222
|
return 'idle';
|
|
225
223
|
}
|
|
226
224
|
|
|
227
|
-
// Priority
|
|
225
|
+
// Priority 3: Processing indicator — still working
|
|
228
226
|
if (PROCESSING_RE.test(tail) || BRAILLE_SPINNER.test(tail)) {
|
|
229
227
|
return 'processing';
|
|
230
228
|
}
|
|
@@ -241,20 +239,6 @@ function isIdle(name) {
|
|
|
241
239
|
return state === 'idle' || state === 'complete';
|
|
242
240
|
}
|
|
243
241
|
|
|
244
|
-
/**
|
|
245
|
-
* Detect if Claude Code is showing an approval prompt (◐).
|
|
246
|
-
*/
|
|
247
|
-
function isApprovalPrompt(name) {
|
|
248
|
-
return detectState(name) === 'approval';
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Detect if Claude Code is actively processing (● or spinner).
|
|
253
|
-
*/
|
|
254
|
-
function isProcessing(name) {
|
|
255
|
-
return detectState(name) === 'processing';
|
|
256
|
-
}
|
|
257
|
-
|
|
258
242
|
// ── Context Management ─────────────────────────────────────────────────────────
|
|
259
243
|
//
|
|
260
244
|
// Claude Code has built-in auto-compact that triggers at ~95% context capacity.
|
|
@@ -398,11 +382,6 @@ function waitForIdle(name, timeoutMs) {
|
|
|
398
382
|
return resolve(false);
|
|
399
383
|
}
|
|
400
384
|
|
|
401
|
-
// Auto-approve any permission prompts
|
|
402
|
-
if (isApprovalPrompt(name)) {
|
|
403
|
-
tmuxSafe(`send-keys -t ${name}:0 'y' Enter`);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
385
|
if (isIdle(name)) {
|
|
407
386
|
return resolve(true);
|
|
408
387
|
}
|
|
@@ -431,11 +410,10 @@ function injectMessage(name, text) {
|
|
|
431
410
|
/**
|
|
432
411
|
* Capture the response after injecting a message.
|
|
433
412
|
*
|
|
434
|
-
* Detection priority
|
|
413
|
+
* Detection priority:
|
|
435
414
|
* P1: Completion message — "[Verb]ed for [N]s/m" (e.g. "Baked for 31s")
|
|
436
415
|
* P2: Idle indicator — ○ appears in pane tail
|
|
437
|
-
* P3:
|
|
438
|
-
* P4: Content stability — 3 consecutive polls with identical MD5 hash
|
|
416
|
+
* P3: Content stability — 3 consecutive polls with identical MD5 hash
|
|
439
417
|
*/
|
|
440
418
|
async function captureResponse(name, marker, engineConfig) {
|
|
441
419
|
const timeout = engineConfig.timeout || 300000;
|
|
@@ -475,16 +453,6 @@ async function captureResponse(name, marker, engineConfig) {
|
|
|
475
453
|
return setTimeout(poll, pollInterval);
|
|
476
454
|
}
|
|
477
455
|
|
|
478
|
-
// P3: Auto-approve permission prompts (◐)
|
|
479
|
-
if (state === 'approval') {
|
|
480
|
-
tmuxSafe(`send-keys -t ${name}:0 'y' Enter`);
|
|
481
|
-
sawProcessing = true; // approval implies processing started
|
|
482
|
-
stableCount = 0;
|
|
483
|
-
lastHash = hash;
|
|
484
|
-
// Brief pause after approval before next poll
|
|
485
|
-
return setTimeout(poll, 2000);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
456
|
// P1: Completion message — most reliable done signal
|
|
489
457
|
if (state === 'complete' && sawProcessing) {
|
|
490
458
|
return resolve(extractResponse(raw, marker));
|