@inetafrica/open-claudia 1.14.4 → 1.14.6

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 (3) hide show
  1. package/bot-agent.js +33 -3
  2. package/bot.js +33 -3
  3. package/package.json +1 -1
package/bot-agent.js CHANGED
@@ -719,6 +719,29 @@ function redactSensitive(value) {
719
719
  .replace(/([?&](?:token|access_token|refresh_token)=)[^\s&]+/gi, "$1[REDACTED]");
720
720
  }
721
721
 
722
+
723
+ function stripTerminalControls(value) {
724
+ return String(value || "")
725
+ // OSC 8 hyperlinks and other OSC sequences
726
+ .replace(/\x1b\][\s\S]*?(?:\x07|\x1b\\)/g, "")
727
+ // CSI ANSI sequences
728
+ .replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
729
+ // remaining non-printing controls except newline/tab
730
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
731
+ }
732
+
733
+ function isClaudeAuthUrl(url) {
734
+ try {
735
+ const u = new URL(url);
736
+ const host = u.hostname.toLowerCase();
737
+ return host === "claude.com" || host.endsWith(".claude.com") ||
738
+ host === "anthropic.com" || host.endsWith(".anthropic.com") ||
739
+ host === "localhost" || host === "127.0.0.1";
740
+ } catch (e) {
741
+ return false;
742
+ }
743
+ }
744
+
722
745
  function looksLikeClaudeToken(value) {
723
746
  const text = String(value || "").trim();
724
747
  return /^sk-ant-[A-Za-z0-9._-]+$/.test(text) || text.length >= 80 && /^[A-Za-z0-9._=-]+$/.test(text);
@@ -786,7 +809,7 @@ function extractClaudeToken(text) {
786
809
  }
787
810
 
788
811
  function extractUrls(text) {
789
- return [...String(text || "").matchAll(/https?:\/\/[^\s)]+/g)].map((m) => m[0]);
812
+ return [...stripTerminalControls(text).matchAll(/https?:\/\/[^\s)]+/g)].map((m) => m[0]);
790
813
  }
791
814
 
792
815
 
@@ -966,14 +989,16 @@ async function runClaudeAuthCommand(args, label, opts = {}) {
966
989
  await send(tokenStored ? "Claude OAuth token captured and stored. I did not print it." : "Claude OAuth token appeared, but I could not store it.");
967
990
  }
968
991
  for (const url of extractUrls(chunk)) {
992
+ if (!isClaudeAuthUrl(url)) continue;
969
993
  if (!sentUrls.has(url)) {
970
994
  sentUrls.add(url);
971
995
  await send(`${label} URL:\n${redactSensitive(url)}\n\nOpen it, complete the flow, then paste any code Claude asks for here.`);
972
996
  }
973
997
  }
974
- const redacted = redactSensitive(chunk).trim();
998
+ const redacted = redactSensitive(stripTerminalControls(chunk)).trim();
975
999
  const now = Date.now();
