@inetafrica/open-claudia 1.14.5 → 1.14.7
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/bot-agent.js +36 -6
- package/bot.js +36 -6
- 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 [...
|
|
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
|
-
|
|
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
|
}
|
|
@@ -986,12 +1011,17 @@ async function runClaudeAuthCommand(args, label, opts = {}) {
|
|
|
986
1011
|
pendingClaudeAuthLabel = null;
|
|
987
1012
|
const token = opts.captureToken ? extractClaudeToken(output) : null;
|
|
988
1013
|
if (token && !tokenStored) tokenStored = saveClaudeOAuthToken(token);
|
|
989
|
-
const
|
|
1014
|
+
const cleaned = redactSensitive(stripTerminalControls(output))
|
|
1015
|
+
.replace(/https?:\/\/github\.com\/vadimdemedes\/ink\S*/gi, "")
|
|
1016
|
+
.trim();
|
|
1017
|
+
const isTtyError = /raw mode is not supported|process\.stdin/i.test(output);
|
|
990
1018
|
if (tokenStored) {
|
|
991
1019
|
await send(`${label} finished. OAuth token stored for launchd/non-interactive Claude runs.`);
|
|
992
1020
|
await sendClaudeAuthStatusSummary("Post-auth check:");
|
|
993
|
-
} else if (
|
|
994
|
-
await send(`${label}
|
|
1021
|
+
} else if (isTtyError && opts.captureToken) {
|
|
1022
|
+
await send(`${label} cannot complete from this bot — the Claude CLI needs an interactive terminal for setup-token.\n\nRun this in your Mac terminal:\n claude setup-token\n\nThen paste the token here with:\n /use_oauth_token <token>`);
|
|
1023
|
+
} else if (cleaned) {
|
|
1024
|
+
await send(`${label} finished (exit ${code}).\n\n${cleaned.slice(-2500)}`);
|
|
995
1025
|
await sendClaudeAuthStatusSummary("Post-auth check:");
|
|
996
1026
|
} else {
|
|
997
1027
|
await send(`${label} finished (exit ${code}).`);
|
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 [...
|
|
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
|
-
|
|
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
|
}
|
|
@@ -1048,12 +1073,17 @@ async function runClaudeAuthCommand(args, label, opts = {}) {
|
|
|
1048
1073
|
pendingClaudeAuthLabel = null;
|
|
1049
1074
|
const token = opts.captureToken ? extractClaudeToken(output) : null;
|
|
1050
1075
|
if (token && !tokenStored) tokenStored = saveClaudeOAuthToken(token);
|
|
1051
|
-
const
|
|
1076
|
+
const cleaned = redactSensitive(stripTerminalControls(output))
|
|
1077
|
+
.replace(/https?:\/\/github\.com\/vadimdemedes\/ink\S*/gi, "")
|
|
1078
|
+
.trim();
|
|
1079
|
+
const isTtyError = /raw mode is not supported|process\.stdin/i.test(output);
|
|
1052
1080
|
if (tokenStored) {
|
|
1053
1081
|
await send(`${label} finished. OAuth token stored for launchd/non-interactive Claude runs.`);
|
|
1054
1082
|
await sendClaudeAuthStatusSummary("Post-auth check:");
|
|
1055
|
-
} else if (
|
|
1056
|
-
await send(`${label}
|
|
1083
|
+
} else if (isTtyError && opts.captureToken) {
|
|
1084
|
+
await send(`${label} cannot complete from this bot — the Claude CLI needs an interactive terminal for setup-token.\n\nRun this in your Mac terminal:\n claude setup-token\n\nThen paste the token here with:\n /use_oauth_token <token>`);
|
|
1085
|
+
} else if (cleaned) {
|
|
1086
|
+
await send(`${label} finished (exit ${code}).\n\n${cleaned.slice(-2500)}`);
|
|
1057
1087
|
await sendClaudeAuthStatusSummary("Post-auth check:");
|
|
1058
1088
|
} else {
|
|
1059
1089
|
await send(`${label} finished (exit ${code}).`);
|