@pixelbyte-software/pixcode 1.53.15 → 1.53.17

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.
@@ -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 isNoisyTerminalBridgeLine(line, prompt) {
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 lines = text
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 ? 2800 : 2200));
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,7 +912,7 @@ async function sendToActiveTerminal({ bot, chatId, link, text }) {
827
912
  projectPath: terminal.projectPath,
828
913
  tabId: terminal.tabId,
829
914
  sessionId: terminal.sessionId,
830
- input: text,
915
+ input: terminalPrompt,
831
916
  submit: true,
832
917
  submitMode: 'deferred-enter',
833
918
  },
@@ -852,7 +937,7 @@ async function sendToActiveTerminal({ bot, chatId, link, text }) {
852
937
  chatId,
853
938
  link,
854
939
  terminal,
855
- prompt: text,
940
+ prompt: terminalPrompt,
856
941
  sinceCursor,
857
942
  editMessageId,
858
943
  monitorKey,