@inetafrica/open-claudia 1.14.2 → 1.14.4

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 +61 -20
  2. package/bot.js +61 -20
  3. package/package.json +1 -1
package/bot-agent.js CHANGED
@@ -724,6 +724,25 @@ function looksLikeClaudeToken(value) {
724
724
  return /^sk-ant-[A-Za-z0-9._-]+$/.test(text) || text.length >= 80 && /^[A-Za-z0-9._=-]+$/.test(text);
725
725
  }
726
726
 
727
+
728
+ function looksLikeClaudeAuthReply(value) {
729
+ const text = String(value || "").trim();
730
+ if (!text) return false;
731
+ if (looksLikeClaudeToken(text)) return true;
732
+ if (/^https?:\/\//i.test(text) && /claude|anthropic/i.test(text)) return true;
733
+ // OAuth callback/login codes are usually long, dense strings. Do not consume normal chat.
734
+ if (text.length >= 24 && !/\s/.test(text) && /^[A-Za-z0-9._~:/?#[\]@!$&'()*+,;=%-]+$/.test(text)) return true;
735
+ return false;
736
+ }
737
+
738
+ function clearPendingClaudeAuth() {
739
+ if (pendingClaudeAuthProcess && pendingClaudeAuthProcess.kill) {
740
+ try { pendingClaudeAuthProcess.kill("SIGTERM"); } catch (e) {}
741
+ }
742
+ pendingClaudeAuthProcess = null;
743
+ pendingClaudeAuthLabel = null;
744
+ }
745
+
727
746
  function getClaudeOAuthToken() {
728
747
  if (config[CLAUDE_OAUTH_TOKEN_KEY]) return { value: config[CLAUDE_OAUTH_TOKEN_KEY], source: ".env" };
729
748
  if (process.env.CLAUDE_CODE_OAUTH_TOKEN) return { value: process.env.CLAUDE_CODE_OAUTH_TOKEN, source: "process env" };
@@ -1452,7 +1471,7 @@ bot.onText(/\/upgrade$/, async (msg) => {
1452
1471
  await send("Upgrading...");
1453
1472
  }
1454
1473
  try {
1455
- execSync("npm install -g @inetafrica/open-claudia@latest 2>&1", {
1474
+ execSync(`npm install -g @inetafrica/open-claudia@${latest} 2>&1`, {
1456
1475
  encoding: "utf-8", timeout: 120000,
1457
1476
  cwd: process.env.HOME || require("os").homedir(),
1458
1477
  env: { ...process.env, PATH: FULL_PATH, HOME: process.env.HOME || require("os").homedir() },
@@ -1463,8 +1482,9 @@ bot.onText(/\/upgrade$/, async (msg) => {
1463
1482
  let whatsNew = "";
1464
1483
  try {
1465
1484
  const changelog = fs.readFileSync(path.join(root, "@inetafrica", "open-claudia", "CHANGELOG.md"), "utf-8");
1466
- const versionHeader = `## v${newPkg.version}`;
1467
- const start = changelog.indexOf(versionHeader);
1485
+ let versionHeader = `## v${newPkg.version}`;
1486
+ let start = changelog.indexOf(versionHeader);
1487
+ if (start < 0) { versionHeader = `## ${newPkg.version}`; start = changelog.indexOf(versionHeader); }
1468
1488
  if (start >= 0) {
1469
1489
  const afterHeader = changelog.slice(start + versionHeader.length);
1470
1490
  const nextVersion = afterHeader.indexOf("\n## ");
@@ -1691,6 +1711,32 @@ bot.onText(/\/(?:auth_status|auth status)$/, async (msg) => {
1691
1711
  proc.on("error", async (err) => send(`Claude auth status failed: ${redactSensitive(err.message)}`));
1692
1712
  });
1693
1713
 
1714
+ bot.onText(/\/cancel_auth$/, async (msg) => {
1715
+ if (!isAuthorized(msg)) return;
1716
+ if (!pendingClaudeAuthProcess) return send("No Claude auth flow is pending.");
1717
+ clearPendingClaudeAuth();
1718
+ await send("Claude auth flow cancelled. Normal messages will go to the assistant again.");
1719
+ });
1720
+
1721
+ bot.onText(/\/auth_code(?:\s+(.+))?$/, async (msg, match) => {
1722
+ if (!isAuthorized(msg)) return;
1723
+ const code = (match[1] || "").trim();
1724
+ await deleteMessage(msg.message_id);
1725
+ if (!pendingClaudeAuthProcess || pendingClaudeAuthLabel === "manual OAuth token save") {
1726
+ return send("No Claude login flow is waiting for an auth code. Start with /login, or use /use_oauth_token for tokens.");
1727
+ }
1728
+ if (!code || !looksLikeClaudeAuthReply(code)) {
1729
+ return send("That does not look like a Claude auth code/callback. Use /cancel_auth to cancel the login flow.");
1730
+ }
1731
+ try {
1732
+ pendingClaudeAuthProcess.stdin.write(code + "\n");
1733
+ await send("Auth code sent to Claude. I’ll confirm with auth status when Claude finishes.");
1734
+ } catch (e) {
1735
+ clearPendingClaudeAuth();
1736
+ await send(`Could not send auth code to Claude: ${redactSensitive(e.message)}`);
1737
+ }
1738
+ });
1739
+
1694
1740
  bot.onText(/\/login$/, async (msg) => {
1695
1741
  if (!isAuthorized(msg)) return;
1696
1742
  await runClaudeAuthCommand(["auth", "login", "--claudeai", "--email", "sumeet@inet.africa"], "Claude login");
@@ -1959,28 +2005,23 @@ bot.on("message", async (msg) => {
1959
2005
  if (msg.voice || msg.audio || msg.photo || msg.document || msg.video || msg.sticker) return;
1960
2006
  if (isDuplicate(msg.message_id)) return;
1961
2007
 
1962
- // Handle pending Claude auth/token paste-back
1963
- if (pendingClaudeAuthProcess) {
2008
+ // Handle pending manual OAuth token paste mode. Login codes must be sent explicitly
2009
+ // with /auth_code so normal chat can never be deleted/consumed accidentally.
2010
+ if (pendingClaudeAuthProcess && pendingClaudeAuthLabel === "manual OAuth token save") {
1964
2011
  const text = msg.text.trim();
1965
- await deleteMessage(msg.message_id);
1966
- if (pendingClaudeAuthLabel === "manual OAuth token save") {
1967
- pendingClaudeAuthProcess = null;
1968
- pendingClaudeAuthLabel = null;
1969
- if (!looksLikeClaudeToken(text)) { await send("That doesn't look like a Claude OAuth token. Not saved."); return; }
2012
+ if (looksLikeClaudeToken(text)) {
2013
+ await deleteMessage(msg.message_id);
2014
+ clearPendingClaudeAuth();
1970
2015
  saveClaudeOAuthToken(text);
1971
2016
  await send(`Claude OAuth token stored in .env${vault.isUnlocked() ? " and vault" : ""}. Restart the bot so launchd picks it up, or use /restart.`);
1972
- await sendClaudeAuthStatusSummary("Stored token. Current Claude auth status:");
2017
+ await sendClaudeAuthStatusSummary("Stored token. Current Claude auth status:");
1973
2018
  return;
1974
2019
  }
1975
- try {
1976
- pendingClaudeAuthProcess.stdin.write(text + "\n");
1977
- await send("Sent to Claude auth process. I’ll confirm when Claude finishes the auth check.");
1978
- } catch (e) {
1979
- pendingClaudeAuthProcess = null;
1980
- pendingClaudeAuthLabel = null;
1981
- await send(`Could not send to Claude auth process: ${redactSensitive(e.message)}`);
1982
- }
1983
- return;
2020
+ await send("Token paste mode is active, but that does not look like a Claude OAuth token. I left your message visible and will handle it normally. Send /cancel_auth to stop token paste mode.");
2021
+ }
2022
+
2023
+ if (pendingClaudeAuthProcess && pendingClaudeAuthLabel !== "manual OAuth token save") {
2024
+ 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.");
1984
2025
  }
1985
2026
 
1986
2027
  // Handle onboarding
package/bot.js CHANGED
@@ -786,6 +786,25 @@ function looksLikeClaudeToken(value) {
786
786
  return /^sk-ant-[A-Za-z0-9._-]+$/.test(text) || text.length >= 80 && /^[A-Za-z0-9._=-]+$/.test(text);
787
787
  }
788
788
 
789
+
790
+ function looksLikeClaudeAuthReply(value) {
791
+ const text = String(value || "").trim();
792
+ if (!text) return false;
793
+ if (looksLikeClaudeToken(text)) return true;
794
+ if (/^https?:\/\//i.test(text) && /claude|anthropic/i.test(text)) return true;
795
+ // OAuth callback/login codes are usually long, dense strings. Do not consume normal chat.
796
+ if (text.length >= 24 && !/\s/.test(text) && /^[A-Za-z0-9._~:/?#[\]@!$&'()*+,;=%-]+$/.test(text)) return true;
797
+ return false;
798
+ }
799
+
800
+ function clearPendingClaudeAuth() {
801
+ if (pendingClaudeAuthProcess && pendingClaudeAuthProcess.kill) {
802
+ try { pendingClaudeAuthProcess.kill("SIGTERM"); } catch (e) {}
803
+ }
804
+ pendingClaudeAuthProcess = null;
805
+ pendingClaudeAuthLabel = null;
806
+ }
807
+
789
808
  function getClaudeOAuthToken() {
790
809
  if (config[CLAUDE_OAUTH_TOKEN_KEY]) return { value: config[CLAUDE_OAUTH_TOKEN_KEY], source: ".env" };
791
810
  if (process.env.CLAUDE_CODE_OAUTH_TOKEN) return { value: process.env.CLAUDE_CODE_OAUTH_TOKEN, source: "process env" };
@@ -1483,7 +1502,7 @@ bot.onText(/\/upgrade$/, async (msg) => {
1483
1502
  await send("Upgrading...");
1484
1503
  }
1485
1504
  try {
1486
- execSync("npm install -g @inetafrica/open-claudia@latest 2>&1", {
1505
+ execSync(`npm install -g @inetafrica/open-claudia@${latest} 2>&1`, {
1487
1506
  encoding: "utf-8", timeout: 120000,
1488
1507
  cwd: process.env.HOME || require("os").homedir(),
1489
1508
  env: { ...process.env, PATH: FULL_PATH, HOME: process.env.HOME || require("os").homedir() },
@@ -1500,8 +1519,9 @@ bot.onText(/\/upgrade$/, async (msg) => {
1500
1519
  let whatsNew = "";
1501
1520
  try {
1502
1521
  const changelog = fs.readFileSync(path.join(root, "@inetafrica", "open-claudia", "CHANGELOG.md"), "utf-8");
1503
- const versionHeader = `## v${newPkg.version}`;
1504
- const start = changelog.indexOf(versionHeader);
1522
+ let versionHeader = `## v${newPkg.version}`;
1523
+ let start = changelog.indexOf(versionHeader);
1524
+ if (start < 0) { versionHeader = `## ${newPkg.version}`; start = changelog.indexOf(versionHeader); }
1505
1525
  if (start >= 0) {
1506
1526
  const afterHeader = changelog.slice(start + versionHeader.length);
1507
1527
  const nextVersion = afterHeader.indexOf("\n## ");
@@ -1722,6 +1742,32 @@ bot.onText(/\/(?:auth_status|auth status)$/, async (msg) => {
1722
1742
  proc.on("error", async (err) => send(`Claude auth status failed: ${redactSensitive(err.message)}`));
1723
1743
  });
1724
1744
 
1745
+ bot.onText(/\/cancel_auth$/, async (msg) => {
1746
+ if (!isAuthorized(msg)) return;
1747
+ if (!pendingClaudeAuthProcess) return send("No Claude auth flow is pending.");
1748
+ clearPendingClaudeAuth();
1749
+ await send("Claude auth flow cancelled. Normal messages will go to the assistant again.");
1750
+ });
1751
+
1752
+ bot.onText(/\/auth_code(?:\s+(.+))?$/, async (msg, match) => {
1753
+ if (!isAuthorized(msg)) return;
1754
+ const code = (match[1] || "").trim();
1755
+ await deleteMessage(msg.message_id);
1756
+ if (!pendingClaudeAuthProcess || pendingClaudeAuthLabel === "manual OAuth token save") {
1757
+ return send("No Claude login flow is waiting for an auth code. Start with /login, or use /use_oauth_token for tokens.");
1758
+ }
1759
+ if (!code || !looksLikeClaudeAuthReply(code)) {
1760
+ return send("That does not look like a Claude auth code/callback. Use /cancel_auth to cancel the login flow.");
1761
+ }
1762
+ try {
1763
+ pendingClaudeAuthProcess.stdin.write(code + "\n");
1764
+ await send("Auth code sent to Claude. I’ll confirm with auth status when Claude finishes.");
1765
+ } catch (e) {
1766
+ clearPendingClaudeAuth();
1767
+ await send(`Could not send auth code to Claude: ${redactSensitive(e.message)}`);
1768
+ }
1769
+ });
1770
+
1725
1771
  bot.onText(/\/login$/, async (msg) => {
1726
1772
  if (!isAuthorized(msg)) return;
1727
1773
  await runClaudeAuthCommand(["auth", "login", "--claudeai", "--email", "sumeet@inet.africa"], "Claude login");
@@ -1998,28 +2044,23 @@ bot.on("message", async (msg) => {
1998
2044
  if (msg.voice || msg.audio || msg.photo || msg.document || msg.video || msg.sticker) return;
1999
2045
  if (isDuplicate(msg.message_id)) return;
2000
2046
 
2001
- // Handle pending Claude auth/token paste-back
2002
- if (pendingClaudeAuthProcess) {
2047
+ // Handle pending manual OAuth token paste mode. Login codes must be sent explicitly
2048
+ // with /auth_code so normal chat can never be deleted/consumed accidentally.
2049
+ if (pendingClaudeAuthProcess && pendingClaudeAuthLabel === "manual OAuth token save") {
2003
2050
  const text = msg.text.trim();
2004
- await deleteMessage(msg.message_id);
2005
- if (pendingClaudeAuthLabel === "manual OAuth token save") {
2006
- pendingClaudeAuthProcess = null;
2007
- pendingClaudeAuthLabel = null;
2008
- if (!looksLikeClaudeToken(text)) { await send("That doesn't look like a Claude OAuth token. Not saved."); return; }
2051
+ if (looksLikeClaudeToken(text)) {
2052
+ await deleteMessage(msg.message_id);
2053
+ clearPendingClaudeAuth();
2009
2054
  saveClaudeOAuthToken(text);
2010
2055
  await send(`Claude OAuth token stored in .env${vault.isUnlocked() ? " and vault" : ""}. Restart the bot so launchd picks it up, or use /restart.`);
2011
- await sendClaudeAuthStatusSummary("Stored token. Current Claude auth status:");
2056
+ await sendClaudeAuthStatusSummary("Stored token. Current Claude auth status:");
2012
2057
  return;
2013
2058
  }
2014
- try {
2015
- pendingClaudeAuthProcess.stdin.write(text + "\n");
2016
- await send("Sent to Claude auth process. I’ll confirm when Claude finishes the auth check.");
2017
- } catch (e) {
2018
- pendingClaudeAuthProcess = null;
2019
- pendingClaudeAuthLabel = null;
2020
- await send(`Could not send to Claude auth process: ${redactSensitive(e.message)}`);
2021
- }
2022
- return;
2059
+ await send("Token paste mode is active, but that does not look like a Claude OAuth token. I left your message visible and will handle it normally. Send /cancel_auth to stop token paste mode.");
2060
+ }
2061
+
2062
+ if (pendingClaudeAuthProcess && pendingClaudeAuthLabel !== "manual OAuth token save") {
2063
+ 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.");
2023
2064
  }
2024
2065
 
2025
2066
  // Handle onboarding
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "1.14.2",
3
+ "version": "1.14.4",
4
4
  "description": "Your always-on AI coding assistant — Claude Code via Telegram",
5
5
  "main": "bot.js",
6
6
  "bin": {