arisa 5.1.13 → 5.1.24
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/AGENTS.md +4 -0
- package/README.md +2 -0
- package/package.json +7 -8
- package/src/core/tools/official-tool-installer.js +78 -6
- package/src/core/tools/tool-dependencies.js +99 -0
- package/src/core/tools/tool-registry.js +50 -6
- package/src/official-tools.lock.json +157 -5
- package/src/runtime/arisa-capabilities.js +12 -1
- package/src/runtime/create-app.js +1 -0
- package/src/runtime/doctor.js +71 -19
- package/src/runtime/tool-usage-report.js +25 -10
- package/src/transport/telegram/bot.js +38 -6
- package/test/capabilities-security.test.js +21 -0
- package/test/context-and-task-bounds.test.js +28 -2
- package/test/doctor.test.js +55 -0
- package/test/official-tool-dependencies.test.js +23 -0
- package/test/official-tool-installer.test.js +37 -9
- package/test/tool-dependencies.test.js +53 -0
- package/test/tool-registry-run.test.js +19 -1
- package/test/tool-usage.test.js +26 -4
package/AGENTS.md
CHANGED
|
@@ -47,6 +47,7 @@ Each tool declares in `tool.manifest.json`:
|
|
|
47
47
|
- `category`: optional broad capability bucket for discovery
|
|
48
48
|
- `keywords`: optional intent tags for capability discovery
|
|
49
49
|
- `skillHints`: optional skills to apply when using or editing the tool
|
|
50
|
+
- `toolDependencies`: optional required Arisa tools mapped to exact or caret semantic versions; use this only for hard runtime dependencies
|
|
50
51
|
|
|
51
52
|
## Text encoding
|
|
52
53
|
All textual content generated or sent by Arisa or its tools must use UTF-8.
|
|
@@ -78,6 +79,8 @@ const result = await arisa.tools.run({
|
|
|
78
79
|
|
|
79
80
|
The IPC channel is a local socket under `~/.arisa/state`. Every request must include `toolName`; chat-scoped capabilities also require `chatId`. Exposed capabilities are explicit: tools (`list`, `help`, `skills`, `setConfig`, `setResourceNote`, `getResourceNote`, `run`), artifacts (`createText`, `listRecent`, `get`, `deliver`), tasks (`add`, `list`, `cancel`, `cancelAll`), agent events (`enqueueEvent`), and runtime paths (`getChatToolStateDir`, `getToolStateDir`, `getChatToolTmpDir`, `getToolTmpDir`, `getChatArtifactsDir`). Do not expose raw `agentManager`, `taskStore`, `artifactStore`, or `toolRegistry` access.
|
|
80
81
|
|
|
82
|
+
`agent.enqueueEvent` may include an optional `acknowledgement` of at most 500 characters. Telegram delivers it before the event enters agent reasoning, so explicit authorization receipts cannot be delayed behind follow-up work. Keep it deterministic, concise, and free of credentials; the event prompt must not repeat it.
|
|
83
|
+
|
|
81
84
|
## Tool resource notes
|
|
82
85
|
A tool resource may have one deterministic chat-scoped operational note of at most 200 characters, keyed by the exact pair `toolName:resourceId`. Notes live in the chat state file returned by `getChatToolResourceNotesFile(chatId)`. They are separate from semantic memory and contain no credentials.
|
|
83
86
|
|
|
@@ -130,6 +133,7 @@ When such a tool is built, implement it with the shared daemon runtime instead o
|
|
|
130
133
|
- expose normal CLI behavior through `run --request-file`; callers should not manage daemon internals
|
|
131
134
|
- use the runtime for `daemon.pid`, `daemon.log`, `status.json`, and `commands/*.request|processing|result.json`
|
|
132
135
|
- keep one daemon owner per tool/session and avoid opening a second client over the same resource
|
|
136
|
+
- daemons that receive unsolicited external traffic (webhooks, bridge imports, persistent sockets, or active watchers) must use `daemon.autoStart: true` and disable idle shutdown while ingress is expected; idle shutdown is only for capabilities that can be restarted by the request initiating their next use
|
|
133
137
|
- use `beforeStart` only for tool-specific cleanup such as stale browser locks, without deleting persistent session/model data
|
|
134
138
|
- keep daemon tools headless/server-safe by default when they are meant to run on VPS machines
|
|
135
139
|
- if the daemon exposes an HTTP server, keep that server inside the tool; Arisa core does not discover or mount tool routes
|
package/README.md
CHANGED
|
@@ -76,6 +76,8 @@ Each tool folder contains:
|
|
|
76
76
|
|
|
77
77
|
`tool.manifest.json` may also include optional `skillHints`; Arisa resolves installed skills and passes them into `run_tool` requests as `skills` guidance, not runtime dependencies.
|
|
78
78
|
|
|
79
|
+
A tool that requires another Arisa tool declares a versioned `toolDependencies` map, for example `{ "mcp-client": "^0.1.0" }`. Official installation resolves these dependencies first, rejects missing or cyclic lock entries, and validates installed versions. The registry blocks execution when a required tool is missing or incompatible, and `/doctor` reports the issue.
|
|
80
|
+
|
|
79
81
|
Each tool is isolated from the root project and from other tools.
|
|
80
82
|
That isolation is part of the architecture:
|
|
81
83
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arisa",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.24",
|
|
4
4
|
"description": "Telegram + Pi Agent modular assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"arisa": "bin/arisa.js"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"start": "node src/index.js",
|
|
12
|
-
"bootstrap": "node src/index.js --bootstrap",
|
|
13
|
-
"test": "node --test"
|
|
14
|
-
},
|
|
15
10
|
"keywords": [
|
|
16
11
|
"telegram",
|
|
17
12
|
"pi-agent",
|
|
@@ -44,11 +39,15 @@
|
|
|
44
39
|
"url": "https://github.com/clasen/Arisa/issues"
|
|
45
40
|
},
|
|
46
41
|
"homepage": "https://arisa.sh",
|
|
47
|
-
"packageManager": "pnpm@11.3.0+sha512.2c403d6594527287672b1f7056343a1f7c3634036a67ffabfcc2b3d7595d843768f8787148d1b57cf7956c90606bbd192857c363af19e96d2d0ec9ec5741d215",
|
|
48
42
|
"dependencies": {
|
|
49
43
|
"@earendil-works/pi-coding-agent": "0.80.6",
|
|
50
44
|
"@sinclair/typebox": "^0.34.41",
|
|
51
45
|
"grammy": "^1.42.0",
|
|
52
46
|
"typebox": "1.1.38"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"start": "node src/index.js",
|
|
50
|
+
"bootstrap": "node src/index.js --bootstrap",
|
|
51
|
+
"test": "node --test"
|
|
53
52
|
}
|
|
54
|
-
}
|
|
53
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import os from "node:os";
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { getToolDir } from "../../runtime/paths.js";
|
|
17
|
+
import { normalizeToolDependencies, resolveToolDependencyPlan, satisfiesToolVersion } from "./tool-dependencies.js";
|
|
17
18
|
|
|
18
19
|
const bundledLockFile = new URL("../../official-tools.lock.json", import.meta.url);
|
|
19
20
|
|
|
@@ -46,7 +47,8 @@ export function validateOfficialToolLock(lock, toolName) {
|
|
|
46
47
|
if (!COMMIT_PATTERN.test(String(lock.commit || ""))) {
|
|
47
48
|
throw new Error("Official tool lock requires an immutable 40-character commit");
|
|
48
49
|
}
|
|
49
|
-
const
|
|
50
|
+
const entry = lock.tools?.[toolName];
|
|
51
|
+
const files = entry?.files;
|
|
50
52
|
if (!files || typeof files !== "object" || Array.isArray(files) || !Object.keys(files).length) {
|
|
51
53
|
throw new Error(`Official tool lock has no files for ${toolName}`);
|
|
52
54
|
}
|
|
@@ -56,7 +58,12 @@ export function validateOfficialToolLock(lock, toolName) {
|
|
|
56
58
|
throw new Error(`Invalid SHA-256 digest for ${toolName}/${file}`);
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
|
-
|
|
61
|
+
const toolDependencies = normalizeToolDependencies(entry.toolDependencies);
|
|
62
|
+
const toolVersion = entry.version == null ? null : String(entry.version);
|
|
63
|
+
if (toolVersion && !satisfiesToolVersion(toolVersion, toolVersion)) {
|
|
64
|
+
throw new Error(`Invalid locked tool version for ${toolName}: ${toolVersion}`);
|
|
65
|
+
}
|
|
66
|
+
return { repository: lock.repository, commit: lock.commit, files, toolVersion, toolDependencies };
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
async function walkFiles(root, relative = "") {
|
|
@@ -133,11 +140,36 @@ async function checkoutRepository({ repository, commit, checkoutDir }) {
|
|
|
133
140
|
if (resolved !== commit) throw new Error(`Official tool checkout resolved ${resolved}, expected ${commit}`);
|
|
134
141
|
}
|
|
135
142
|
|
|
136
|
-
async function
|
|
143
|
+
async function installPackageDependencies(toolDir) {
|
|
144
|
+
let packageJson;
|
|
145
|
+
try {
|
|
146
|
+
packageJson = JSON.parse(await readFile(path.join(toolDir, "package.json"), "utf8"));
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error?.code === "ENOENT") return { installed: false };
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
const dependencyCount = Object.keys(packageJson.dependencies || {}).length + Object.keys(packageJson.optionalDependencies || {}).length;
|
|
152
|
+
if (!dependencyCount) return { installed: false };
|
|
153
|
+
if (await exists(path.join(toolDir, "package-lock.json"))) {
|
|
154
|
+
await runCommand("npm", ["ci", "--omit=dev"], { cwd: toolDir });
|
|
155
|
+
} else {
|
|
156
|
+
await runCommand("npm", ["install", "--omit=dev"], { cwd: toolDir });
|
|
157
|
+
}
|
|
158
|
+
return { installed: true, dependencyCount };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function validateEntrypoint(toolDir, toolName, locked) {
|
|
137
162
|
const manifest = JSON.parse(await readFile(path.join(toolDir, "tool.manifest.json"), "utf8"));
|
|
138
163
|
if (manifest.name !== toolName) {
|
|
139
164
|
throw new Error(`Official tool manifest mismatch: expected ${toolName}, got ${manifest.name || "missing"}`);
|
|
140
165
|
}
|
|
166
|
+
if (locked.toolVersion && manifest.version !== locked.toolVersion) {
|
|
167
|
+
throw new Error(`Official tool version mismatch: expected ${locked.toolVersion}, got ${manifest.version || "missing"}`);
|
|
168
|
+
}
|
|
169
|
+
const manifestDependencies = normalizeToolDependencies(manifest.toolDependencies);
|
|
170
|
+
if (JSON.stringify(manifestDependencies) !== JSON.stringify(locked.toolDependencies)) {
|
|
171
|
+
throw new Error(`Official tool dependency metadata mismatch: ${toolName}`);
|
|
172
|
+
}
|
|
141
173
|
const entry = manifest.entry || "index.js";
|
|
142
174
|
const entryPath = path.join(toolDir, entry);
|
|
143
175
|
if (!(await exists(entryPath))) throw new Error(`Official tool entry does not exist: ${entry}`);
|
|
@@ -151,6 +183,7 @@ export async function installLockedOfficialTool({
|
|
|
151
183
|
destination,
|
|
152
184
|
scratchRoot = os.tmpdir(),
|
|
153
185
|
checkout = checkoutRepository,
|
|
186
|
+
installDependencies = installPackageDependencies,
|
|
154
187
|
validate = validateEntrypoint
|
|
155
188
|
}) {
|
|
156
189
|
const locked = validateOfficialToolLock(lock, toolName);
|
|
@@ -165,7 +198,8 @@ export async function installLockedOfficialTool({
|
|
|
165
198
|
const sourceDir = path.join(checkoutDir, "tools", toolName);
|
|
166
199
|
await verifyOfficialToolTree(sourceDir, locked.files);
|
|
167
200
|
await cp(sourceDir, stageDir, { recursive: true, errorOnExist: true, force: false });
|
|
168
|
-
await
|
|
201
|
+
await installDependencies(stageDir, toolName);
|
|
202
|
+
await validate(stageDir, toolName, locked);
|
|
169
203
|
await mkdir(path.dirname(destination), { recursive: true });
|
|
170
204
|
await rename(stageDir, destination);
|
|
171
205
|
return { toolName, destination, commit: locked.commit, files: Object.keys(locked.files).length };
|
|
@@ -174,10 +208,48 @@ export async function installLockedOfficialTool({
|
|
|
174
208
|
}
|
|
175
209
|
}
|
|
176
210
|
|
|
211
|
+
async function installedToolVersion(toolName) {
|
|
212
|
+
try {
|
|
213
|
+
const manifest = JSON.parse(await readFile(path.join(getToolDir(toolName), "tool.manifest.json"), "utf8"));
|
|
214
|
+
return typeof manifest.version === "string" ? manifest.version : null;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (error?.code === "ENOENT") return undefined;
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
177
221
|
export async function installBundledOfficialTool(toolName, {
|
|
178
222
|
lockFile = bundledLockFile,
|
|
179
|
-
install = installLockedOfficialTool
|
|
223
|
+
install = installLockedOfficialTool,
|
|
224
|
+
resolveInstalledVersion = installedToolVersion
|
|
180
225
|
} = {}) {
|
|
181
226
|
const lock = JSON.parse(await readFile(lockFile, "utf8"));
|
|
182
|
-
|
|
227
|
+
const entries = new Map(Object.entries(lock.tools || {}).map(([name, entry]) => [name, {
|
|
228
|
+
version: entry.version || null,
|
|
229
|
+
toolDependencies: normalizeToolDependencies(entry.toolDependencies)
|
|
230
|
+
}]));
|
|
231
|
+
const plan = resolveToolDependencyPlan(entries, toolName);
|
|
232
|
+
const dependencies = [];
|
|
233
|
+
let result = null;
|
|
234
|
+
for (const name of plan) {
|
|
235
|
+
const locked = validateOfficialToolLock(lock, name);
|
|
236
|
+
if (name !== toolName) {
|
|
237
|
+
const installedVersion = await resolveInstalledVersion(name);
|
|
238
|
+
if (installedVersion !== undefined) {
|
|
239
|
+
const requiredRanges = plan
|
|
240
|
+
.map((dependentName) => entries.get(dependentName)?.toolDependencies?.[name])
|
|
241
|
+
.filter(Boolean);
|
|
242
|
+
const incompatibleRange = requiredRanges.find((range) => !satisfiesToolVersion(installedVersion, range));
|
|
243
|
+
if (incompatibleRange || (!requiredRanges.length && locked.toolVersion !== installedVersion)) {
|
|
244
|
+
throw new Error(`Installed tool dependency is incompatible: ${name}@${installedVersion} does not satisfy ${incompatibleRange || locked.toolVersion || "locked version"}`);
|
|
245
|
+
}
|
|
246
|
+
dependencies.push({ name, version: installedVersion, status: "already-installed" });
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const installed = await install({ toolName: name, lock, destination: getToolDir(name) });
|
|
251
|
+
if (name === toolName) result = installed;
|
|
252
|
+
else dependencies.push({ name, version: locked.toolVersion, status: "installed" });
|
|
253
|
+
}
|
|
254
|
+
return { ...result, dependencies };
|
|
183
255
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const TOOL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
2
|
+
const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
3
|
+
const RANGE_PATTERN = /^(\^)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
4
|
+
|
|
5
|
+
function versionParts(version) {
|
|
6
|
+
const match = VERSION_PATTERN.exec(String(version || ""));
|
|
7
|
+
return match ? match.slice(1).map(Number) : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function compareVersions(left, right) {
|
|
11
|
+
for (let index = 0; index < 3; index += 1) {
|
|
12
|
+
if (left[index] !== right[index]) return left[index] - right[index];
|
|
13
|
+
}
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function normalizeToolDependencies(value) {
|
|
18
|
+
if (value == null) return {};
|
|
19
|
+
if (typeof value !== "object" || Array.isArray(value)) throw new Error("toolDependencies must be an object");
|
|
20
|
+
const normalized = {};
|
|
21
|
+
for (const [name, range] of Object.entries(value)) {
|
|
22
|
+
if (!TOOL_NAME_PATTERN.test(name)) throw new Error(`Invalid tool dependency name: ${name}`);
|
|
23
|
+
if (!RANGE_PATTERN.test(String(range || ""))) throw new Error(`Unsupported tool dependency range for ${name}: ${range || "empty"}`);
|
|
24
|
+
normalized[name] = String(range);
|
|
25
|
+
}
|
|
26
|
+
return normalized;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function satisfiesToolVersion(version, range) {
|
|
30
|
+
const actual = versionParts(version);
|
|
31
|
+
const match = RANGE_PATTERN.exec(String(range || ""));
|
|
32
|
+
if (!actual || !match) return false;
|
|
33
|
+
const expected = match.slice(2).map(Number);
|
|
34
|
+
if (!match[1]) return compareVersions(actual, expected) === 0;
|
|
35
|
+
if (compareVersions(actual, expected) < 0) return false;
|
|
36
|
+
if (expected[0] > 0) return actual[0] === expected[0];
|
|
37
|
+
if (expected[1] > 0) return actual[0] === 0 && actual[1] === expected[1];
|
|
38
|
+
return actual[0] === 0 && actual[1] === 0 && actual[2] === expected[2];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function inspectToolDependencies(tools, rootName = null) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
const visiting = new Set();
|
|
44
|
+
const visited = new Set();
|
|
45
|
+
const visit = (name, chain = []) => {
|
|
46
|
+
if (visiting.has(name)) {
|
|
47
|
+
issues.push({ tool: name, type: "cycle", dependency: name, chain: [...chain, name] });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (visited.has(name)) return;
|
|
51
|
+
const tool = tools.get(name);
|
|
52
|
+
if (!tool) return;
|
|
53
|
+
visiting.add(name);
|
|
54
|
+
for (const [dependency, range] of Object.entries(normalizeToolDependencies(tool.toolDependencies))) {
|
|
55
|
+
const installed = tools.get(dependency);
|
|
56
|
+
if (!installed) {
|
|
57
|
+
issues.push({ tool: name, type: "missing", dependency, range });
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!satisfiesToolVersion(installed.version, range)) {
|
|
61
|
+
issues.push({ tool: name, type: "incompatible", dependency, range, installedVersion: installed.version || null });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
visit(dependency, [...chain, name]);
|
|
65
|
+
}
|
|
66
|
+
visiting.delete(name);
|
|
67
|
+
visited.add(name);
|
|
68
|
+
};
|
|
69
|
+
if (rootName) visit(rootName);
|
|
70
|
+
else for (const name of tools.keys()) visit(name);
|
|
71
|
+
return issues;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function resolveToolDependencyPlan(entries, rootName) {
|
|
75
|
+
const tools = entries instanceof Map ? entries : new Map(Object.entries(entries || {}));
|
|
76
|
+
const order = [];
|
|
77
|
+
const visiting = new Set();
|
|
78
|
+
const visited = new Set();
|
|
79
|
+
const visit = (name, chain = []) => {
|
|
80
|
+
const tool = tools.get(name);
|
|
81
|
+
if (!tool) throw new Error(`Official tool dependency is not locked: ${name}`);
|
|
82
|
+
if (visiting.has(name)) throw new Error(`Circular official tool dependency: ${[...chain, name].join(" -> ")}`);
|
|
83
|
+
if (visited.has(name)) return;
|
|
84
|
+
visiting.add(name);
|
|
85
|
+
for (const [dependency, range] of Object.entries(normalizeToolDependencies(tool.toolDependencies))) {
|
|
86
|
+
const lockedDependency = tools.get(dependency);
|
|
87
|
+
if (!lockedDependency) throw new Error(`Official tool dependency is not locked: ${name} -> ${dependency}`);
|
|
88
|
+
if (!satisfiesToolVersion(lockedDependency.version, range)) {
|
|
89
|
+
throw new Error(`Locked tool dependency is incompatible: ${name} requires ${dependency}@${range}, lock has ${lockedDependency.version || "no version"}`);
|
|
90
|
+
}
|
|
91
|
+
visit(dependency, [...chain, name]);
|
|
92
|
+
}
|
|
93
|
+
visiting.delete(name);
|
|
94
|
+
visited.add(name);
|
|
95
|
+
order.push(name);
|
|
96
|
+
};
|
|
97
|
+
visit(rootName);
|
|
98
|
+
return order;
|
|
99
|
+
}
|
|
@@ -2,7 +2,7 @@ import { mkdir, readdir, readFile, rmdir, unlink, writeFile } from "node:fs/prom
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { arisaIpcSocketFile, arisaPackageDir, getToolConfigPath, getToolTmpDir, getChatToolTmpDir, toolsDir as userToolsRoot } from "../../runtime/paths.js";
|
|
5
|
+
import { arisaIpcSocketFile, arisaPackageDir, getToolConfigPath, getToolStateDir, getToolTmpDir, getChatToolTmpDir, toolsDir as userToolsRoot } from "../../runtime/paths.js";
|
|
6
6
|
import { loadToolConfig, parseConfigModule, writeToolConfig } from "./tool-config.js";
|
|
7
7
|
import { normalizeToolResult } from "./tool-result.js";
|
|
8
8
|
import { readDaemonDiagnostic } from "./daemon-processes.js";
|
|
@@ -10,6 +10,7 @@ import { createDaemonRuntime, DAEMON_EVENT_TYPES, DAEMON_PROTOCOL_VERSION } from
|
|
|
10
10
|
import { daemonConfigDefaults } from "../config/config-defaults.js";
|
|
11
11
|
import { SkillRegistry } from "../skills/skill-registry.js";
|
|
12
12
|
import { ToolUsageStore } from "./tool-usage-store.js";
|
|
13
|
+
import { inspectToolDependencies, normalizeToolDependencies } from "./tool-dependencies.js";
|
|
13
14
|
|
|
14
15
|
function toolEnv() {
|
|
15
16
|
return { ...process.env, ARISA_PACKAGE_DIR: arisaPackageDir, ARISA_IPC_SOCKET: arisaIpcSocketFile };
|
|
@@ -203,12 +204,36 @@ function formatSemanticMetadata(tool) {
|
|
|
203
204
|
].join("\n");
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
function formatToolDependencies(tool, tools) {
|
|
208
|
+
const dependencies = Object.entries(tool.toolDependencies || {});
|
|
209
|
+
if (!dependencies.length) return null;
|
|
210
|
+
const lines = dependencies.map(([name, range]) => {
|
|
211
|
+
const issue = inspectToolDependencies(tools, tool.name).find((item) => item.dependency === name);
|
|
212
|
+
return `- ${name}@${range}: ${issue ? issue.type : "ready"}`;
|
|
213
|
+
});
|
|
214
|
+
return `Tool dependencies:\n${lines.join("\n")}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function readOfficialToolNames() {
|
|
218
|
+
const baselinesDir = path.join(getToolStateDir("official-tool-sync"), "baselines");
|
|
219
|
+
try {
|
|
220
|
+
const entries = await readdir(baselinesDir, { withFileTypes: true });
|
|
221
|
+
return new Set(entries
|
|
222
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
|
|
223
|
+
.map((entry) => entry.name.slice(0, -5)));
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (error?.code === "ENOENT") return new Set();
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
206
230
|
export class ToolRegistry {
|
|
207
|
-
constructor({ logger, usageStore = new ToolUsageStore() } = {}) {
|
|
231
|
+
constructor({ logger, usageStore = new ToolUsageStore(), resolveOfficialToolNames = readOfficialToolNames } = {}) {
|
|
208
232
|
this.logger = logger;
|
|
209
233
|
this.tools = new Map();
|
|
210
234
|
this.skillRegistry = new SkillRegistry();
|
|
211
235
|
this.usageStore = usageStore;
|
|
236
|
+
this.resolveOfficialToolNames = resolveOfficialToolNames;
|
|
212
237
|
}
|
|
213
238
|
|
|
214
239
|
async load() {
|
|
@@ -235,6 +260,7 @@ export class ToolRegistry {
|
|
|
235
260
|
const skillHints = this.skillRegistry.normalizeHints(manifest);
|
|
236
261
|
this.tools.set(manifest.name, {
|
|
237
262
|
...manifest,
|
|
263
|
+
toolDependencies: normalizeToolDependencies(manifest.toolDependencies),
|
|
238
264
|
category: normalizeCategory(manifest.category),
|
|
239
265
|
keywords: normalizeKeywords(manifest.keywords),
|
|
240
266
|
skillHints,
|
|
@@ -259,6 +285,7 @@ export class ToolRegistry {
|
|
|
259
285
|
version: typeof tool.version === "string" ? tool.version : null,
|
|
260
286
|
packageDigest: typeof tool.packageDigest === "string" ? tool.packageDigest : null,
|
|
261
287
|
requirements: requirementNames(tool.requirements),
|
|
288
|
+
toolDependencies: tool.toolDependencies || {},
|
|
262
289
|
description: tool.description,
|
|
263
290
|
input: tool.input,
|
|
264
291
|
output: tool.output,
|
|
@@ -311,7 +338,8 @@ export class ToolRegistry {
|
|
|
311
338
|
const skills = await this.resolveSkills(name);
|
|
312
339
|
const sections = [
|
|
313
340
|
help.trimEnd(),
|
|
314
|
-
formatSemanticMetadata(tool)
|
|
341
|
+
formatSemanticMetadata(tool),
|
|
342
|
+
formatToolDependencies(tool, this.tools)
|
|
315
343
|
];
|
|
316
344
|
if (skills.length) {
|
|
317
345
|
const skillHelp = skills.map((item) => [
|
|
@@ -360,16 +388,32 @@ export class ToolRegistry {
|
|
|
360
388
|
return { ok: true, tool: name, field, configPath };
|
|
361
389
|
}
|
|
362
390
|
|
|
391
|
+
dependencyIssues(name = null) {
|
|
392
|
+
return inspectToolDependencies(this.tools, name);
|
|
393
|
+
}
|
|
394
|
+
|
|
363
395
|
async usage(chatId) {
|
|
364
|
-
const counts = await
|
|
365
|
-
|
|
366
|
-
.
|
|
396
|
+
const [counts, officialNames] = await Promise.all([
|
|
397
|
+
this.usageStore.counts(chatId),
|
|
398
|
+
this.resolveOfficialToolNames()
|
|
399
|
+
]);
|
|
400
|
+
const names = new Set([
|
|
401
|
+
...this.list().map((tool) => tool.name),
|
|
402
|
+
...Object.keys(counts)
|
|
403
|
+
]);
|
|
404
|
+
return [...names]
|
|
405
|
+
.map((name) => ({ name, count: counts[name] || 0, official: officialNames.has(name) }))
|
|
367
406
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
368
407
|
}
|
|
369
408
|
|
|
370
409
|
async run({ name, request, chatId = null, onEvent = null }) {
|
|
371
410
|
const tool = this.get(name);
|
|
372
411
|
if (!tool) throw new Error(`Tool not found: ${name}`);
|
|
412
|
+
const dependencyIssue = this.dependencyIssues(name)[0];
|
|
413
|
+
if (dependencyIssue) {
|
|
414
|
+
const version = dependencyIssue.installedVersion ? `; installed ${dependencyIssue.installedVersion}` : "";
|
|
415
|
+
throw new Error(`Tool dependency ${dependencyIssue.type}: ${dependencyIssue.tool} requires ${dependencyIssue.dependency}@${dependencyIssue.range || "valid"}${version}`);
|
|
416
|
+
}
|
|
373
417
|
await this.usageStore.record(chatId, name).catch((error) => {
|
|
374
418
|
this.logger?.error("tools", `could not record ${name} usage: ${error?.message || String(error)}`);
|
|
375
419
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
3
|
"repository": "https://github.com/clasen/Arisa.git",
|
|
4
|
-
"commit": "
|
|
4
|
+
"commit": "eff37798c546e33cc4386c878ee01baa5dbd701c",
|
|
5
5
|
"tools": {
|
|
6
6
|
"master-slave": {
|
|
7
7
|
"files": {
|
|
8
|
-
"README.md": "
|
|
9
|
-
"batch-runner.js": "
|
|
8
|
+
"README.md": "84d2841d8df31c07065d4fee6e434dc43cad241f3abf63e95efafad51ed69fcb",
|
|
9
|
+
"batch-runner.js": "97756a03b36278cd0315cc16da0c34a7821c322149c51ba6666f1c5081dbecbc",
|
|
10
10
|
"chat-state-store.js": "50de39aa33432733bb688eb01968e314a32b169324a66d0f0089b2a19ed9c880",
|
|
11
11
|
"config.js": "ff1c1cb6701ae1da7a6eb1519ba96a416e48daa73c2155a6f93cf5d64f65cef8",
|
|
12
12
|
"index.js": "8586303b3d1bf937932159adbe9b69c1031e6a393300e7d3aca93910ddfab082",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"lib/secure-store.js": "b8f365197f8e60d7f81fde6ed1cfc8851b603f6b0783e4cdc9036bb5c99726e1",
|
|
20
20
|
"master-domain.js": "10b7dfb43eb9939eb5baec54f742076cc73a2add6589a0ff57c51bc79c236faf",
|
|
21
21
|
"network-session.js": "db2d81a7ef47af29236d963b98e21414a11fef68e8b20895126eaad3f696ba3d",
|
|
22
|
-
"package.json": "
|
|
22
|
+
"package.json": "ef4824ccb46ddb3f901dd6e7a94abbd458152a2e73292ec409470643f45ff396",
|
|
23
23
|
"remote-runtime.js": "55dd7e577a822be17c2f337798a2d7f44ad0c5b6d68c46490e058282135c4658",
|
|
24
24
|
"slave-operations.js": "fec2e8addfff98f080284f24f722c1516124e5f6d12d8c03bb3c9cc0c475d1d6",
|
|
25
25
|
"state-store.js": "c56849a3f1b9c990128276e17963034a7836abacedc44f2e500d5732ebf9e451",
|
|
26
|
-
"test/batch-runner.test.js": "
|
|
26
|
+
"test/batch-runner.test.js": "69f69150eadd18c1ad1bc54f429e6cb5bc0c4492e3c6a6e76c2ce6827780ae41",
|
|
27
27
|
"test/bootstrap-url.test.js": "62c112b1a38c59ea2c77f797e32873667b52db32386da661a6ae8410490126fe",
|
|
28
28
|
"test/encrypted-frames.test.js": "cfb3195d3a58df7dc570bc7840a21c1841a53e0abc8b92840e0c24ed3435bcc1",
|
|
29
29
|
"test/handshake-crypto.test.js": "f11d6e95658f2055d8256bd7dfb66b39bedf95bf62a3cec5525b109bb6f9bc95",
|
|
@@ -35,6 +35,158 @@
|
|
|
35
35
|
"test/slave-operations.test.js": "a84526ad7554c7d03192a68655b4637bec18750559a5c3436f7471e912ca74cc",
|
|
36
36
|
"tool.manifest.json": "abf24c67b1d9ef0331ded59e04dcc092772419e74691c0d753ab51b40286d6f6"
|
|
37
37
|
}
|
|
38
|
+
},
|
|
39
|
+
"mcp-client": {
|
|
40
|
+
"version": "0.1.0",
|
|
41
|
+
"files": {
|
|
42
|
+
"README.md": "798125171049f939f4487e1a023cb3a11b3c28aae96b2687df1681a11bad8dc0",
|
|
43
|
+
"config.js": "b5b05fb242034e2d04b6301e848da9701c95be195ba1cdac2421964e9a7db8c9",
|
|
44
|
+
"index.js": "ba828f353ef23cd7acc3a064f859f553705836e4ede5d31ea0824a761cc88c2a",
|
|
45
|
+
"mcp-session.js": "51765b46f410e1cd49647235b611db0b10af20c9707efcacfbe0ff7dabe3c1ff",
|
|
46
|
+
"network-security.js": "60a020d4e3c7a4784a5a4e7b7246ee34e63ac73ee2316e09a09d10668dc8a7bc",
|
|
47
|
+
"oauth-device.js": "698aa9255bae47190c63527db7680aaab4f06392a108a0ff6444e32d31b7b89f",
|
|
48
|
+
"oauth-watch-plan.js": "b1bbed52eeb0e2e50dd52d733897ebd70573fea3ff5f023b3c63347f92633d3e",
|
|
49
|
+
"package-lock.json": "fd7b6bf4545de4056908bd656a4a4e21b9f84acc7b06d8c1d581a8c84c295e90",
|
|
50
|
+
"package.json": "16d423b77a32902671a751b1d673077c789a5bc3c79254bde296e4a4207fc4e3",
|
|
51
|
+
"state-store.js": "a8fb63096b8efdec8de1cb386eff371f1552f3fd71d96f25036e1c724285e0af",
|
|
52
|
+
"test/mcp-client.test.js": "188b253343f551303d1ee6ab2adc34e7153282461ba7399b598fe292e78a22a1",
|
|
53
|
+
"tool.manifest.json": "5659c398922c914c5bf893404519a30071ee685ab49f34a650ecafd585b4d6ec"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"magnific-mcp": {
|
|
57
|
+
"version": "0.1.0",
|
|
58
|
+
"toolDependencies": {
|
|
59
|
+
"mcp-client": "^0.1.0"
|
|
60
|
+
},
|
|
61
|
+
"files": {
|
|
62
|
+
"README.md": "00342fc9ae98f38716aeb332941524336c0e9ee4a5020104e52e7ed7b61882f9",
|
|
63
|
+
"config.js": "98a629781a1b2541806050952aa78a1e6e1b1671a6f1df7ba36c70dd116936a7",
|
|
64
|
+
"delivery-claims.js": "52f05a5bd1ece1ab21f7d9a49f362f9c55f101ef5723efd642dbecf0236921cd",
|
|
65
|
+
"generation-watch-plan.js": "eb60660341f254adc224181ca19dbbb969ef1d676aeaab60b71a8567f52648fe",
|
|
66
|
+
"index.js": "da7d35f2685fa0d5e716073f20725d7a5a4a0c477a1982b106a314662641b989",
|
|
67
|
+
"magnific-api.js": "39fa9a122577029111965c3e8487565c88ce46b61dec5ca685acf1c76cd3b636",
|
|
68
|
+
"network.js": "b45e43b49eea98ca7d80921ebfa6daf8b0a85d2079d4653f9eda682bc82101ae",
|
|
69
|
+
"package.json": "10ded9e89c13b500208717610984fd837e67e82ac3b31b21fe0058bd53c22a96",
|
|
70
|
+
"state-store.js": "c3ee744509f7a6be251cd895406bd1c70827f53cbdc1ac9d1c2a6e48479bfe1e",
|
|
71
|
+
"test/magnific-mcp.test.js": "c6345e70a7834a22df49abaf648c781f4da2e4d0790cbc13035c8af433c814c5",
|
|
72
|
+
"tool.manifest.json": "bbb24f54814c67f1ca1e119e6767e59d48f8e0cbc7f92444cf8e22fcc2fe06ed"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"campaign-draft-runner": {
|
|
76
|
+
"version": "0.1.0",
|
|
77
|
+
"toolDependencies": {
|
|
78
|
+
"pr-campaign": "^0.1.0",
|
|
79
|
+
"gmail-workspace": "^0.1.0"
|
|
80
|
+
},
|
|
81
|
+
"files": {
|
|
82
|
+
"README.md": "4e97db605c55c31c5fdb3ad83973f7733cef7a689b71b6d014fe07df631a4f99",
|
|
83
|
+
"config.js": "3c0c252baa7170e0bf0a9d1a7ecdb4febcf19f7baf0fcd320c0b852008f41b63",
|
|
84
|
+
"index.js": "0fd4574c70e7d008714f17eb54ccc34bc703a1fee7ab7eae768d79f86d2e747c",
|
|
85
|
+
"package.json": "a25b7ed1dd2c30cd68c3c10feb8ee1752cac8cd55cd4344690ffad649e231ec1",
|
|
86
|
+
"test/selection-policy.test.js": "b1bc804ba2be210230e78d7e4cfa5469e07e75c6ee944f58d77e6d00e88561cd",
|
|
87
|
+
"tool.manifest.json": "2609869985fd78000c999a9ae03f4b251c0aa945d19eed97e630f70da97c72ce"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"pr-campaign": {
|
|
91
|
+
"version": "0.1.0",
|
|
92
|
+
"files": {
|
|
93
|
+
"config.js": "f265f3a15721d3b04fcfd259d62e33c62c35ed03d7cd33e432cd32b1c44ac84f",
|
|
94
|
+
"contact-dedupe.js": "00cec722c5987c40eced127b0528004a5c54c0c6463c27c04ba37daf51c13f25",
|
|
95
|
+
"index.js": "9e858aed2510d3a2e93f38f693f0e0b5d8b2cac6965c84872aad91f785754d0a",
|
|
96
|
+
"package.json": "3919118d382b80153aab2dade602eb7ebad632642997c8d20b3561c517b2b7a6",
|
|
97
|
+
"test/add-contact-dedupe.test.js": "7a8f8c097181d5c42697e4f4c15e6bd080b4c9304a9878fd20d4b4b6a8300340",
|
|
98
|
+
"test/contact-dedupe.test.js": "be636643881c10105c731c923d0ac07db62fc4a663d7ed3badb2649119223a32",
|
|
99
|
+
"tool.manifest.json": "9c68d89276996039b055c43b4b4f82499ea684edbb36d9bfedcc909a3a23a80f"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"gmail-workspace": {
|
|
103
|
+
"version": "0.1.0",
|
|
104
|
+
"files": {
|
|
105
|
+
"config.js": "6ad295ec4cedbc936835d8f86c7528e0939ef09d5792c003308d2ee85dc5eea4",
|
|
106
|
+
"index.js": "495b5cec129a71638ab9b2682cf575eb8659e9a100b2e70deb0c523e60b69886",
|
|
107
|
+
"package.json": "1e88d42180a8dacd08c7ad1aa84d783991f901bb3bca7f0dddc4efd919470bdc",
|
|
108
|
+
"secretary-state.js": "0c4ef04db0d990a92b4b49ef62135baea76b7e4d5c232dfbf2087c61d1ce1948",
|
|
109
|
+
"test/secretary-state.test.mjs": "d8e866400853b39dc26e4b4ec09880c3cb1dd0b0091b2d25097388adf38559e7",
|
|
110
|
+
"tool.manifest.json": "93583b8c3a5f417435e3b3e88b129d2c610f2f168788e510f4cb2c03d4aef3a4"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"x-campaign-runner": {
|
|
114
|
+
"version": "0.1.0",
|
|
115
|
+
"toolDependencies": {
|
|
116
|
+
"x-dm": "^0.2.0"
|
|
117
|
+
},
|
|
118
|
+
"files": {
|
|
119
|
+
"README.md": "7cb7264446b9bef41332da9634cd6c94130f55c740142d084cddec776cf703c8",
|
|
120
|
+
"config.js": "5eb3c5667d01705d48504a4bf711347262b8a440605cb6b75ec519dd56cb1309",
|
|
121
|
+
"index.js": "19ca6dd9aa62b15e62481c6c7ce65023af6a25a21ffc622527acae12ff0171ed",
|
|
122
|
+
"package.json": "7a2dd72ce45cb1f3946b2459362ed39b82478d6df622a78690a0cc483fa03043",
|
|
123
|
+
"test/x-campaign-runner.test.mjs": "cf62245bccc7d7b5804117ca02753130e7eec4f56fcc671af82757f922117389",
|
|
124
|
+
"tool.manifest.json": "ebde15ad3666ed985377ae8ff67264567f3d5db408b5ec0823617f386ef46140"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"x-dm": {
|
|
128
|
+
"version": "0.2.0",
|
|
129
|
+
"files": {
|
|
130
|
+
"README.md": "f02835c10d822ce906df121441761de8c6d61c3a4aac3f9aa9a6d9211b73a6ea",
|
|
131
|
+
"config.js": "69a2dcccd10aa2f1ddcc24d52f4ce8fe4a6f5f5a85be64abbdf9dc9e19de0cd4",
|
|
132
|
+
"index.js": "cf4f92e94b9f21f6fcfed7d8d2926105a11b4ad621e2121c762d9c1e67a91456",
|
|
133
|
+
"package.json": "3a76a921b1e78e91b1d2a5ae1926b298dfd6b4ee3f716d5382159b474ee400f4",
|
|
134
|
+
"test/x-dm.test.mjs": "06352996e14777358eb62ad5e5d757b0dab5c0696927ed54ff40a5b7cdefcfd0",
|
|
135
|
+
"tool.manifest.json": "f3b2e613562e4dd0f88d196c4e3caf525a425483133a54351300ce284a5836a9"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"official-tool-sync": {
|
|
139
|
+
"version": "1.0.0",
|
|
140
|
+
"toolDependencies": {
|
|
141
|
+
"trash": "^1.0.0"
|
|
142
|
+
},
|
|
143
|
+
"files": {
|
|
144
|
+
".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
|
|
145
|
+
"config.js": "744c445b1d2ff65b77f38a5473c24e50a32f4288c4a08c25a874a478086c08c8",
|
|
146
|
+
"index.js": "fdd4167c63cd33c8e7640cb7ce09fd618dbd416030aa920407392e4591543e94",
|
|
147
|
+
"package.json": "4447cb5d4e0a04526604dfb9820c44af88349c27e208f27baa148686846559da",
|
|
148
|
+
"sync-lib.js": "c9f2cd7e19370088ab5fd10f6b2ada52c07d2e405674a356d0989f9a0f4984f6",
|
|
149
|
+
"sync-lib.test.js": "c97cf850d9f42f6b121a458863b048bdcaa6d7d0475642f20742c5862ebf7cc4",
|
|
150
|
+
"tool.manifest.json": "8e0f94ad786bdaf9edb1a65cd03438e26c1e9927e8db9a5a39e349e7ef3c6cd3"
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"trash": {
|
|
154
|
+
"version": "1.0.0",
|
|
155
|
+
"files": {
|
|
156
|
+
".gitignore": "4d56952b0fb13bf8f9b6c13a6d4c34a075bac3af447636a1df4335d7576e2f97",
|
|
157
|
+
"config.js": "ad76578e9dcc05c2e45854de9fa2cd41285fd8dcdb9a7d9ee2056e0f8b2d68d6",
|
|
158
|
+
"index.js": "d562d2466bddc93dd9a3bc5455962a3457c50368ee5dde0607cae3ff5a88578a",
|
|
159
|
+
"package.json": "18ec594d43b6595c587b16125b9ce0c9426fdf00a28d7e342834e31e360575f8",
|
|
160
|
+
"tool.manifest.json": "4f236d274c891b55e4445d459cff6a3337a5d13adc5e8aca7fb965ff6aba4e4d",
|
|
161
|
+
"trash-store.js": "1318e0f9539292684c0c2ec2f1b7189f066fdba42f78e07821b067792f40e8c9",
|
|
162
|
+
"trash-store.test.js": "5647edba4ab5e5492764ccf8ba3e674e42b63942623d779b0bf69465c5adb53f"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"process-retrospective": {
|
|
166
|
+
"version": "1.0.0",
|
|
167
|
+
"files": {
|
|
168
|
+
"README.md": "7fa901adf532dbd1bb337a8019b0bd73978eef3b1ded51ffb24a3279d107056d",
|
|
169
|
+
"config.js": "30703e809f0a2c4b85ffb1e1f9cd7ee599224e9bc62c3bc19e71e271cbc72b5d",
|
|
170
|
+
"index.js": "9bd1ae078293211387ee3035b4c4dc7cc5852d08503cd55cf5fb3187cf1ace34",
|
|
171
|
+
"package.json": "e3978089354004e495b7c7f4b4edd9c0984b34f68229d0dfdafbb2e606d48c8d",
|
|
172
|
+
"reflection-plan.js": "ae78b47f5108993395fe9a6f1ff2eea0663a07ae1100780f9a63107fd6402314",
|
|
173
|
+
"state-store.js": "6d0d39bff7e5e16558123c088eb8946bf3758596ae974598936b94424618c7cf",
|
|
174
|
+
"test/reflection-plan.test.js": "d4e960948fc76aaed03651652a592ee4b3109abbb91693d415945cbb79642237",
|
|
175
|
+
"tool.manifest.json": "4304208986be075c95c6d71aa97d301fd266af18fef1b6ddac4cf004e38427e7"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"creator-scout": {
|
|
179
|
+
"version": "1.0.1",
|
|
180
|
+
"files": {
|
|
181
|
+
"README.md": "4f50850317c0875ad7ddea767c7dda112669112bec107a98e67a31a42787b82c",
|
|
182
|
+
"config.js": "bab728665650b986c0eaef8e1be1c259ec42b1f83df4217c9780f5468d3c7666",
|
|
183
|
+
"index.js": "d1266d622b6abaf77ce1fe93823d4f2faedb8a5991371997c364082a198dc728",
|
|
184
|
+
"package-lock.json": "ed479120b59c2d9b083991dea60eb7750ba36bc7b2c7defb01cfb598889b8d90",
|
|
185
|
+
"package.json": "ad463eeddea6a958ef291d58f216c0b42c5ff3b398b62ed9512b857ea5e4b672",
|
|
186
|
+
"reference-match.js": "762d822ad31f89c06cb5a40f84ba3f864436db486375ed30e48bde94de282c7c",
|
|
187
|
+
"test/reference-match.test.js": "701ce83396126b1e42bd3a54e331ff011a1fc27646a0f3aa99ce1c3e576aff6d",
|
|
188
|
+
"tool.manifest.json": "0617b0488035fd7f8a83a8e5a698558b3d0e956e7ea1e043e2e80bb224d4974f"
|
|
189
|
+
}
|
|
38
190
|
}
|
|
39
191
|
}
|
|
40
192
|
}
|
|
@@ -43,6 +43,13 @@ function normalizeLimit(limit) {
|
|
|
43
43
|
return Math.min(value, 100);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function normalizeAcknowledgement(value) {
|
|
47
|
+
if (value == null || value === "") return "";
|
|
48
|
+
const acknowledgement = requireString(value, "acknowledgement").trim();
|
|
49
|
+
if (acknowledgement.length > 500) throw new Error("acknowledgement must be at most 500 characters");
|
|
50
|
+
return acknowledgement;
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
export function createArisaCapabilities({
|
|
47
54
|
artifactStore,
|
|
48
55
|
taskStore,
|
|
@@ -206,7 +213,11 @@ export function createArisaCapabilities({
|
|
|
206
213
|
const resourceId = String(params.resourceId || "").trim();
|
|
207
214
|
return taskStore.add({
|
|
208
215
|
kind: "agent_event",
|
|
209
|
-
payload: {
|
|
216
|
+
payload: {
|
|
217
|
+
prompt: requireString(params.prompt, "prompt"),
|
|
218
|
+
resourceId,
|
|
219
|
+
acknowledgement: normalizeAcknowledgement(params.acknowledgement)
|
|
220
|
+
}
|
|
210
221
|
}, {
|
|
211
222
|
payload: { chatId: scopedChatId },
|
|
212
223
|
source: { type: "tool", toolName: scopedToolName, chatId: scopedChatId, resourceId }
|
|
@@ -135,6 +135,7 @@ export async function createApp({ logger, runtimeOverrides, requestRestart } = {
|
|
|
135
135
|
toolProcessSupervisor,
|
|
136
136
|
daemonPolicy: config.daemons,
|
|
137
137
|
doctorPolicy: config.doctor,
|
|
138
|
+
inspectToolDependencies: async () => toolRegistry.dependencyIssues(),
|
|
138
139
|
inspectInfrastructure: async () => {
|
|
139
140
|
const tool = toolRegistry.get("master-slave");
|
|
140
141
|
if (!tool) return null;
|