@runfusion/fusion 0.20.0 → 0.22.0
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/dist/bin.js +2021 -996
- package/dist/client/assets/AgentDetailView-BKKpbp1S.js +18 -0
- package/dist/client/assets/AgentDetailView-CeO_1MK7.css +1 -0
- package/dist/client/assets/AgentsView-BRXFmrcJ.js +527 -0
- package/dist/client/assets/AgentsView-Bs03ptrd.css +1 -0
- package/dist/client/assets/ChatView-D7L2e_qu.js +1 -0
- package/dist/client/assets/DevServerView-l8RCyL2k.js +1 -0
- package/dist/client/assets/DirectoryPicker-CS1dwqcC.js +1 -0
- package/dist/client/assets/DocumentsView-DmthQWDZ.js +1 -0
- package/dist/client/assets/{InsightsView-Cqim12az.js → InsightsView-DvXpMKmH.js} +2 -2
- package/dist/client/assets/{MemoryView-CakLoJtY.js → MemoryView-CPwlKnUI.js} +2 -2
- package/dist/client/assets/{NodesView-BxGm3poT.js → NodesView-BLlfUfsy.js} +3 -3
- package/dist/client/assets/{PiExtensionsManager-lJbmskyZ.js → PiExtensionsManager-j8rPXqmB.js} +2 -2
- package/dist/client/assets/PluginManager-pW6RMz5z.js +1 -0
- package/dist/client/assets/ResearchView-D9DNJYDq.js +1 -0
- package/dist/client/assets/{RoadmapsView-CeKks_OI.js → RoadmapsView-Djc_X35v.js} +2 -2
- package/dist/client/assets/SettingsModal-WGCF_pk8.js +31 -0
- package/dist/client/assets/{SettingsModal-YdeVPhRJ.js → SettingsModal-fxvTFLtR.js} +1 -1
- package/dist/client/assets/SetupWizardModal-tG_MF_nA.js +1 -0
- package/dist/client/assets/SkillsView-Ddf0YL8z.js +1 -0
- package/dist/client/assets/agentSkills-DDHJnrkn.css +1 -0
- package/dist/client/assets/agentSkills-EwIwBlG8.js +1 -0
- package/dist/client/assets/folder-open-BiJpmnaT.js +6 -0
- package/dist/client/assets/index-D6ebxTPF.css +1 -0
- package/dist/client/assets/index-DYDLmOcK.js +694 -0
- package/dist/client/assets/{star-DxVRh9VT.js → star-BwRZmiuZ.js} +2 -2
- package/dist/client/assets/upload-D4NwZhPp.js +6 -0
- package/dist/client/assets/{users-3SD3oNMQ.js → users-DNISDtI1.js} +2 -2
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +1172 -401
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +480 -0
- package/dist/plugins/fusion-plugin-hermes-runtime/manifest.json +14 -0
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +11 -0
- package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +369 -0
- package/dist/plugins/fusion-plugin-openclaw-runtime/manifest.json +14 -0
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +11 -0
- package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +966 -0
- package/dist/plugins/fusion-plugin-paperclip-runtime/manifest.json +15 -0
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +11 -0
- package/package.json +3 -1
- package/skill/fusion/references/engine-tools.md +1 -1
- package/dist/client/assets/AgentDetailView-C6BG7O7i.js +0 -18
- package/dist/client/assets/AgentDetailView-CUtWvXBn.css +0 -1
- package/dist/client/assets/ChatView-DeXUYwSY.js +0 -1
- package/dist/client/assets/DevServerView-Dariyxt_.js +0 -1
- package/dist/client/assets/DirectoryPicker-SchiK-Aq.js +0 -1
- package/dist/client/assets/DocumentsView-C6v-tBhG.js +0 -1
- package/dist/client/assets/PluginManager-BZjNNf9m.js +0 -1
- package/dist/client/assets/ResearchView-Bzsr9V0y.js +0 -1
- package/dist/client/assets/SettingsModal-D-9CLguN.js +0 -31
- package/dist/client/assets/SetupWizardModal-DAC04LlA.js +0 -1
- package/dist/client/assets/SkillsView-CClC_5RN.js +0 -1
- package/dist/client/assets/index-CrHLf3pB.js +0 -1222
- package/dist/client/assets/index-Df1bHDY4.css +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion/pi-claude-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Fusion vendored fork: pi coding-agent extension that routes LLM calls through the Claude Code CLI. Forked from rchern/pi-claude-cli (MIT). See UPSTREAM.md.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": true,
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
// ../plugin-sdk/dist/index.js
|
|
2
|
+
function definePlugin(plugin2) {
|
|
3
|
+
return plugin2;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// ../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js
|
|
7
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import path, { sep as PATH_SEP } from "node:path";
|
|
10
|
+
var resolvedBinaryCache = /* @__PURE__ */ new Map();
|
|
11
|
+
function resolveBinaryForSpawn(binary) {
|
|
12
|
+
if (process.platform !== "win32")
|
|
13
|
+
return binary;
|
|
14
|
+
if (binary.includes(PATH_SEP) || binary.includes("/") || /\.[a-z]{2,4}$/i.test(binary)) {
|
|
15
|
+
return binary;
|
|
16
|
+
}
|
|
17
|
+
const cached = resolvedBinaryCache.get(binary);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
try {
|
|
21
|
+
const result = spawnSync("where", [binary], { encoding: "utf-8" });
|
|
22
|
+
if (result.status === 0) {
|
|
23
|
+
const first = (result.stdout ?? "").trim().split(/\r?\n/)[0];
|
|
24
|
+
if (first?.length) {
|
|
25
|
+
resolvedBinaryCache.set(binary, first);
|
|
26
|
+
return first;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
return binary;
|
|
32
|
+
}
|
|
33
|
+
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
34
|
+
var SESSION_ID_RE = /^session_id:\s+([0-9]{8}_[0-9]{6}_[0-9a-f]{6})\s*$/m;
|
|
35
|
+
var CHROME_LINE_RES = [
|
|
36
|
+
/^\s*┊\s/,
|
|
37
|
+
// memory/status sidebar lines
|
|
38
|
+
/^↻ Resumed session /,
|
|
39
|
+
// resume banner
|
|
40
|
+
/^╭─.*╮\s*$/,
|
|
41
|
+
// top box border
|
|
42
|
+
/^╰─.*╯\s*$/,
|
|
43
|
+
// bottom box border
|
|
44
|
+
/^Query:\s*/
|
|
45
|
+
// query echo line
|
|
46
|
+
];
|
|
47
|
+
var PROFILE_RULE_RE = /^[\s─]+$/;
|
|
48
|
+
var EM_DASH = "\u2014";
|
|
49
|
+
function parseProfileListOutput(raw) {
|
|
50
|
+
const lines = raw.replace(ANSI_RE, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
51
|
+
const profiles = [];
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (line.trim() === "")
|
|
54
|
+
continue;
|
|
55
|
+
if (/^\s*Profile\b/.test(line))
|
|
56
|
+
continue;
|
|
57
|
+
if (PROFILE_RULE_RE.test(line))
|
|
58
|
+
continue;
|
|
59
|
+
const stripped = line.replace(/^\s+/, "");
|
|
60
|
+
const columns = stripped.split(/\s{2,}/);
|
|
61
|
+
const rawName = columns[0] ?? "";
|
|
62
|
+
const isDefault = rawName.startsWith("\u25C6");
|
|
63
|
+
const name = rawName.replace(/^◆/, "").trim();
|
|
64
|
+
if (!name)
|
|
65
|
+
continue;
|
|
66
|
+
const toUndef = (v) => v === void 0 || v.trim() === "" || v.trim() === EM_DASH ? void 0 : v.trim();
|
|
67
|
+
profiles.push({
|
|
68
|
+
name,
|
|
69
|
+
model: toUndef(columns[1]),
|
|
70
|
+
gateway: toUndef(columns[2]),
|
|
71
|
+
alias: toUndef(columns[3]),
|
|
72
|
+
isDefault
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return profiles;
|
|
76
|
+
}
|
|
77
|
+
function hermesProfileHome(profileName) {
|
|
78
|
+
const base = process.env.HERMES_HOME ?? path.join(os.homedir(), ".hermes");
|
|
79
|
+
if (profileName === "default" || profileName === "")
|
|
80
|
+
return base;
|
|
81
|
+
return path.join(base, "profiles", profileName);
|
|
82
|
+
}
|
|
83
|
+
async function listHermesProfiles(opts) {
|
|
84
|
+
const binary = resolveBinaryForSpawn(opts?.binaryPath ?? "hermes");
|
|
85
|
+
const timeoutMs = opts?.timeoutMs ?? 5e3;
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
let settled = false;
|
|
88
|
+
const child = spawn(binary, ["profile", "list"], {
|
|
89
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
90
|
+
env: { ...process.env }
|
|
91
|
+
});
|
|
92
|
+
const timer = setTimeout(() => {
|
|
93
|
+
if (settled)
|
|
94
|
+
return;
|
|
95
|
+
settled = true;
|
|
96
|
+
try {
|
|
97
|
+
child.kill("SIGKILL");
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
reject(new Error(`hermes profile list failed: timed out after ${timeoutMs}ms`));
|
|
101
|
+
}, timeoutMs);
|
|
102
|
+
let stdout = "";
|
|
103
|
+
let stderr = "";
|
|
104
|
+
child.stdout?.on("data", (chunk) => {
|
|
105
|
+
stdout += chunk.toString("utf-8");
|
|
106
|
+
});
|
|
107
|
+
child.stderr?.on("data", (chunk) => {
|
|
108
|
+
stderr += chunk.toString("utf-8");
|
|
109
|
+
});
|
|
110
|
+
child.on("error", (err) => {
|
|
111
|
+
if (settled)
|
|
112
|
+
return;
|
|
113
|
+
settled = true;
|
|
114
|
+
clearTimeout(timer);
|
|
115
|
+
const isNotFound = err.code === "ENOENT";
|
|
116
|
+
reject(new Error(isNotFound ? `hermes profile list failed: binary not found at "${opts?.binaryPath ?? "hermes"}"` : `hermes profile list failed: ${err.message}`));
|
|
117
|
+
});
|
|
118
|
+
child.on("close", (code) => {
|
|
119
|
+
if (settled)
|
|
120
|
+
return;
|
|
121
|
+
settled = true;
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
if (code !== 0) {
|
|
124
|
+
const combined = [stdout, stderr].filter(Boolean).join("\n");
|
|
125
|
+
reject(new Error(`hermes profile list failed: process exited with code ${String(code)}.
|
|
126
|
+
${combined}`));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
resolve(parseProfileListOutput(stdout));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function resolveCliSettings(settings) {
|
|
134
|
+
const str = (v) => typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
|
|
135
|
+
const num = (v, envKey, fallback) => {
|
|
136
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0)
|
|
137
|
+
return v;
|
|
138
|
+
const raw = str(v) ?? str(process.env[envKey]);
|
|
139
|
+
if (raw !== void 0) {
|
|
140
|
+
const parsed = Number(raw);
|
|
141
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
142
|
+
return parsed;
|
|
143
|
+
}
|
|
144
|
+
return fallback;
|
|
145
|
+
};
|
|
146
|
+
const bool = (v, envKey, fallback) => {
|
|
147
|
+
if (typeof v === "boolean")
|
|
148
|
+
return v;
|
|
149
|
+
const raw = str(v) ?? str(process.env[envKey]);
|
|
150
|
+
if (raw !== void 0)
|
|
151
|
+
return raw === "1" || raw.toLowerCase() === "true";
|
|
152
|
+
return fallback;
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
binaryPath: str(settings?.binaryPath) ?? str(process.env.HERMES_BIN) ?? "hermes",
|
|
156
|
+
model: str(settings?.model) ?? str(process.env.HERMES_MODEL_ID),
|
|
157
|
+
provider: str(settings?.provider) ?? str(process.env.HERMES_PROVIDER),
|
|
158
|
+
maxTurns: num(settings?.maxTurns, "HERMES_MAX_TURNS", 12),
|
|
159
|
+
yolo: bool(settings?.yolo, "HERMES_YOLO", false),
|
|
160
|
+
cliTimeoutMs: num(settings?.cliTimeoutMs, "HERMES_CLI_TIMEOUT_MS", 3e5),
|
|
161
|
+
profile: str(settings?.profile) ?? str(process.env.HERMES_PROFILE)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function cleanText(raw) {
|
|
165
|
+
return raw.replace(ANSI_RE, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
166
|
+
}
|
|
167
|
+
function stripChrome(text) {
|
|
168
|
+
const lines = text.split("\n");
|
|
169
|
+
const filtered = lines.filter((line) => !CHROME_LINE_RES.some((re) => re.test(line)));
|
|
170
|
+
return filtered.join("\n").trim();
|
|
171
|
+
}
|
|
172
|
+
function parseHermesOutput(rawStdout, rawStderr) {
|
|
173
|
+
const cleaned = cleanText(rawStdout);
|
|
174
|
+
const match = SESSION_ID_RE.exec(cleaned);
|
|
175
|
+
if (!match) {
|
|
176
|
+
const combined = [rawStdout, rawStderr].filter(Boolean).join("\n");
|
|
177
|
+
throw new Error(`hermes: missing session_id in output.
|
|
178
|
+
${combined}`);
|
|
179
|
+
}
|
|
180
|
+
const sessionId = match[1];
|
|
181
|
+
const sessionIdLineStart = cleaned.lastIndexOf("\nsession_id:");
|
|
182
|
+
const bodyRaw = sessionIdLineStart >= 0 ? cleaned.slice(0, sessionIdLineStart) : cleaned;
|
|
183
|
+
const body = stripChrome(bodyRaw);
|
|
184
|
+
return { body, sessionId };
|
|
185
|
+
}
|
|
186
|
+
function buildHermesArgs(prompt, settings, resumeSessionId) {
|
|
187
|
+
const args = ["chat", "-q", prompt, "-Q", "--source", "tool"];
|
|
188
|
+
if (resumeSessionId) {
|
|
189
|
+
args.push("--resume", resumeSessionId);
|
|
190
|
+
}
|
|
191
|
+
if (settings.model) {
|
|
192
|
+
args.push("-m", settings.model);
|
|
193
|
+
}
|
|
194
|
+
if (settings.provider) {
|
|
195
|
+
args.push("--provider", settings.provider);
|
|
196
|
+
}
|
|
197
|
+
args.push("--max-turns", String(settings.maxTurns));
|
|
198
|
+
if (settings.yolo) {
|
|
199
|
+
args.push("--yolo");
|
|
200
|
+
}
|
|
201
|
+
return args;
|
|
202
|
+
}
|
|
203
|
+
async function invokeHermesCli(prompt, settings, resumeSessionId, signal) {
|
|
204
|
+
const args = buildHermesArgs(prompt, settings, resumeSessionId);
|
|
205
|
+
const binary = resolveBinaryForSpawn(settings.binaryPath);
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
let settled = false;
|
|
208
|
+
const spawnEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
|
|
209
|
+
if (settings.profile) {
|
|
210
|
+
spawnEnv.HERMES_HOME = hermesProfileHome(settings.profile);
|
|
211
|
+
}
|
|
212
|
+
const child = spawn(binary, args, {
|
|
213
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
214
|
+
env: spawnEnv
|
|
215
|
+
});
|
|
216
|
+
const hardKillTimer = setTimeout(() => {
|
|
217
|
+
if (settled)
|
|
218
|
+
return;
|
|
219
|
+
settled = true;
|
|
220
|
+
try {
|
|
221
|
+
child.kill("SIGKILL");
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
reject(new Error(`hermes: process timed out after ${settings.cliTimeoutMs}ms`));
|
|
225
|
+
}, settings.cliTimeoutMs);
|
|
226
|
+
const onAbort = () => {
|
|
227
|
+
if (settled)
|
|
228
|
+
return;
|
|
229
|
+
settled = true;
|
|
230
|
+
clearTimeout(hardKillTimer);
|
|
231
|
+
try {
|
|
232
|
+
child.kill("SIGTERM");
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
reject(new Error("hermes: invocation aborted"));
|
|
236
|
+
};
|
|
237
|
+
if (signal) {
|
|
238
|
+
if (signal.aborted) {
|
|
239
|
+
onAbort();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
243
|
+
}
|
|
244
|
+
let stdout = "";
|
|
245
|
+
let stderr = "";
|
|
246
|
+
child.stdout?.on("data", (chunk) => {
|
|
247
|
+
stdout += chunk.toString("utf-8");
|
|
248
|
+
});
|
|
249
|
+
child.stderr?.on("data", (chunk) => {
|
|
250
|
+
stderr += chunk.toString("utf-8");
|
|
251
|
+
});
|
|
252
|
+
child.on("error", (err) => {
|
|
253
|
+
if (settled)
|
|
254
|
+
return;
|
|
255
|
+
settled = true;
|
|
256
|
+
clearTimeout(hardKillTimer);
|
|
257
|
+
signal?.removeEventListener("abort", onAbort);
|
|
258
|
+
const isNotFound = err.code === "ENOENT";
|
|
259
|
+
reject(new Error(isNotFound ? `hermes: binary not found at "${settings.binaryPath}". Install hermes or set binaryPath/HERMES_BIN.` : `hermes: spawn error \u2014 ${err.message}`));
|
|
260
|
+
});
|
|
261
|
+
child.on("close", (code) => {
|
|
262
|
+
if (settled)
|
|
263
|
+
return;
|
|
264
|
+
settled = true;
|
|
265
|
+
clearTimeout(hardKillTimer);
|
|
266
|
+
signal?.removeEventListener("abort", onAbort);
|
|
267
|
+
if (code !== 0) {
|
|
268
|
+
const combined = [stdout, stderr].filter(Boolean).join("\n");
|
|
269
|
+
reject(new Error(`hermes: process exited with code ${String(code)}.
|
|
270
|
+
${combined}`));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
resolve(parseHermesOutput(stdout, stderr));
|
|
275
|
+
} catch (parseErr) {
|
|
276
|
+
reject(parseErr);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ../../plugins/fusion-plugin-hermes-runtime/dist/runtime-adapter.js
|
|
283
|
+
var HermesRuntimeAdapter = class {
|
|
284
|
+
id = "hermes";
|
|
285
|
+
name = "Hermes Runtime";
|
|
286
|
+
settings;
|
|
287
|
+
constructor(settings) {
|
|
288
|
+
this.settings = resolveCliSettings(settings);
|
|
289
|
+
}
|
|
290
|
+
async createSession(options) {
|
|
291
|
+
const session = {
|
|
292
|
+
model: void 0,
|
|
293
|
+
systemPrompt: options.systemPrompt,
|
|
294
|
+
messages: [],
|
|
295
|
+
apiKey: void 0,
|
|
296
|
+
thinkingLevel: void 0,
|
|
297
|
+
sessionId: "",
|
|
298
|
+
lastModelDescription: this.describeFromSettings(),
|
|
299
|
+
callbacks: {
|
|
300
|
+
onText: options.onText,
|
|
301
|
+
onThinking: options.onThinking,
|
|
302
|
+
onToolStart: options.onToolStart,
|
|
303
|
+
onToolEnd: options.onToolEnd
|
|
304
|
+
},
|
|
305
|
+
dispose: () => void 0
|
|
306
|
+
};
|
|
307
|
+
return { session, sessionFile: void 0 };
|
|
308
|
+
}
|
|
309
|
+
async promptWithFallback(session, prompt, _options) {
|
|
310
|
+
const resumeId = session.sessionId || void 0;
|
|
311
|
+
const result = await invokeHermesCli(prompt, this.settings, resumeId);
|
|
312
|
+
session.sessionId = result.sessionId;
|
|
313
|
+
session.lastModelDescription = this.describeFromSettings();
|
|
314
|
+
if (result.body) {
|
|
315
|
+
session.callbacks.onText?.(result.body);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
describeModel(session) {
|
|
319
|
+
return session.lastModelDescription || this.describeFromSettings();
|
|
320
|
+
}
|
|
321
|
+
async dispose(_session) {
|
|
322
|
+
}
|
|
323
|
+
describeFromSettings() {
|
|
324
|
+
const provider = this.settings.provider;
|
|
325
|
+
const model = this.settings.model;
|
|
326
|
+
if (provider && model)
|
|
327
|
+
return `hermes/${provider}/${model}`;
|
|
328
|
+
if (model)
|
|
329
|
+
return `hermes/${model}`;
|
|
330
|
+
if (provider)
|
|
331
|
+
return `hermes/${provider}`;
|
|
332
|
+
return "hermes";
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// ../../plugins/fusion-plugin-hermes-runtime/dist/probe.js
|
|
337
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
338
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
|
|
339
|
+
async function probeHermesBinary(opts) {
|
|
340
|
+
const startedAt = Date.now();
|
|
341
|
+
const binary = typeof opts?.binaryPath === "string" && opts.binaryPath.trim().length > 0 ? opts.binaryPath.trim() : "hermes";
|
|
342
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
343
|
+
const resolvedPath = await tryResolveBinaryPath(binary);
|
|
344
|
+
return new Promise((resolvePromise) => {
|
|
345
|
+
const finish = (result) => {
|
|
346
|
+
resolvePromise({ ...result, probeDurationMs: Date.now() - startedAt });
|
|
347
|
+
};
|
|
348
|
+
let settled = false;
|
|
349
|
+
const child = spawn2(resolvedPath ?? binary, ["--version"], {
|
|
350
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
351
|
+
});
|
|
352
|
+
const timer = setTimeout(() => {
|
|
353
|
+
if (settled)
|
|
354
|
+
return;
|
|
355
|
+
settled = true;
|
|
356
|
+
try {
|
|
357
|
+
child.kill("SIGKILL");
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
360
|
+
finish({
|
|
361
|
+
available: false,
|
|
362
|
+
binaryPath: resolvedPath,
|
|
363
|
+
reason: `Probe timed out after ${timeoutMs}ms`
|
|
364
|
+
});
|
|
365
|
+
}, timeoutMs);
|
|
366
|
+
let stdout = "";
|
|
367
|
+
let stderr = "";
|
|
368
|
+
child.stdout?.on("data", (chunk) => {
|
|
369
|
+
stdout += chunk.toString("utf-8");
|
|
370
|
+
});
|
|
371
|
+
child.stderr?.on("data", (chunk) => {
|
|
372
|
+
stderr += chunk.toString("utf-8");
|
|
373
|
+
});
|
|
374
|
+
child.on("error", (err) => {
|
|
375
|
+
if (settled)
|
|
376
|
+
return;
|
|
377
|
+
settled = true;
|
|
378
|
+
clearTimeout(timer);
|
|
379
|
+
const isNotFound = err.code === "ENOENT";
|
|
380
|
+
finish({
|
|
381
|
+
available: false,
|
|
382
|
+
binaryPath: resolvedPath,
|
|
383
|
+
reason: isNotFound ? `\`${binary}\` not found on PATH` : err.message
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
child.on("close", (code) => {
|
|
387
|
+
if (settled)
|
|
388
|
+
return;
|
|
389
|
+
settled = true;
|
|
390
|
+
clearTimeout(timer);
|
|
391
|
+
if (code === 0) {
|
|
392
|
+
finish({
|
|
393
|
+
available: true,
|
|
394
|
+
version: stdout.trim() || void 0,
|
|
395
|
+
binaryPath: resolvedPath
|
|
396
|
+
});
|
|
397
|
+
} else {
|
|
398
|
+
finish({
|
|
399
|
+
available: false,
|
|
400
|
+
binaryPath: resolvedPath,
|
|
401
|
+
reason: stderr.trim() || `hermes --version exited with code ${String(code)}`
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
async function tryResolveBinaryPath(binary) {
|
|
408
|
+
return new Promise((resolvePromise) => {
|
|
409
|
+
const which = process.platform === "win32" ? "where" : "which";
|
|
410
|
+
const child = spawn2(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
|
|
411
|
+
let out = "";
|
|
412
|
+
child.stdout?.on("data", (chunk) => {
|
|
413
|
+
out += chunk.toString("utf-8");
|
|
414
|
+
});
|
|
415
|
+
child.on("error", () => resolvePromise(void 0));
|
|
416
|
+
child.on("close", (code) => {
|
|
417
|
+
if (code === 0) {
|
|
418
|
+
const first = out.trim().split(/\r?\n/)[0];
|
|
419
|
+
resolvePromise(first?.length ? first : void 0);
|
|
420
|
+
} else {
|
|
421
|
+
resolvePromise(void 0);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ../../plugins/fusion-plugin-hermes-runtime/dist/index.js
|
|
428
|
+
var HERMES_RUNTIME_ID = "hermes";
|
|
429
|
+
var HERMES_RUNTIME_VERSION = "0.2.0";
|
|
430
|
+
var hermesRuntimeMetadata = {
|
|
431
|
+
runtimeId: HERMES_RUNTIME_ID,
|
|
432
|
+
name: "Hermes Runtime",
|
|
433
|
+
description: "Drives the local `hermes` CLI (NousResearch/hermes-agent)",
|
|
434
|
+
version: HERMES_RUNTIME_VERSION
|
|
435
|
+
};
|
|
436
|
+
var hermesRuntimeFactory = async (ctx) => {
|
|
437
|
+
return new HermesRuntimeAdapter(ctx.settings);
|
|
438
|
+
};
|
|
439
|
+
var plugin = definePlugin({
|
|
440
|
+
manifest: {
|
|
441
|
+
id: "fusion-plugin-hermes-runtime",
|
|
442
|
+
name: "Hermes Runtime Plugin",
|
|
443
|
+
version: HERMES_RUNTIME_VERSION,
|
|
444
|
+
description: "Drives the local `hermes` CLI for Fusion agents \u2014 captures session ids and resumes via --resume.",
|
|
445
|
+
author: "Fusion Team",
|
|
446
|
+
homepage: "https://github.com/NousResearch/hermes-agent",
|
|
447
|
+
runtime: hermesRuntimeMetadata
|
|
448
|
+
},
|
|
449
|
+
state: "installed",
|
|
450
|
+
hooks: {
|
|
451
|
+
onLoad: (ctx) => {
|
|
452
|
+
const settings = resolveCliSettings(ctx.settings);
|
|
453
|
+
ctx.logger.info(`Hermes Runtime Plugin loaded \u2014 binary=${settings.binaryPath} model=${settings.model ?? "(default)"}`);
|
|
454
|
+
ctx.emitEvent("hermes-runtime:loaded", {
|
|
455
|
+
runtimeId: HERMES_RUNTIME_ID,
|
|
456
|
+
version: HERMES_RUNTIME_VERSION
|
|
457
|
+
});
|
|
458
|
+
},
|
|
459
|
+
onUnload: () => {
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
runtime: {
|
|
463
|
+
metadata: hermesRuntimeMetadata,
|
|
464
|
+
factory: hermesRuntimeFactory
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
var index_default = plugin;
|
|
468
|
+
export {
|
|
469
|
+
HERMES_RUNTIME_ID,
|
|
470
|
+
HermesRuntimeAdapter,
|
|
471
|
+
buildHermesArgs,
|
|
472
|
+
index_default as default,
|
|
473
|
+
hermesRuntimeFactory,
|
|
474
|
+
hermesRuntimeMetadata,
|
|
475
|
+
invokeHermesCli,
|
|
476
|
+
listHermesProfiles,
|
|
477
|
+
parseHermesOutput,
|
|
478
|
+
probeHermesBinary,
|
|
479
|
+
resolveCliSettings
|
|
480
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "fusion-plugin-hermes-runtime",
|
|
3
|
+
"name": "Hermes Runtime Plugin",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Hermes AI runtime plugin for Fusion - provides AI agent execution runtime capabilities",
|
|
6
|
+
"author": "Fusion Team",
|
|
7
|
+
"homepage": "https://github.com/gsxdsm/fusion",
|
|
8
|
+
"runtime": {
|
|
9
|
+
"runtimeId": "hermes",
|
|
10
|
+
"name": "Hermes Runtime",
|
|
11
|
+
"description": "Hermes raw-model runtime using pi-ai direct streaming",
|
|
12
|
+
"version": "0.1.0"
|
|
13
|
+
}
|
|
14
|
+
}
|