@pixelbyte-software/pixcode 1.53.14 → 1.53.16
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/assets/{index-CV_x2mrI.js → index-BgMvphaU.js} +1 -1
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +29 -1
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/services/telegram/control-center.js +96 -10
- package/dist-server/server/services/telegram/control-center.js.map +1 -1
- package/dist-server/server/utils/url-detection.js +1 -1
- package/dist-server/server/utils/url-detection.js.map +1 -1
- package/package.json +1 -1
- package/scripts/smoke/telegram-control.mjs +41 -0
- package/server/index.js +28 -1
- package/server/services/telegram/control-center.js +98 -10
- package/server/utils/url-detection.js +1 -1
|
@@ -18,6 +18,8 @@ const TERMINAL_BRIDGE_TIMEOUT_MS = 5 * 60 * 1000;
|
|
|
18
18
|
const TERMINAL_BRIDGE_POLL_MS = 1500;
|
|
19
19
|
const TERMINAL_BRIDGE_EDIT_THROTTLE_MS = 3500;
|
|
20
20
|
const TERMINAL_BRIDGE_SETTLE_MS = 6000;
|
|
21
|
+
const TERMINAL_BRIDGE_FINAL_OPEN = '<PIXCODE_TELEGRAM_FINAL>';
|
|
22
|
+
const TERMINAL_BRIDGE_FINAL_CLOSE = '</PIXCODE_TELEGRAM_FINAL>';
|
|
21
23
|
const callbackActions = new Map();
|
|
22
24
|
const runMonitors = new Map();
|
|
23
25
|
const activeLongTasks = new Map();
|
|
@@ -585,17 +587,91 @@ function terminalBridgeMonitorKey(chatId, terminal) {
|
|
|
585
587
|
terminal.sessionId || '-',
|
|
586
588
|
].join(':');
|
|
587
589
|
}
|
|
590
|
+
function escapeRegExp(value) {
|
|
591
|
+
return String(value || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
592
|
+
}
|
|
593
|
+
function terminalBridgeInput(text, lang) {
|
|
594
|
+
const prompt = String(text || '').trim();
|
|
595
|
+
const instruction = lang === 'tr'
|
|
596
|
+
? `Pixcode Telegram senkronu: Yanıtının sonunda Telegram için okunabilir ve eksiksiz final cevabını ${TERMINAL_BRIDGE_FINAL_OPEN} ve ${TERMINAL_BRIDGE_FINAL_CLOSE} etiketleri arasına yaz. Etiketlerin içine spinner, terminal ekranı veya tekrar eden durum satırı koyma.`
|
|
597
|
+
: `Pixcode Telegram sync: At the end of your response, write the readable complete final answer for Telegram between ${TERMINAL_BRIDGE_FINAL_OPEN} and ${TERMINAL_BRIDGE_FINAL_CLOSE}. Do not put spinners, terminal screen text, or repeated status lines inside the tags.`;
|
|
598
|
+
return `${prompt}\n\n${instruction}`;
|
|
599
|
+
}
|
|
588
600
|
function normalizeBridgeLine(value) {
|
|
589
601
|
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
590
602
|
}
|
|
591
|
-
function
|
|
603
|
+
function terminalBridgeLabels(terminal) {
|
|
604
|
+
const labels = new Set();
|
|
605
|
+
for (const value of [
|
|
606
|
+
terminal?.provider,
|
|
607
|
+
terminal?.projectName,
|
|
608
|
+
terminal?.projectLabel,
|
|
609
|
+
terminal?.projectPath,
|
|
610
|
+
]) {
|
|
611
|
+
const normalized = normalizeBridgeLine(value);
|
|
612
|
+
if (!normalized)
|
|
613
|
+
continue;
|
|
614
|
+
labels.add(normalized);
|
|
615
|
+
const pathParts = normalized.split(/[\\/]/u).filter(Boolean);
|
|
616
|
+
const basename = pathParts.at(-1);
|
|
617
|
+
if (basename)
|
|
618
|
+
labels.add(basename);
|
|
619
|
+
}
|
|
620
|
+
return [...labels]
|
|
621
|
+
.map((value) => value.trim())
|
|
622
|
+
.filter((value) => value.length >= 2)
|
|
623
|
+
.sort((a, b) => b.length - a.length);
|
|
624
|
+
}
|
|
625
|
+
function stripTerminalBridgeFragments(value, terminal) {
|
|
626
|
+
let text = String(value || '');
|
|
627
|
+
text = text.replace(/\[[0-?]{1,32}[ -/]*[@-~]/gu, ' ');
|
|
628
|
+
text = text.replace(/\b\d{1,3}(?:;\d{1,3}){1,8}[A-Za-z]/gu, ' ');
|
|
629
|
+
text = text.replace(/\b[012];[^\n\r]{0,100}[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳][^\n\r]{0,100}/gu, ' ');
|
|
630
|
+
for (const label of terminalBridgeLabels(terminal)) {
|
|
631
|
+
const labelPattern = escapeRegExp(label).replace(/\s+/gu, '\\s+');
|
|
632
|
+
const titlePattern = new RegExp(String.raw `\b(?:\d+[a-z])?[012];[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳•*·\s-]*${labelPattern}(?:\d+;?)?`, 'giu');
|
|
633
|
+
text = text.replace(titlePattern, ' ');
|
|
634
|
+
}
|
|
635
|
+
return text
|
|
636
|
+
.replace(/[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳]+/gu, ' ')
|
|
637
|
+
.replace(/\b(?:Working|Determining|Thinking|Running)(?:\s*•\s*(?:Working|Determining|Thinking|Running))+\b/giu, ' ');
|
|
638
|
+
}
|
|
639
|
+
function extractTerminalBridgeFinalBlock(text) {
|
|
640
|
+
const blocks = [];
|
|
641
|
+
const blockPattern = /(?:<|\[)\s*PIXCODE_TELEGRAM_FINAL\s*(?:>|\])([\s\S]*?)(?:<|\[)\s*\/\s*PIXCODE_TELEGRAM_FINAL\s*(?:>|\])/giu;
|
|
642
|
+
for (const match of text.matchAll(blockPattern)) {
|
|
643
|
+
const block = String(match[1] || '').trim();
|
|
644
|
+
if (block)
|
|
645
|
+
blocks.push(block);
|
|
646
|
+
}
|
|
647
|
+
if (blocks.length > 0)
|
|
648
|
+
return blocks.at(-1);
|
|
649
|
+
const openPattern = /(?:<|\[)\s*PIXCODE_TELEGRAM_FINAL\s*(?:>|\])/giu;
|
|
650
|
+
let lastOpen = null;
|
|
651
|
+
for (const match of text.matchAll(openPattern))
|
|
652
|
+
lastOpen = match;
|
|
653
|
+
if (!lastOpen)
|
|
654
|
+
return '';
|
|
655
|
+
return text.slice((lastOpen.index || 0) + lastOpen[0].length).trim();
|
|
656
|
+
}
|
|
657
|
+
function isNoisyTerminalBridgeLine(line, prompt, terminal) {
|
|
592
658
|
const normalized = normalizeBridgeLine(line);
|
|
593
659
|
if (!normalized || normalized.length <= 1)
|
|
594
660
|
return true;
|
|
661
|
+
if (/PIXCODE_TELEGRAM_FINAL/iu.test(normalized))
|
|
662
|
+
return true;
|
|
663
|
+
if (/Pixcode Telegram (?:sync|senkronu)/iu.test(normalized))
|
|
664
|
+
return true;
|
|
595
665
|
if (/^[╭╮╰╯│─═┌┐└┘├┤┬┴┼\s]+$/u.test(normalized))
|
|
596
666
|
return true;
|
|
597
667
|
if (/^[●✶✻✽✢✳⠂⠐⏵·\s0;:()\-|/\\]+$/u.test(normalized))
|
|
598
668
|
return true;
|
|
669
|
+
if (/^\[[0-?]{1,32}[ -/]*[@-~]/u.test(normalized))
|
|
670
|
+
return true;
|
|
671
|
+
if (/^(?:\d+[a-z])?[012];/iu.test(normalized) && /[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳]/u.test(normalized))
|
|
672
|
+
return true;
|
|
673
|
+
if ((normalized.match(/[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳]/gu) || []).length >= 2)
|
|
674
|
+
return true;
|
|
599
675
|
const lower = normalized.toLowerCase();
|
|
600
676
|
const promptNeedle = normalizeBridgeLine(prompt).toLowerCase();
|
|
601
677
|
if (promptNeedle && lower.includes(promptNeedle.slice(0, 120)))
|
|
@@ -620,17 +696,25 @@ function isNoisyTerminalBridgeLine(line, prompt) {
|
|
|
620
696
|
return true;
|
|
621
697
|
if (/^\(?\d+s\s*·\s*[↓↑]?\d*\s*tokens?\)?$/iu.test(normalized))
|
|
622
698
|
return true;
|
|
699
|
+
for (const label of terminalBridgeLabels(terminal)) {
|
|
700
|
+
if (lower.includes(label.toLowerCase())
|
|
701
|
+
&& /(?:^[012];|[⠂⠐⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏✶✻✽✢✳]|working|determining)/iu.test(normalized)) {
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
623
705
|
return false;
|
|
624
706
|
}
|
|
625
|
-
function cleanTerminalBridgeOutput(output, prompt) {
|
|
626
|
-
const text = String(output || '')
|
|
707
|
+
export function cleanTerminalBridgeOutput(output, prompt, terminal = null) {
|
|
708
|
+
const text = stripTerminalBridgeFragments(String(output || ''), terminal)
|
|
627
709
|
.replace(/\r/g, '\n')
|
|
628
710
|
.replace(/[\x00-\x08\x0B-\x1F\x7F]/g, '')
|
|
629
711
|
.replace(/\u00a0/g, ' ');
|
|
630
|
-
const
|
|
712
|
+
const finalBlock = extractTerminalBridgeFinalBlock(text);
|
|
713
|
+
const source = finalBlock || text;
|
|
714
|
+
const lines = source
|
|
631
715
|
.split('\n')
|
|
632
716
|
.map((line) => line.replace(/[ \t]+/g, ' ').trim())
|
|
633
|
-
.filter((line) => !isNoisyTerminalBridgeLine(line, prompt));
|
|
717
|
+
.filter((line) => !isNoisyTerminalBridgeLine(line, prompt, terminal));
|
|
634
718
|
const deduped = [];
|
|
635
719
|
for (const line of lines) {
|
|
636
720
|
if (deduped.at(-1) === line)
|
|
@@ -649,12 +733,12 @@ function renderTerminalBridgeProgress(lang, terminal, { output = '', statusKey =
|
|
|
649
733
|
if (terminal.sessionId) {
|
|
650
734
|
lines.push(`🧵 ${t(lang, 'control.activity.session')}: ${terminal.sessionId}`);
|
|
651
735
|
}
|
|
652
|
-
if (terminalState) {
|
|
736
|
+
if (terminalState && terminalState !== 'unknown') {
|
|
653
737
|
lines.push(`📌 ${t(lang, 'control.activity.status')}: ${terminalState}`);
|
|
654
738
|
}
|
|
655
739
|
if (output) {
|
|
656
740
|
lines.push('', `💬 ${t(lang, 'control.activity.output')}:`);
|
|
657
|
-
lines.push(truncate(output, final ?
|
|
741
|
+
lines.push(truncate(output, final ? 3100 : 2200));
|
|
658
742
|
}
|
|
659
743
|
else {
|
|
660
744
|
lines.push('', t(lang, 'control.terminalWaitingHint'));
|
|
@@ -691,7 +775,7 @@ async function monitorTerminalBridgeResponse({ bot, chatId, link, terminal, prom
|
|
|
691
775
|
});
|
|
692
776
|
return;
|
|
693
777
|
}
|
|
694
|
-
const cleanOutput = cleanTerminalBridgeOutput(data?.output, prompt);
|
|
778
|
+
const cleanOutput = cleanTerminalBridgeOutput(data?.output, prompt, terminal);
|
|
695
779
|
const terminalState = data?.terminalState || data?.lifecycleState || 'unknown';
|
|
696
780
|
const now = Date.now();
|
|
697
781
|
if (cleanOutput && cleanOutput !== lastCleanOutput) {
|
|
@@ -819,6 +903,7 @@ async function sendToActiveTerminal({ bot, chatId, link, text }) {
|
|
|
819
903
|
});
|
|
820
904
|
const editMessageId = sent?.message_id || sent?.message?.message_id || null;
|
|
821
905
|
try {
|
|
906
|
+
const terminalPrompt = terminalBridgeInput(text, lang);
|
|
822
907
|
const inputResult = await localApi(link.user_id, '/api/shell/sessions/provider-input', {
|
|
823
908
|
method: 'POST',
|
|
824
909
|
timeoutMs: 15_000,
|
|
@@ -827,8 +912,9 @@ async function sendToActiveTerminal({ bot, chatId, link, text }) {
|
|
|
827
912
|
projectPath: terminal.projectPath,
|
|
828
913
|
tabId: terminal.tabId,
|
|
829
914
|
sessionId: terminal.sessionId,
|
|
830
|
-
input:
|
|
915
|
+
input: terminalPrompt,
|
|
831
916
|
submit: true,
|
|
917
|
+
submitMode: 'deferred-enter',
|
|
832
918
|
},
|
|
833
919
|
});
|
|
834
920
|
const sinceCursor = Number.isFinite(inputResult?.outputCursorBefore)
|
|
@@ -851,7 +937,7 @@ async function sendToActiveTerminal({ bot, chatId, link, text }) {
|
|
|
851
937
|
chatId,
|
|
852
938
|
link,
|
|
853
939
|
terminal,
|
|
854
|
-
prompt:
|
|
940
|
+
prompt: terminalPrompt,
|
|
855
941
|
sinceCursor,
|
|
856
942
|
editMessageId,
|
|
857
943
|
monitorKey,
|