arisa 5.2.17 → 5.2.20
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/LOW-MEMORY.md +37 -0
- package/README.md +6 -3
- package/package.json +3 -3
- package/pnpm-workspace.yaml +7 -5
- package/src/core/agent/agent-manager.js +13 -14
- package/src/core/agent/auth-flow.js +6 -6
- package/src/core/agent/model-selection.js +4 -3
- package/src/core/agent/model-speed.js +13 -3
- package/src/core/agent/pi-auth-login.js +28 -28
- package/src/core/agent/pi-capability-tools.js +1 -0
- package/src/core/agent/pi-runtime.js +14 -21
- package/src/core/artifacts/artifact-index.js +107 -0
- package/src/core/artifacts/artifact-store.js +15 -84
- package/src/core/artifacts/legacy-artifact-reader.js +46 -0
- package/src/core/capabilities/capability-service.js +25 -0
- package/src/core/tasks/task-store.js +2 -1
- package/src/index.js +10 -4
- package/src/official-tools.lock.json +25 -18
- package/src/platform/paths.js +5 -0
- package/src/runtime/bootstrap-cli.js +3 -3
- package/src/runtime/bootstrap-telegram.js +7 -7
- package/src/runtime/slave-cli.js +20 -10
- package/src/runtime/slave-service.js +299 -7
- package/src/runtime/tui.js +5 -6
- package/src/transport/telegram/bot.js +9 -5
- package/src/transport/telegram/model-callback.js +3 -2
- package/src/transport/telegram/model-controls.js +4 -4
- package/src/transport/telegram/model-picker.js +1 -1
- package/src/transport/telegram/task-dispatcher.js +50 -23
- package/src/transport/telegram/telegram-auth-controller.js +7 -7
- package/src/transport/telegram/telegram-session-bridge.js +2 -1
- package/test/agent-turn-coordinator.test.js +5 -2
- package/test/artifact-index-memory.test.js +46 -0
- package/test/artifact-index-migration.test.js +88 -0
- package/test/artifact-store.test.js +3 -3
- package/test/auth-flow.test.js +2 -2
- package/test/capabilities-security.test.js +36 -0
- package/test/cli-memory.test.js +22 -0
- package/test/model-selection.test.js +14 -4
- package/test/official-tool-installer.test.js +13 -0
- package/test/paths.test.js +2 -0
- package/test/pi-auth-login.test.js +78 -0
- package/test/pi-capability-tools.test.js +3 -0
- package/test/pi-speed-integration.test.js +177 -0
- package/test/slave-cli.test.js +221 -5
- package/test/task-store.test.js +3 -1
- package/test/telegram-task-dispatcher.test.js +57 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { copyFile, mkdir,
|
|
1
|
+
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
|
-
import { getChatArtifactsDir, getChatArtifactsIndexFile } from "../../platform/paths.js";
|
|
4
|
+
import { getChatArtifactsDir, getChatArtifactsIndexFile, getChatArtifactsDatabaseFile } from "../../platform/paths.js";
|
|
5
|
+
import { withArtifactIndex, appendArtifact, getArtifact, listRecentArtifacts } from "./artifact-index.js";
|
|
5
6
|
|
|
6
7
|
const UTF8_BOM = Buffer.from([0xef, 0xbb, 0xbf]);
|
|
7
|
-
const indexOperations = new Map();
|
|
8
8
|
|
|
9
9
|
function id() {
|
|
10
10
|
return crypto.randomUUID();
|
|
@@ -43,94 +43,27 @@ async function copyArtifactFile(originalPath, destPath, mimeType) {
|
|
|
43
43
|
return writeFile(destPath, withUtf8Bom(content));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
async function serializeIndexOperation(indexFile, operation) {
|
|
47
|
-
const previous = indexOperations.get(indexFile) || Promise.resolve();
|
|
48
|
-
const current = previous.catch(() => {}).then(operation);
|
|
49
|
-
indexOperations.set(indexFile, current);
|
|
50
|
-
try {
|
|
51
|
-
return await current;
|
|
52
|
-
} finally {
|
|
53
|
-
if (indexOperations.get(indexFile) === current) indexOperations.delete(indexFile);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function syncParentDirectory(file) {
|
|
58
|
-
let handle;
|
|
59
|
-
try {
|
|
60
|
-
handle = await open(path.dirname(file), "r");
|
|
61
|
-
await handle.sync();
|
|
62
|
-
} catch {
|
|
63
|
-
// Some platforms do not support fsync on directories; rename remains atomic there.
|
|
64
|
-
} finally {
|
|
65
|
-
await handle?.close().catch(() => {});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function writeJsonAtomically(file, value) {
|
|
70
|
-
await mkdir(path.dirname(file), { recursive: true });
|
|
71
|
-
const temporary = `${file}.${process.pid}.${id()}.tmp`;
|
|
72
|
-
let handle;
|
|
73
|
-
try {
|
|
74
|
-
handle = await open(temporary, "wx", 0o600);
|
|
75
|
-
await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
76
|
-
await handle.sync();
|
|
77
|
-
await handle.close();
|
|
78
|
-
handle = null;
|
|
79
|
-
await rename(temporary, file);
|
|
80
|
-
await syncParentDirectory(file);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
await handle?.close().catch(() => {});
|
|
83
|
-
await unlink(temporary).catch(() => {});
|
|
84
|
-
throw error;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
46
|
class ChatArtifactStore {
|
|
89
47
|
constructor(chatId) {
|
|
90
48
|
this.chatId = String(chatId);
|
|
91
49
|
this.rootDir = getChatArtifactsDir(this.chatId);
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const parsed = JSON.parse(await readFile(this.indexFile, "utf8"));
|
|
99
|
-
if (!Array.isArray(parsed)) throw new Error("Artifact index must contain a JSON array");
|
|
100
|
-
this.items = parsed;
|
|
101
|
-
} catch (error) {
|
|
102
|
-
if (error?.code === "ENOENT") {
|
|
103
|
-
this.items = [];
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
throw new Error(`Artifact index is unreadable: ${this.indexFile}`, { cause: error });
|
|
107
|
-
}
|
|
50
|
+
this.index = {
|
|
51
|
+
chatId: this.chatId,
|
|
52
|
+
legacyFile: getChatArtifactsIndexFile(this.chatId),
|
|
53
|
+
databaseFile: getChatArtifactsDatabaseFile(this.chatId)
|
|
54
|
+
};
|
|
108
55
|
}
|
|
109
56
|
|
|
110
57
|
async init() {
|
|
111
58
|
await mkdir(this.rootDir, { recursive: true });
|
|
112
|
-
|
|
59
|
+
await withArtifactIndex(this.index, () => {});
|
|
113
60
|
}
|
|
114
61
|
|
|
115
62
|
async appendToIndex(artifact) {
|
|
116
|
-
return
|
|
117
|
-
await this.reload();
|
|
118
|
-
this.items.push(artifact);
|
|
119
|
-
await writeJsonAtomically(this.indexFile, this.items);
|
|
120
|
-
return artifact;
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async readIndex() {
|
|
125
|
-
return serializeIndexOperation(this.indexFile, async () => {
|
|
126
|
-
await this.reload();
|
|
127
|
-
return this.items;
|
|
128
|
-
});
|
|
63
|
+
return withArtifactIndex(this.index, (db) => appendArtifact(db, artifact));
|
|
129
64
|
}
|
|
130
65
|
|
|
131
66
|
async createText({ text, mimeType = "text/plain", source, metadata = {} }) {
|
|
132
|
-
await this.init();
|
|
133
|
-
await this.reload();
|
|
134
67
|
const artifact = {
|
|
135
68
|
id: id(),
|
|
136
69
|
chatId: this.chatId,
|
|
@@ -146,7 +79,6 @@ class ChatArtifactStore {
|
|
|
146
79
|
|
|
147
80
|
async createFileArtifact({ fileName, kind, mimeType, source, metadata = {}, writeFileContent }) {
|
|
148
81
|
await this.init();
|
|
149
|
-
await this.reload();
|
|
150
82
|
const artifactId = id();
|
|
151
83
|
const dir = path.join(this.rootDir, artifactId);
|
|
152
84
|
await mkdir(dir, { recursive: true });
|
|
@@ -188,15 +120,14 @@ class ChatArtifactStore {
|
|
|
188
120
|
}
|
|
189
121
|
|
|
190
122
|
async get(artifactId) {
|
|
191
|
-
|
|
192
|
-
const items = await this.readIndex();
|
|
193
|
-
return items.find((item) => item.id === artifactId) || null;
|
|
123
|
+
return withArtifactIndex(this.index, (db) => getArtifact(db, artifactId));
|
|
194
124
|
}
|
|
195
125
|
|
|
196
126
|
async listRecent(limit = 20) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
127
|
+
if (!Number.isSafeInteger(limit) || limit < 0 || limit > 1000) {
|
|
128
|
+
throw new RangeError("Artifact list limit must be an integer between 0 and 1000");
|
|
129
|
+
}
|
|
130
|
+
return withArtifactIndex(this.index, (db) => listRecentArtifacts(db, limit));
|
|
200
131
|
}
|
|
201
132
|
}
|
|
202
133
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
|
|
3
|
+
// The legacy format is a JSON array of objects. Retain only one object's bytes,
|
|
4
|
+
// not the complete index. JSON.parse validates each object's JSON grammar.
|
|
5
|
+
export async function* readLegacyArtifacts(file, { highWaterMark = 64 * 1024 } = {}) {
|
|
6
|
+
const stream = createReadStream(file, { encoding: "utf8", highWaterMark });
|
|
7
|
+
let state = "array";
|
|
8
|
+
let depth = 0;
|
|
9
|
+
let quoted = false;
|
|
10
|
+
let escaped = false;
|
|
11
|
+
let parts = [];
|
|
12
|
+
for await (const chunk of stream) {
|
|
13
|
+
let start = depth ? 0 : -1;
|
|
14
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
15
|
+
const char = chunk[i];
|
|
16
|
+
if (depth) {
|
|
17
|
+
if (quoted) {
|
|
18
|
+
if (escaped) escaped = false;
|
|
19
|
+
else if (char === "\\") escaped = true;
|
|
20
|
+
else if (char === '"') quoted = false;
|
|
21
|
+
} else if (char === '"') quoted = true;
|
|
22
|
+
else if (char === "{" || char === "[") depth++;
|
|
23
|
+
else if (char === "}" || char === "]") depth--;
|
|
24
|
+
if (!depth) {
|
|
25
|
+
parts.push(chunk.slice(start, i + 1));
|
|
26
|
+
const value = JSON.parse(parts.join(""));
|
|
27
|
+
parts = [];
|
|
28
|
+
start = -1;
|
|
29
|
+
state = "separator";
|
|
30
|
+
yield value;
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (char === " " || char === "\n" || char === "\r" || char === "\t") continue;
|
|
35
|
+
if (state === "array" && char === "[") state = "first";
|
|
36
|
+
else if ((state === "first" || state === "separator") && char === "]") state = "done";
|
|
37
|
+
else if (state === "separator" && char === ",") state = "value";
|
|
38
|
+
else if ((state === "first" || state === "value") && char === "{") {
|
|
39
|
+
depth = 1;
|
|
40
|
+
start = i;
|
|
41
|
+
} else throw new Error("Invalid legacy artifact array");
|
|
42
|
+
}
|
|
43
|
+
if (start >= 0) parts.push(chunk.slice(start));
|
|
44
|
+
}
|
|
45
|
+
if (state !== "done" || depth) throw new Error("Truncated legacy artifact array");
|
|
46
|
+
}
|
|
@@ -48,6 +48,17 @@ function normalizeAcknowledgement(value) {
|
|
|
48
48
|
return acknowledgement;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
function recordAgentTaskAuthBlock(execution, toolName, result) {
|
|
52
|
+
if (!execution || execution.blockedAuth || result?.ok !== false || result?.status !== "blocked_auth") return;
|
|
53
|
+
execution.blockedAuth = {
|
|
54
|
+
toolName,
|
|
55
|
+
error: String(result.error || `${toolName} authentication is required`).slice(0, 1_000),
|
|
56
|
+
resolution: result.resolution && typeof result.resolution === "object"
|
|
57
|
+
? structuredClone(result.resolution)
|
|
58
|
+
: {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
function inferDeliveryMethod(artifact) {
|
|
52
63
|
if (artifact.kind === "audio" || (artifact.mimeType || "").startsWith("audio/")) return "audio";
|
|
53
64
|
if (artifact.kind === "image" || (artifact.mimeType || "").startsWith("image/")) return "photo";
|
|
@@ -178,6 +189,19 @@ export function createCapabilityService({
|
|
|
178
189
|
if (!toolExecutor?.runTool) throw new Error("tools.run requires toolExecutor");
|
|
179
190
|
const scopedChatId = requireChatId(chatId, method);
|
|
180
191
|
const targetToolName = requireString(params.name, "name");
|
|
192
|
+
const blocked = context.agentTaskExecution?.blockedAuth;
|
|
193
|
+
if (blocked) {
|
|
194
|
+
return {
|
|
195
|
+
ok: false,
|
|
196
|
+
status: "blocked_prerequisite",
|
|
197
|
+
error: `Authentication for ${blocked.toolName} is blocking this scheduled task.`,
|
|
198
|
+
resolution: {
|
|
199
|
+
type: "blocked_prerequisite",
|
|
200
|
+
prerequisiteStatus: "blocked_auth",
|
|
201
|
+
toolName: blocked.toolName
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
181
205
|
const chatArtifactStore = artifactStore.forChat(scopedChatId);
|
|
182
206
|
const artifact = params.artifactId
|
|
183
207
|
? await chatArtifactStore.get(requireString(params.artifactId, "artifactId"))
|
|
@@ -197,6 +221,7 @@ export function createCapabilityService({
|
|
|
197
221
|
chatId: scopedChatId,
|
|
198
222
|
taskContext: context.taskContext || null
|
|
199
223
|
});
|
|
224
|
+
recordAgentTaskAuthBlock(context.agentTaskExecution, targetToolName, result);
|
|
200
225
|
if (params.deliver && result.output?.artifactId) {
|
|
201
226
|
const generated = await chatArtifactStore.get(result.output.artifactId);
|
|
202
227
|
if (generated?.path) {
|
|
@@ -177,7 +177,8 @@ function normalizeAuthResolution(resolution = {}) {
|
|
|
177
177
|
? structuredClone(value.probeArgs)
|
|
178
178
|
: {};
|
|
179
179
|
if (JSON.stringify(probeArgs).length > 4_096) throw new Error("Authentication probe arguments are too large");
|
|
180
|
-
|
|
180
|
+
const toolName = typeof value.toolName === "string" ? value.toolName.trim().slice(0, 128) : "";
|
|
181
|
+
return { retryAfterSeconds, probeArgs, ...(toolName ? { toolName } : {}) };
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
function failTask(task, error) {
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { bootstrapIfNeeded } from "./runtime/bootstrap.js";
|
|
4
|
-
import { applyRuntimeOverrides, createApp } from "./runtime/create-app.js";
|
|
5
3
|
import { loadConfig } from "./core/config/config-store.js";
|
|
6
4
|
import { createLogger } from "./runtime/logger.js";
|
|
7
5
|
import { getServiceStatus, handoffServiceRestart, registerServiceProcess, restartService, serviceEntryFile, startService, stopService, unregisterServiceProcess } from "./runtime/service-manager.js";
|
|
@@ -10,10 +8,8 @@ import { recordUnexpectedWorkerExit } from "./runtime/worker-recovery-report.js"
|
|
|
10
8
|
import { flushArisaHome } from "./runtime/flush.js";
|
|
11
9
|
import { readPackageVersion, showServiceLogs } from "./runtime/log-viewer.js";
|
|
12
10
|
import { arisaPackageDir } from "./platform/paths.js";
|
|
13
|
-
import { runSlaveCli } from "./runtime/slave-cli.js";
|
|
14
11
|
import { unregisterSlaveServiceProcess } from "./runtime/slave-service.js";
|
|
15
12
|
import { protectCoreFromOom } from "./runtime/oom-protection.js";
|
|
16
|
-
import { runTui } from "./runtime/tui.js";
|
|
17
13
|
|
|
18
14
|
process.env.ARISA_PACKAGE_DIR = arisaPackageDir;
|
|
19
15
|
|
|
@@ -128,7 +124,13 @@ process.once("SIGINT", () => {
|
|
|
128
124
|
shutdown(0);
|
|
129
125
|
});
|
|
130
126
|
|
|
127
|
+
async function bootstrapIfNeeded(options) {
|
|
128
|
+
const bootstrap = await import("./runtime/bootstrap.js");
|
|
129
|
+
return bootstrap.bootstrapIfNeeded(options);
|
|
130
|
+
}
|
|
131
|
+
|
|
131
132
|
async function startRuntimeApp() {
|
|
133
|
+
const { createApp } = await import("./runtime/create-app.js");
|
|
132
134
|
const app = await createApp({
|
|
133
135
|
logger,
|
|
134
136
|
runtimeOverrides,
|
|
@@ -142,6 +144,7 @@ async function startRuntimeApp() {
|
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
async function startBackgroundService() {
|
|
147
|
+
const { applyRuntimeOverrides } = await import("./runtime/create-app.js");
|
|
145
148
|
const persistedConfig = await loadConfig();
|
|
146
149
|
applyRuntimeOverrides(persistedConfig, runtimeOverrides);
|
|
147
150
|
const result = await startService({ verbose, cliArgs: toServiceRunnerArgs(cli.nestedFlags) });
|
|
@@ -155,6 +158,7 @@ async function startBackgroundService() {
|
|
|
155
158
|
}
|
|
156
159
|
|
|
157
160
|
async function restartBackgroundService() {
|
|
161
|
+
const { applyRuntimeOverrides } = await import("./runtime/create-app.js");
|
|
158
162
|
const persistedConfig = await loadConfig();
|
|
159
163
|
applyRuntimeOverrides(persistedConfig, runtimeOverrides);
|
|
160
164
|
const result = await restartService({
|
|
@@ -224,6 +228,7 @@ async function runForeground() {
|
|
|
224
228
|
|
|
225
229
|
async function main() {
|
|
226
230
|
if (slaveCommand) {
|
|
231
|
+
const { runSlaveCli } = await import("./runtime/slave-cli.js");
|
|
227
232
|
const result = await runSlaveCli({
|
|
228
233
|
positionals: cli.positionals.slice(1),
|
|
229
234
|
flags: cli.flags,
|
|
@@ -265,6 +270,7 @@ async function main() {
|
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
if (command === "tui") {
|
|
273
|
+
const { runTui } = await import("./runtime/tui.js");
|
|
268
274
|
await runTui({ logger });
|
|
269
275
|
return;
|
|
270
276
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
3
|
"repository": "https://github.com/clasen/Arisa.git",
|
|
4
|
-
"commit": "
|
|
4
|
+
"commit": "2256f9e19f26f23826b9a9062d3a9643b511bb3c",
|
|
5
5
|
"tools": {
|
|
6
6
|
"audio-extractor": {
|
|
7
7
|
"version": null,
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"browser-session-bridge": {
|
|
16
|
-
"version": "0.2.
|
|
16
|
+
"version": "0.2.5",
|
|
17
17
|
"files": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"README.md": "79cb347ead539309429eca19ba6e9c472e4790ec1ab39a20bba71a4149f61f15",
|
|
19
|
+
"bridge-server.js": "03722a2657ba74bf34de9cae683b8f23242657da87c05771dd413a38fb446eca",
|
|
20
|
+
"chrome-web-store.js": "4b588d1288dee754c5d8afd609b8c1f67f73d23de7dda247b7a2ff8b68f7ef60",
|
|
20
21
|
"config.js": "45c8e9e9a159b9125d6ea3458c616926c2ba2b5327fdfd750aa05316d3ce5af8",
|
|
21
22
|
"extension/icons/icon-128.png": "a55af49bb570bd5471fc0a2e15a6bcaf3f76a2c5e7439f16bb1829682b343380",
|
|
22
23
|
"extension/icons/icon-16.png": "a4aedb49e2227222a68dc56455812a9e17938fd197b1f30268f02d6c9f7bf95e",
|
|
@@ -31,24 +32,26 @@
|
|
|
31
32
|
"extension/site-permissions.js": "83f9aa4d0295318fc730bd561c2db9d1aacf36152319090e99d12f62deea11ad",
|
|
32
33
|
"index.js": "c01a6b825da4587a550ecec560a558cc6736200e73b6831f5919000c7b81679d",
|
|
33
34
|
"lightpanda-session.js": "57c713dafac531617d7285122b2098c1e0b2f334e43144632f2b1fc79405f789",
|
|
34
|
-
"package-lock.json": "
|
|
35
|
-
"package.json": "
|
|
36
|
-
"README.md": "79cb347ead539309429eca19ba6e9c472e4790ec1ab39a20bba71a4149f61f15",
|
|
35
|
+
"package-lock.json": "b97f5a333df234fecde788d0f90b620d39e02fee6079c1b4347baaabd8010b1b",
|
|
36
|
+
"package.json": "5c9edd6155b6b4868cc87d474e808dfc23567bc312e0d1e0230d8f9f0a1cc081",
|
|
37
37
|
"session-browser.js": "7af716a1c0d6793b82ebbaaf64ec3e8f73dfc52b3c9aceef2179d2d859e32a9c",
|
|
38
38
|
"session-redaction.js": "c2393023c1d3b7634432606ad82a96d79c1f093d9b0a6440d955d0ae419c8393",
|
|
39
39
|
"session-selection.js": "da5a4f55ccc8ba22791840943288e7aecacd730425c03f05c2bc10fd6a14341f",
|
|
40
|
-
"session-store.js": "
|
|
41
|
-
"test/device-enrollment.test.js": "
|
|
40
|
+
"session-store.js": "ee85e5b9696e542bb535a996743ddbbd2093fc66e18873a2f1c7a27707a83994",
|
|
41
|
+
"test/device-enrollment.test.js": "a4246f4cb19e959ef4b8a83f60664887b624526b0e5646e5ec1fdb93750082b0",
|
|
42
42
|
"test/lightpanda-session.test.js": "1fa6c1693a5008c173ec6c5c97effe001b68c535c7a3d4530500c0c4b691c532",
|
|
43
43
|
"test/onboarding-state.test.js": "889f7746bbdb51320e68447560459d2a5d812e4b135de08a7b6e94ef5a142250",
|
|
44
44
|
"test/session-redaction.test.js": "e45b5cbd19eea7996d57141b5185c3a6e4c79989e4cb7253272fc66cd2cbd719",
|
|
45
|
-
"test/session-refresh.test.js": "
|
|
45
|
+
"test/session-refresh.test.js": "ffa688433185c08696761f189df244ed9ac212731b012a3eb9a91da05b43dd56",
|
|
46
46
|
"test/session-selection.test.js": "ee1a15d42b156403d46d789a3ecf0a9c8f0019a00ab908276297d031243a89f5",
|
|
47
47
|
"test/session-send-state.test.js": "c8ccbdf0863c5de85f784e7e32436591fe2db16a2ef4c554f671c6352736d5b6",
|
|
48
48
|
"test/site-permissions.test.js": "27c297475c38ee1cbe7c7df210c767c157e03ecd379cde99a1b502268bda56ab",
|
|
49
|
-
"tool.manifest.json": "
|
|
49
|
+
"tool.manifest.json": "820f6060f077b95c286168f175e5521bc67b043425cae69c5be40834d5016454",
|
|
50
50
|
"web-store/listing.md": "3e6d7aab1f60142984c3f8c18d92bf23646dc901644c6b71bdb979802bcf320c",
|
|
51
|
-
"web-store/privacy-policy.md": "
|
|
51
|
+
"web-store/privacy-policy.md": "eaaaa6066b36ef56896321d62b6ac4596d62104a0591d4edceb8c6040c47fd5c"
|
|
52
|
+
},
|
|
53
|
+
"toolDependencies": {
|
|
54
|
+
"lightpanda-browser": "^0.11.5"
|
|
52
55
|
}
|
|
53
56
|
},
|
|
54
57
|
"campaign-draft-runner": {
|
|
@@ -115,6 +118,7 @@
|
|
|
115
118
|
"creator-scout": {
|
|
116
119
|
"version": "1.4.0",
|
|
117
120
|
"files": {
|
|
121
|
+
"README.md": "6895b2c0cc3a230ddf3f59f1c4670b12070464f8e742bfdf40a04120a7fefaea",
|
|
118
122
|
"config.js": "bab728665650b986c0eaef8e1be1c259ec42b1f83df4217c9780f5468d3c7666",
|
|
119
123
|
"index.js": "a544e5dbac9cb92e996c2b07690a18481a20b8b10c13c397412581ec9ac6bb04",
|
|
120
124
|
"outcome-contract.js": "5685bd8fbe4fcb608ee43a0148201206283013c1a60855c974a928c1d312480a",
|
|
@@ -122,13 +126,16 @@
|
|
|
122
126
|
"package.json": "19c61d77ec90fce64d1a3baa1acc5b29af23f7c0574964504bc69b19e38aa34f",
|
|
123
127
|
"panda-results.js": "24a31263b4a03e2c2719d9c54be7b5c022b17fb7dcb249eed33b93882518145b",
|
|
124
128
|
"panda-session.js": "69878ff01bfbf26afe4db0e2e6489b211e3aca100ba5353befefaea009636bb5",
|
|
125
|
-
"README.md": "6895b2c0cc3a230ddf3f59f1c4670b12070464f8e742bfdf40a04120a7fefaea",
|
|
126
129
|
"reference-match.js": "5ceb71bfe57763258d89c60936bb7e5b3166b6aa7127f9d2f8da49f01298f46b",
|
|
127
130
|
"test/outcome-contract.test.js": "dda85d1f56880b30d7fad3e8a27aacbb0808d91fc0addac6e0c38f9f0c4849bf",
|
|
128
131
|
"test/panda-results.test.js": "b918d6341251822292fe3e375ab66694a0f71f3c7a24e91be263ee36e5f3e92c",
|
|
129
132
|
"test/panda-session.test.js": "6cfa4e0543fab77c502c1103c60d8cb7d16040770e7aa5c034a47e0292de8521",
|
|
130
133
|
"test/reference-match.test.js": "38572ee3756f4ff0b0c61942dda0a19c9d06697826051cf0924dd3c47fc99b67",
|
|
131
134
|
"tool.manifest.json": "5368082b6808dc9b5966a46afcc6042cc82aabef0cd55ed65b4e783a4cb2579e"
|
|
135
|
+
},
|
|
136
|
+
"toolDependencies": {
|
|
137
|
+
"lightpanda-browser": "^0.11.4",
|
|
138
|
+
"browser-session-bridge": "^0.1.3"
|
|
132
139
|
}
|
|
133
140
|
},
|
|
134
141
|
"file-document": {
|
|
@@ -177,27 +184,27 @@
|
|
|
177
184
|
"lightpanda-browser": {
|
|
178
185
|
"version": "0.11.5",
|
|
179
186
|
"files": {
|
|
187
|
+
"BENCHMARK.md": "9c732c65f6d8bceb4e73c1a03d298d5140d919f50269f982bd0ec6c1b21fa8b6",
|
|
188
|
+
"COMPATIBILITY-MIGRATION.md": "230e12e8ddac837b7772519693e530c43d2158b69c671036bf246fb3a9e35561",
|
|
189
|
+
"LIMITS.md": "6c0ec9624c76de8ddf09b82a4da1dba1b89a48a1f0e71a083ffbcf7a3d5401fb",
|
|
190
|
+
"README.md": "c79a9a24d2fe804a7ce3e160e8308b1ac0039461cbfd012347aaa61f841f5fed",
|
|
180
191
|
"action-policy.js": "66c6ad39f65378ccf8ed54177f5a3665e23ef82818c30fb05d28cd58cba9b2ab",
|
|
181
192
|
"authenticated-profile.js": "2bbb96c4d25a108c44256514c1c9b4e61e1f125e470ab35c5e02515216cd1b33",
|
|
182
193
|
"benchmark-latest.json": "c5524e6d42479578579fd7db0e50857ff0831ca219e611b821ad1e0a4fade303",
|
|
183
194
|
"benchmark-policy.js": "2c3763d7f327293c9d54ca24da9e65b94dc304af44908c1e196a4af45ed49a89",
|
|
184
|
-
"BENCHMARK.md": "9c732c65f6d8bceb4e73c1a03d298d5140d919f50269f982bd0ec6c1b21fa8b6",
|
|
185
195
|
"binary.js": "accd3f1f536ae7ceee4dbfcee2de9ac56fc1ae343656238d62003233417257f1",
|
|
186
196
|
"browser-operation.js": "51384d146d45fda8c672d3d6672fa223b715ad40c3c5b5878719e9df38151592",
|
|
187
197
|
"capture.js": "b68b198d494c762822c6da079a556dd3463e681557f2abef1387d9cd41abaf4c",
|
|
188
|
-
"COMPATIBILITY-MIGRATION.md": "230e12e8ddac837b7772519693e530c43d2158b69c671036bf246fb3a9e35561",
|
|
189
198
|
"config.js": "d08eb436df15540a53b02cf72e117c7fc8ead80195dbd53764a17598c9e565c5",
|
|
190
199
|
"daemon-service.js": "10e70ed64f1fe8c7660044f6ce24e78d01da75a50322bfc08f42248c14ad5226",
|
|
191
200
|
"index.js": "5fc54aec13fb27c6b55e20aed132853b79c44041f45ea4b0f4b47b00c205da16",
|
|
192
201
|
"limit-suite-latest.json": "3d30f958d2d6c1e9dfcaf53e40a401ae288bf264a97ba6c3b64a25a08031feb0",
|
|
193
202
|
"limit-suite-policy.js": "61440ee2e7f557ab2f3c74f8ef4ec2ec85fd2fb7fc53a4121e1f0d066670ea17",
|
|
194
|
-
"LIMITS.md": "6c0ec9624c76de8ddf09b82a4da1dba1b89a48a1f0e71a083ffbcf7a3d5401fb",
|
|
195
203
|
"mcp-session.js": "cd4a1e6d3c9d80c399fda8f313d69e38fa22a9b24789d7919832a56df7dc90c2",
|
|
196
204
|
"output-bounds.js": "08ab730d0d8722c5e0e761911a509653dd23d8eb4d8c2abf2d9c5e8432870bdd",
|
|
197
205
|
"package-lock.json": "815dfdb89ce94b543e520955480e322438abd2b71fad4c4ddd699838b8622b65",
|
|
198
206
|
"package.json": "934ae0f55d1baea305c28f12c0c9faccdd864244d899663c96f9083d96442841",
|
|
199
207
|
"process-metrics.js": "e39d2980abb581ca0b917d0d33a1d71922ce49b679a7e96cf16a6a66b81d879a",
|
|
200
|
-
"README.md": "c79a9a24d2fe804a7ce3e160e8308b1ac0039461cbfd012347aaa61f841f5fed",
|
|
201
208
|
"recipe-store.js": "358ac391ae86e0bfb82fc5b55bd08cfe3fd4fa56ac12a5ad4ad5abfa43c9a6c6",
|
|
202
209
|
"scripts/benchmark.js": "f1bb939984460d84118317f9b4f811e0df80f590b0a441cd62a56eb97bb69b37",
|
|
203
210
|
"scripts/install-lightpanda.js": "ba4a2f9e5ffae80b9375578731d68eff25997333cb9e3e443b155f7834948205",
|
|
@@ -255,6 +262,7 @@
|
|
|
255
262
|
"master-slave": {
|
|
256
263
|
"version": "0.1.9",
|
|
257
264
|
"files": {
|
|
265
|
+
"README.md": "a75f87df7906fe143d2ecaddfe9263561db17436df7ec2c4a8d985e1e3e8996e",
|
|
258
266
|
"batch-cancellation.js": "b9ca57dfcca4f1a672d5435536b7eb83547dba98ed3fd09f34376f1d995bb97f",
|
|
259
267
|
"batch-runner.js": "97756a03b36278cd0315cc16da0c34a7821c322149c51ba6666f1c5081dbecbc",
|
|
260
268
|
"chat-state-store.js": "50de39aa33432733bb688eb01968e314a32b169324a66d0f0089b2a19ed9c880",
|
|
@@ -271,7 +279,6 @@
|
|
|
271
279
|
"master-domain.js": "10b7dfb43eb9939eb5baec54f742076cc73a2add6589a0ff57c51bc79c236faf",
|
|
272
280
|
"network-session.js": "6ef332ef9694ff211f4aed1e8b6ff4df3614a1d4c63affe6fdd00409329ec431",
|
|
273
281
|
"package.json": "774af304ec05a24461318172882a28373e568b5240d8eee9a31a286997b9a403",
|
|
274
|
-
"README.md": "a75f87df7906fe143d2ecaddfe9263561db17436df7ec2c4a8d985e1e3e8996e",
|
|
275
282
|
"remote-runtime.js": "d38b7a28f36e8f1be1d4826a056a03d0ebc2b9b17be277e010be25048797a562",
|
|
276
283
|
"slave-operations.js": "5a8967e2006f3f30ee221614d25fbf7863ffd9c717fd7eeeb0ba981c8c8c367a",
|
|
277
284
|
"state-store.js": "c56849a3f1b9c990128276e17963034a7836abacedc44f2e500d5732ebf9e451",
|
package/src/platform/paths.js
CHANGED
|
@@ -46,10 +46,15 @@ export function getChatArtifactsDir(chatId) {
|
|
|
46
46
|
return path.join(getChatDir(chatId), "artifacts");
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Legacy JSON index; retained unchanged as a migration backup.
|
|
49
50
|
export function getChatArtifactsIndexFile(chatId) {
|
|
50
51
|
return path.join(getChatDir(chatId), "state", "artifacts.json");
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
export function getChatArtifactsDatabaseFile(chatId) {
|
|
55
|
+
return path.join(getChatDir(chatId), "state", "artifacts.sqlite");
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
export function getChatSessionSeedFile(chatId) {
|
|
54
59
|
return path.join(getChatDir(chatId), "state", "session-seed.jsonl");
|
|
55
60
|
}
|
|
@@ -66,7 +66,7 @@ async function runInternalPiLogin(provider, { rl = null } = {}) {
|
|
|
66
66
|
|
|
67
67
|
export async function collectCliBootstrapChoices({ telegramApiKey, rl, ask }) {
|
|
68
68
|
const telegramMaxChatIds = Number(await ask("Maximum authorized chat IDs", "1"));
|
|
69
|
-
const runtime = createPiRuntime();
|
|
69
|
+
const runtime = await createPiRuntime();
|
|
70
70
|
const providers = sortBootstrapProviders(listPiProviders(runtime));
|
|
71
71
|
console.log("\nAvailable Pi providers:");
|
|
72
72
|
providers.forEach((item, index) => console.log(`${index + 1}. ${formatProviderOption(item)}`));
|
|
@@ -89,7 +89,7 @@ export async function collectCliBootstrapChoices({ telegramApiKey, rl, ask }) {
|
|
|
89
89
|
while (true) {
|
|
90
90
|
piApiKey = (await rl.question(`Pi API key for ${selectedProvider.provider} (optional): `)).trim();
|
|
91
91
|
if (piApiKey) break;
|
|
92
|
-
if (hasProviderAuth(selectedProvider.provider, createPiRuntime())) break;
|
|
92
|
+
if (hasProviderAuth(selectedProvider.provider, await createPiRuntime())) break;
|
|
93
93
|
if (!providerSupportsOAuth) {
|
|
94
94
|
console.log(`No existing Pi auth found for ${selectedProvider.provider}. This provider requires an API key.`);
|
|
95
95
|
continue;
|
|
@@ -100,7 +100,7 @@ export async function collectCliBootstrapChoices({ telegramApiKey, rl, ask }) {
|
|
|
100
100
|
} catch (error) {
|
|
101
101
|
console.log(`Internal Pi login failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
102
102
|
}
|
|
103
|
-
if (hasProviderAuth(selectedProvider.provider, createPiRuntime())) {
|
|
103
|
+
if (hasProviderAuth(selectedProvider.provider, await createPiRuntime())) {
|
|
104
104
|
console.log(`Detected Pi auth for ${selectedProvider.provider}. Continuing bootstrap.`);
|
|
105
105
|
break;
|
|
106
106
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo }) {
|
|
25
25
|
const bot = new Bot(telegramApiKey);
|
|
26
|
-
const runtime = createPiRuntime();
|
|
26
|
+
const runtime = await createPiRuntime();
|
|
27
27
|
const providers = sortBootstrapProviders(listPiProviders(runtime));
|
|
28
28
|
let setupChatId = null;
|
|
29
29
|
let chatMeta = {};
|
|
@@ -90,7 +90,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
90
90
|
|
|
91
91
|
const askModel = async (ctx = null, page = 0) => {
|
|
92
92
|
state = "model";
|
|
93
|
-
const models = sortBootstrapModels(selectedProvider.provider, listProviderModels(selectedProvider.provider, createPiRuntime()));
|
|
93
|
+
const models = sortBootstrapModels(selectedProvider.provider, listProviderModels(selectedProvider.provider, await createPiRuntime()));
|
|
94
94
|
const keyboard = buildPagedInlineKeyboard("model", models.map((model) => ({ text: formatPiModelOption(model) })), {
|
|
95
95
|
page,
|
|
96
96
|
pageSize: telegramConfigDefaults.modelPickerPageSize
|
|
@@ -119,7 +119,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
const askAuthMethod = async (ctx = null) => {
|
|
122
|
-
const providerRuntime = createPiRuntime();
|
|
122
|
+
const providerRuntime = await createPiRuntime();
|
|
123
123
|
const selectedAuthReady = hasProviderAuth(selectedProvider.provider, providerRuntime);
|
|
124
124
|
const providerSupportsOAuth = supportsProviderOAuth(selectedProvider.provider, providerRuntime);
|
|
125
125
|
const buttons = [];
|
|
@@ -142,7 +142,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
142
142
|
try {
|
|
143
143
|
await login.promise;
|
|
144
144
|
activeLogin = null;
|
|
145
|
-
if (hasProviderAuth(selectedProvider.provider, createPiRuntime())) {
|
|
145
|
+
if (hasProviderAuth(selectedProvider.provider, await createPiRuntime())) {
|
|
146
146
|
await sendSetupMessage(`Detected Pi auth for ${selectedProvider.provider}.`);
|
|
147
147
|
await askBackground();
|
|
148
148
|
return;
|
|
@@ -157,7 +157,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
const startPiLogin = async () => {
|
|
160
|
-
if (hasProviderAuth(selectedProvider.provider, createPiRuntime())) {
|
|
160
|
+
if (hasProviderAuth(selectedProvider.provider, await createPiRuntime())) {
|
|
161
161
|
await sendSetupMessage(`Existing Pi auth for ${selectedProvider.provider} detected.`);
|
|
162
162
|
await askBackground();
|
|
163
163
|
return;
|
|
@@ -248,7 +248,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
248
248
|
return;
|
|
249
249
|
}
|
|
250
250
|
if (action === "model" && state === "model") {
|
|
251
|
-
const models = sortBootstrapModels(selectedProvider.provider, listProviderModels(selectedProvider.provider, createPiRuntime()));
|
|
251
|
+
const models = sortBootstrapModels(selectedProvider.provider, listProviderModels(selectedProvider.provider, await createPiRuntime()));
|
|
252
252
|
selectedModel = models[Number(rawValue)];
|
|
253
253
|
if (!selectedModel) return;
|
|
254
254
|
await askAuthMethod(ctx);
|
|
@@ -256,7 +256,7 @@ export async function runTelegramBootstrap({ telegramApiKey, setupToken, botInfo
|
|
|
256
256
|
}
|
|
257
257
|
if (action === "auth" && state === "auth-method") {
|
|
258
258
|
if (rawValue === "existing") {
|
|
259
|
-
if (hasProviderAuth(selectedProvider.provider, createPiRuntime())) {
|
|
259
|
+
if (hasProviderAuth(selectedProvider.provider, await createPiRuntime())) {
|
|
260
260
|
await askBackground(ctx);
|
|
261
261
|
} else {
|
|
262
262
|
await sendSetupMessage(`No existing Pi auth found for ${selectedProvider.provider}.`);
|
package/src/runtime/slave-cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { withSecureRequestFile } from "./secure-request-file.js";
|
|
|
11
11
|
import {
|
|
12
12
|
controlSlaveService,
|
|
13
13
|
getSlavePaths,
|
|
14
|
-
|
|
14
|
+
installSlaveService,
|
|
15
15
|
isSlaveToolInstalled,
|
|
16
16
|
readSlaveServiceDescriptor,
|
|
17
17
|
registerSlaveServiceProcess,
|
|
@@ -138,11 +138,13 @@ function parseSlaveToolOutput(result) {
|
|
|
138
138
|
return result?.output && typeof result.output === "object" ? result.output : result;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
export function formatSlaveStatus({ systemd, diagnostic }) {
|
|
141
|
+
export function formatSlaveStatus({ service, systemd, diagnostic }) {
|
|
142
|
+
const serviceStatus = service || systemd;
|
|
143
|
+
const manager = serviceStatus?.serviceManager || (systemd ? "systemd" : "service");
|
|
142
144
|
const jobs = diagnostic?.jobs && typeof diagnostic.jobs === "object" ? diagnostic.jobs : {};
|
|
143
145
|
return [
|
|
144
146
|
"Arisa Slave status",
|
|
145
|
-
`
|
|
147
|
+
`Service (${manager}): ${serviceStatus?.running ? "active" : serviceStatus?.status || "inactive"}`,
|
|
146
148
|
`Daemon: ${diagnostic?.daemon?.state || diagnostic?.daemonState || "unknown"}`,
|
|
147
149
|
`Role: ${diagnostic?.role || "unknown"}`,
|
|
148
150
|
`Endpoint: ${diagnostic?.endpoint || "not configured"}`,
|
|
@@ -167,14 +169,14 @@ export async function runSlaveBootstrap(url, {
|
|
|
167
169
|
paths = getSlavePaths(resolveSlaveHome()),
|
|
168
170
|
selectAccount = selectSlaveServiceAccount,
|
|
169
171
|
ensureTool = ensureMasterSlaveTool,
|
|
170
|
-
installService =
|
|
172
|
+
installService = installSlaveService,
|
|
171
173
|
invokeTool = invokeSlaveTool,
|
|
172
174
|
entryFile,
|
|
173
175
|
output = console,
|
|
174
176
|
platform = process.platform
|
|
175
177
|
} = {}) {
|
|
176
178
|
parseSlaveBootstrapUrl(url);
|
|
177
|
-
if (
|
|
179
|
+
if (!["linux", "darwin", "win32"].includes(platform)) throw new Error(`Arisa Slave service installation is not supported on ${platform}`);
|
|
178
180
|
const account = await selectAccount();
|
|
179
181
|
await ensureSlaveConfig(paths);
|
|
180
182
|
await ensureTool(paths);
|
|
@@ -188,8 +190,16 @@ export async function runSlaveBootstrap(url, {
|
|
|
188
190
|
} catch (error) {
|
|
189
191
|
throw explainSlaveBootstrapError(error);
|
|
190
192
|
}
|
|
191
|
-
await installService({ account, slaveHome: paths.home, entryFile });
|
|
192
|
-
await writeSlaveServiceDescriptor(paths, {
|
|
193
|
+
const installedService = await installService({ account, slaveHome: paths.home, entryFile, platform });
|
|
194
|
+
await writeSlaveServiceDescriptor(paths, {
|
|
195
|
+
version: 1,
|
|
196
|
+
account,
|
|
197
|
+
serviceManager: installedService?.serviceManager || ({ darwin: "launchd", win32: "windows-task" }[platform] || "systemd"),
|
|
198
|
+
serviceTarget: installedService?.serviceTarget || null,
|
|
199
|
+
unitFile: installedService?.unitFile || null,
|
|
200
|
+
launcherFile: installedService?.launcherFile || null,
|
|
201
|
+
installedAt: new Date().toISOString()
|
|
202
|
+
});
|
|
193
203
|
output.log(`Arisa Slave paired and running as ${account.user}${account.root ? " (root)" : ""}.`);
|
|
194
204
|
return result;
|
|
195
205
|
}
|
|
@@ -240,12 +250,12 @@ export async function runSlaveCli({
|
|
|
240
250
|
}
|
|
241
251
|
if (action === "status") {
|
|
242
252
|
if (positionals.length !== 1) throw new Error("arisa slave status does not accept additional arguments");
|
|
243
|
-
const
|
|
253
|
+
const service = await controlService(paths, "status");
|
|
244
254
|
const diagnostic = await toolInstalled(paths, toolName)
|
|
245
255
|
? parseSlaveToolOutput(await invokeTool(paths, { action: "slave.status" }))
|
|
246
256
|
: { daemonState: "not-installed", role: "slave", paired: false, toolCount: 0, pendingSecrets: 0 };
|
|
247
|
-
output.log(formatSlaveStatus({
|
|
248
|
-
return {
|
|
257
|
+
output.log(formatSlaveStatus({ service, diagnostic }));
|
|
258
|
+
return { service, diagnostic };
|
|
249
259
|
}
|
|
250
260
|
if (action === "log") {
|
|
251
261
|
if (positionals.length !== 1) throw new Error("arisa slave log does not accept additional arguments");
|