976
- if (redacted && now - lastSnippetAt > 3000 && !looksLikeClaudeToken(redacted)) {
1000
+ const usefulAuthLine = /opening browser|paste code|enter code|login|auth|token|error|failed/i.test(redacted);
1001
+ if (redacted && usefulAuthLine && now - lastSnippetAt > 3000 && !looksLikeClaudeToken(redacted) && !/github\.com\/vadimdemedes\/ink/i.test(redacted)) {
977
1002
  lastSnippetAt = now;
978
1003
  await send(redacted.length > 1200 ? redacted.slice(-1200) : redacted);
979
1004
  }
@@ -2021,6 +2046,11 @@ bot.on("message", async (msg) => {
2021
2046
  }
2022
2047
 
2023
2048
  if (pendingClaudeAuthProcess && pendingClaudeAuthLabel !== "manual OAuth token save") {
2049
+ const text = msg.text.trim();
2050
+ if (looksLikeClaudeAuthReply(text)) {
2051
+ await send("That looks like a Claude login code/callback. I did not delete it or send it to Claude as a prompt. Please resend it as `/auth_code YOUR_CODE`, or use /cancel_auth to stop the login flow.");
2052
+ return;
2053
+ }
2024
2054
  await send("Claude login is still waiting. I will not delete normal messages. If Claude gave you a code, send it as `/auth_code YOUR_CODE`, or use /cancel_auth.");
2025
2055
  }
2026
2056
 
package/bot.js CHANGED
@@ -781,6 +781,29 @@ function redactSensitive(value) {
781
781
  .replace(/([?&](?:token|access_token|refresh_token)=)[^\s&]+/gi, "$1[REDACTED]");
782
782
  }
783
783
 
784
+
785
+ function stripTerminalControls(value) {
786
+ return String(value || "")
787
+ // OSC 8 hyperlinks and other OSC sequences
788
+ .replace(/\x1b\][\s\S]*?(?:\x07|\x1b\\)/g, "")
789
+ // CSI ANSI sequences
790
+ .replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
791
+ // remaining non-printing controls except newline/tab
792
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
793
+ }
794
+
795
+ function isClaudeAuthUrl(url) {
796
+ try {
797
+ const u = new URL(url);
798
+ const host = u.hostname.toLowerCase();
799
+ return host === "claude.com" || host.endsWith(".claude.com") ||
800
+ host === "anthropic.com" || host.endsWith(".anthropic.com") ||
801
+ host === "localhost" || host === "127.0.0.1";
802
+ } catch (e) {
803
+ return false;
804
+ }
805
+ }
806
+
784
807
  function looksLikeClaudeToken(value) {
785
808
  const text = String(value || "").trim();
786
809
  return /^sk-ant-[A-Za-z0-9._-]+$/.test(text) || text.length >= 80 && /^[A-Za-z0-9._=-]+$/.test(text);
@@ -848,7 +871,7 @@ function extractClaudeToken(text) {
848
871
  }
849
872
 
850
873
  function extractUrls(text) {
851
- return [...String(text || "").matchAll(/https?:\/\/[^\s)]+/g)].map((m) => m[0]);
874
+ return [...stripTerminalControls(text).matchAll(/https?:\/\/[^\s)]+/g)].map((m) => m[0]);
852
875
  }
853
876
 
854
877
 
@@ -1028,14 +1051,16 @@ async function runClaudeAuthCommand(args, label, opts = {}) {
1028
1051
  await send(tokenStored ? "Claude OAuth token captured and stored. I did not print it." : "Claude OAuth token appeared, but I could not store it.");
1029
1052
  }
1030
1053
  for (const url of extractUrls(chunk)) {
1054
+ if (!isClaudeAuthUrl(url)) continue;
1031
1055
  if (!sentUrls.has(url)) {
1032
1056
  sentUrls.add(url);
1033
1057
  await send(`${label} URL:\n${redactSensitive(url)}\n\nOpen it, complete the flow, then paste any code Claude asks for here.`);
1034
1058
  }
1035
1059
  }
1036
- const redacted = redactSensitive(chunk).trim();
1060
+ const redacted = redactSensitive(stripTerminalControls(chunk)).trim();
1037
1061
  const now = Date.now();
1038
- if (redacted && now - lastSnippetAt > 3000 && !looksLikeClaudeToken(redacted)) {
1062
+ const usefulAuthLine = /opening browser|paste code|enter code|login|auth|token|error|failed/i.test(redacted);
1063
+ if (redacted && usefulAuthLine && now - lastSnippetAt > 3000 && !looksLikeClaudeToken(redacted) && !/github\.com\/vadimdemedes\/ink/i.test(redacted)) {
1039
1064
  lastSnippetAt = now;
1040
1065
  await send(redacted.length > 1200 ? redacted.slice(-1200) : redacted);
1041
1066
  }
@@ -2060,6 +2085,11 @@ bot.on("message", async (msg) => {
2060
2085
  }
2061
2086
 
2062
2087
  if (pendingClaudeAuthProcess && pendingClaudeAuthLabel !== "manual OAuth token save") {
2088
+ const text = msg.text.trim();
2089
+ if (looksLikeClaudeAuthReply(text)) {
2090
+ await send("That looks like a Claude login code/callback. I did not delete it or send it to Claude as a prompt. Please resend it as `/auth_code YOUR_CODE`, or use /cancel_auth to stop the login flow.");
2091
+ return;
2092
+ }
2063
2093
  await send("Claude login is still waiting. I will not delete normal messages. If Claude gave you a code, send it as `/auth_code YOUR_CODE`, or use /cancel_auth.");
2064
2094
  }
2065
2095
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "1.14.4",
3
+ "version": "1.14.6",
4
4
  "description": "Your always-on AI coding assistant — Claude Code via Telegram",
5
5
  "main": "bot.js",
6
6
  "bin": {