arisa 4.2.4 → 4.2.8
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/package.json +2 -2
- package/pnpm-workspace.yaml +6 -0
- package/src/core/agent/auth-flow.js +3 -3
- package/src/runtime/bootstrap.js +3 -2
- package/src/transport/telegram/bot.js +4 -2
- package/src/transport/telegram/device-code-message.js +48 -0
- package/src/transport/telegram/text-format.js +1 -1
- package/test/device-code-message.test.js +42 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arisa",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.8",
|
|
4
4
|
"description": "Telegram + Pi Agent modular assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://arisa.sh",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
40
|
+
"@earendil-works/pi-coding-agent": "^0.80.6",
|
|
41
41
|
"@sinclair/typebox": "^0.34.41",
|
|
42
42
|
"grammy": "^1.42.0"
|
|
43
43
|
},
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
allowBuilds:
|
|
2
2
|
'@google/genai': false
|
|
3
3
|
|
|
4
|
+
minimumReleaseAgeExclude:
|
|
5
|
+
- '@earendil-works/pi-agent-core@0.80.6'
|
|
6
|
+
- '@earendil-works/pi-ai@0.80.6'
|
|
7
|
+
- '@earendil-works/pi-coding-agent@0.80.6'
|
|
8
|
+
- '@earendil-works/pi-tui@0.80.6'
|
|
9
|
+
|
|
4
10
|
overrides:
|
|
5
11
|
'@protobufjs/utf8@<=1.1.0': '>=1.1.1'
|
|
6
12
|
basic-ftp@<=5.2.1: '>=5.2.2'
|
|
@@ -78,11 +78,11 @@ export function buildPiAuthTelegramMessage({ config, issue = null, verified = fa
|
|
|
78
78
|
if (verified) {
|
|
79
79
|
lines.push("No action needed.");
|
|
80
80
|
} else if (!issue) {
|
|
81
|
-
lines.push("Run
|
|
81
|
+
lines.push("Run /auth to validate these credentials against the provider.");
|
|
82
82
|
} else if (status.hasApiKey) {
|
|
83
83
|
lines.push("A Pi API key is configured, but the provider rejected the current request. Update the key and restart Arisa.");
|
|
84
84
|
} else if (status.supportsOAuth) {
|
|
85
|
-
lines.push("Run
|
|
85
|
+
lines.push("Run /auth here in Telegram to renew the Pi login.");
|
|
86
86
|
} else {
|
|
87
87
|
lines.push("This provider needs a Pi API key. Re-run `arisa --bootstrap`, provide a key, and restart Arisa.");
|
|
88
88
|
}
|
|
@@ -103,7 +103,7 @@ export function buildPiAuthRecoveryBlockedMessage({ config, issue = null, renewa
|
|
|
103
103
|
|
|
104
104
|
lines.push(renewalActive
|
|
105
105
|
? "A Pi login is already in progress. Paste the redirect URL or code here when the provider gives it to you."
|
|
106
|
-
: "Send
|
|
106
|
+
: "Send /auth to start Pi login from Telegram.");
|
|
107
107
|
|
|
108
108
|
return lines.join("\n");
|
|
109
109
|
}
|
package/src/runtime/bootstrap.js
CHANGED
|
@@ -6,6 +6,7 @@ import { spawn } from "node:child_process";
|
|
|
6
6
|
import { Bot } from "grammy";
|
|
7
7
|
import { createPiOAuthLogin } from "../core/agent/pi-auth-login.js";
|
|
8
8
|
import { createPiRuntime, hasProviderAuth, listPiProviders, listProviderModels, supportsProviderOAuth } from "../core/agent/pi-runtime.js";
|
|
9
|
+
import { buildDeviceCodeTelegramMessage } from "../transport/telegram/device-code-message.js";
|
|
9
10
|
import { configFile, ensureArisaHome } from "./paths.js";
|
|
10
11
|
|
|
11
12
|
const ARISA_BANNER = [
|
|
@@ -424,8 +425,8 @@ async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo }) {
|
|
|
424
425
|
].join("\n"));
|
|
425
426
|
},
|
|
426
427
|
onDeviceCode: async ({ userCode, verificationUri, expiresInSeconds }) => {
|
|
427
|
-
const
|
|
428
|
-
await sendSetupMessage(
|
|
428
|
+
const { text, ...options } = buildDeviceCodeTelegramMessage({ userCode, verificationUri, expiresInSeconds });
|
|
429
|
+
await sendSetupMessage(text, options);
|
|
429
430
|
},
|
|
430
431
|
onPrompt: async ({ message, controller }) => {
|
|
431
432
|
await sendSetupMessage(`${message}\nReply here with the value.`);
|
|
@@ -2,6 +2,7 @@ import { Bot, InputFile } from "grammy";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { authorizeChat } from "./auth.js";
|
|
4
4
|
import { captureIncomingArtifact, formatLocationText } from "./media.js";
|
|
5
|
+
import { buildDeviceCodeTelegramMessage } from "./device-code-message.js";
|
|
5
6
|
import { renderTelegramHtml } from "./text-format.js";
|
|
6
7
|
import { buildPiAuthRecoveryBlockedMessage, buildPiAuthTelegramMessage, getErrorMessage, getPiAuthIssue, getPiAuthStatus } from "../../core/agent/auth-flow.js";
|
|
7
8
|
import { createPiOAuthLogin } from "../../core/agent/pi-auth-login.js";
|
|
@@ -365,8 +366,9 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
365
366
|
].join("\n"));
|
|
366
367
|
},
|
|
367
368
|
onDeviceCode: async ({ userCode, verificationUri, expiresInSeconds }) => {
|
|
368
|
-
const
|
|
369
|
-
|
|
369
|
+
const payload = buildDeviceCodeTelegramMessage({ userCode, verificationUri, expiresInSeconds });
|
|
370
|
+
const { text, ...options } = payload;
|
|
371
|
+
await bot.api.sendMessage(chatId, text, options);
|
|
370
372
|
},
|
|
371
373
|
onPrompt: async ({ message, controller }) => {
|
|
372
374
|
await bot.api.sendMessage(chatId, `${message}\nReply here with the value.`);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { escapeHtml } from "./text-format.js";
|
|
2
|
+
|
|
3
|
+
const maxCopyTextLength = 256;
|
|
4
|
+
const maxButtonLabelLength = 64;
|
|
5
|
+
|
|
6
|
+
function truncateButtonLabel(text = "") {
|
|
7
|
+
const source = String(text || "").trim();
|
|
8
|
+
if (source.length <= maxButtonLabelLength) return source;
|
|
9
|
+
return `${source.slice(0, maxButtonLabelLength - 1)}…`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function buildDeviceCodeTelegramMessage({ userCode, verificationUri, expiresInSeconds } = {}) {
|
|
13
|
+
const code = String(userCode || "").trim();
|
|
14
|
+
const uri = String(verificationUri || "").trim();
|
|
15
|
+
const expiry = expiresInSeconds
|
|
16
|
+
? `\nExpires in ${Math.round(expiresInSeconds / 60)} minute(s).`
|
|
17
|
+
: "";
|
|
18
|
+
|
|
19
|
+
const lines = [
|
|
20
|
+
"Open this URL:",
|
|
21
|
+
uri ? `<a href="${escapeHtml(uri)}">${escapeHtml(uri)}</a>` : "",
|
|
22
|
+
"Then enter code:",
|
|
23
|
+
code ? `<code>${escapeHtml(code)}</code>` : "",
|
|
24
|
+
escapeHtml(expiry.trim())
|
|
25
|
+
].filter(Boolean);
|
|
26
|
+
|
|
27
|
+
const payload = {
|
|
28
|
+
text: lines.join("\n"),
|
|
29
|
+
parse_mode: "HTML",
|
|
30
|
+
link_preview_options: { is_disabled: true }
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const buttons = [];
|
|
34
|
+
if (code && code.length <= maxCopyTextLength) {
|
|
35
|
+
buttons.push({
|
|
36
|
+
text: truncateButtonLabel(`Copy code: ${code}`),
|
|
37
|
+
copy_text: { text: code }
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (uri) {
|
|
41
|
+
buttons.push({ text: "Open login page", url: uri });
|
|
42
|
+
}
|
|
43
|
+
if (buttons.length) {
|
|
44
|
+
payload.reply_markup = { inline_keyboard: [buttons] };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return payload;
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { buildDeviceCodeTelegramMessage } from "../src/transport/telegram/device-code-message.js";
|
|
4
|
+
|
|
5
|
+
test("builds a copyable device-code Telegram message with HTML and inline buttons", () => {
|
|
6
|
+
const payload = buildDeviceCodeTelegramMessage({
|
|
7
|
+
userCode: "TR2S-K4GBZ",
|
|
8
|
+
verificationUri: "https://auth.openai.com/codex/device",
|
|
9
|
+
expiresInSeconds: 900
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
assert.equal(payload.parse_mode, "HTML");
|
|
13
|
+
assert.match(payload.text, /https:\/\/auth\.openai\.com\/codex\/device/);
|
|
14
|
+
assert.match(payload.text, /<code>TR2S-K4GBZ<\/code>/);
|
|
15
|
+
assert.match(payload.text, /Expires in 15 minute\(s\)\./);
|
|
16
|
+
assert.deepEqual(payload.reply_markup.inline_keyboard, [[
|
|
17
|
+
{ text: "Copy code: TR2S-K4GBZ", copy_text: { text: "TR2S-K4GBZ" } },
|
|
18
|
+
{ text: "Open login page", url: "https://auth.openai.com/codex/device" }
|
|
19
|
+
]]);
|
|
20
|
+
assert.deepEqual(payload.link_preview_options, { is_disabled: true });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("escapes HTML-sensitive device-code values", () => {
|
|
24
|
+
const payload = buildDeviceCodeTelegramMessage({
|
|
25
|
+
userCode: "A&B<1>",
|
|
26
|
+
verificationUri: "https://example.com/?q=\"x\""
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
assert.match(payload.text, /<code>A&B<1><\/code>/);
|
|
30
|
+
assert.match(payload.text, /href="https:\/\/example\.com\/\?q="x""/);
|
|
31
|
+
assert.equal(payload.reply_markup.inline_keyboard[0][0].copy_text.text, "A&B<1>");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("omits copy button when code exceeds Telegram copy_text limit", () => {
|
|
35
|
+
const payload = buildDeviceCodeTelegramMessage({
|
|
36
|
+
userCode: "x".repeat(257),
|
|
37
|
+
verificationUri: "https://example.com/device"
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.equal(payload.reply_markup.inline_keyboard[0].length, 1);
|
|
41
|
+
assert.equal(payload.reply_markup.inline_keyboard[0][0].text, "Open login page");
|
|
42
|
+
});
|