@botcord/daemon 0.2.89 → 0.2.91
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/cloud-daemon.js +18 -4
- package/dist/daemon.d.ts +2 -3
- package/dist/daemon.js +21 -6
- package/dist/gateway/channels/botcord.js +35 -22
- package/dist/provision.d.ts +1 -0
- package/dist/provision.js +103 -9
- package/dist/runtime-models.js +46 -0
- package/dist/self-restart.d.ts +29 -0
- package/dist/self-restart.js +172 -0
- package/dist/skill-index.d.ts +14 -2
- package/dist/skill-index.js +109 -41
- package/dist/skill-installer.d.ts +61 -0
- package/dist/skill-installer.js +340 -0
- package/dist/system-context.d.ts +6 -0
- package/dist/system-context.js +1 -1
- package/package.json +3 -3
- package/src/__tests__/provision.test.ts +23 -0
- package/src/__tests__/runtime-discovery.test.ts +6 -3
- package/src/__tests__/runtime-models.test.ts +53 -0
- package/src/__tests__/self-restart.test.ts +57 -0
- package/src/__tests__/skill-index.test.ts +130 -13
- package/src/__tests__/skill-installer.test.ts +224 -0
- package/src/cloud-daemon.ts +17 -4
- package/src/daemon.ts +23 -8
- package/src/gateway/__tests__/botcord-channel.test.ts +38 -0
- package/src/gateway/channels/botcord.ts +41 -22
- package/src/provision.ts +111 -14
- package/src/runtime-models.ts +47 -0
- package/src/self-restart.ts +218 -0
- package/src/skill-index.ts +130 -53
- package/src/skill-installer.ts +472 -0
- package/src/system-context.ts +7 -1
package/src/skill-index.ts
CHANGED
|
@@ -8,8 +8,10 @@ import { homedir } from "node:os";
|
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import {
|
|
10
10
|
agentCodexHomeDir,
|
|
11
|
+
agentHermesHomeDir,
|
|
11
12
|
agentWorkspaceDir,
|
|
12
13
|
} from "./agent-workspace.js";
|
|
14
|
+
import { hermesProfileHomeDir } from "./gateway/runtimes/hermes-agent.js";
|
|
13
15
|
|
|
14
16
|
const MAX_SKILLS = 24;
|
|
15
17
|
const MAX_DESCRIPTION_CHARS = 260;
|
|
@@ -19,6 +21,8 @@ export interface SoftSkillEntry {
|
|
|
19
21
|
name: string;
|
|
20
22
|
path: string;
|
|
21
23
|
source: string;
|
|
24
|
+
runtime?: string;
|
|
25
|
+
profile?: string;
|
|
22
26
|
description?: string;
|
|
23
27
|
mtimeMs: number;
|
|
24
28
|
}
|
|
@@ -26,53 +30,118 @@ export interface SoftSkillEntry {
|
|
|
26
30
|
export interface AgentSkillSnapshotEntry {
|
|
27
31
|
name: string;
|
|
28
32
|
source: string;
|
|
33
|
+
sourceDetail?: string;
|
|
34
|
+
runtime?: string;
|
|
35
|
+
path?: string;
|
|
36
|
+
profile?: string;
|
|
29
37
|
description?: string;
|
|
30
38
|
mtimeMs: number;
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
export interface AgentSkillSnapshot {
|
|
34
42
|
agentId: string;
|
|
43
|
+
runtime?: string;
|
|
35
44
|
skills: AgentSkillSnapshotEntry[];
|
|
36
45
|
probedAt: number;
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
export interface SkillIndexOptions {
|
|
40
49
|
extraDirs?: string[];
|
|
50
|
+
hermesProfile?: string;
|
|
41
51
|
includeGlobal?: boolean;
|
|
42
52
|
runtime?: string;
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
interface SkillRoot {
|
|
56
|
+
dir: string;
|
|
57
|
+
source: string;
|
|
58
|
+
runtime?: string;
|
|
59
|
+
profile?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
export function defaultSkillDirs(
|
|
46
63
|
agentId: string,
|
|
47
64
|
opts: SkillIndexOptions = {},
|
|
48
|
-
):
|
|
65
|
+
): SkillRoot[] {
|
|
49
66
|
const includeGlobal = opts.includeGlobal !== false;
|
|
50
67
|
const agentClaude = {
|
|
51
68
|
dir: path.join(agentWorkspaceDir(agentId), ".claude", "skills"),
|
|
52
69
|
source: "agent-claude",
|
|
70
|
+
runtime: "claude-code",
|
|
53
71
|
};
|
|
54
72
|
const agentCodex = {
|
|
55
73
|
dir: path.join(agentCodexHomeDir(agentId), "skills"),
|
|
56
74
|
source: "agent-codex",
|
|
75
|
+
runtime: "codex",
|
|
57
76
|
};
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
const agentGemini = [
|
|
78
|
+
{
|
|
79
|
+
dir: path.join(agentWorkspaceDir(agentId), ".gemini", "skills"),
|
|
80
|
+
source: "agent-gemini",
|
|
81
|
+
runtime: "gemini",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
dir: path.join(agentWorkspaceDir(agentId), ".agents", "skills"),
|
|
85
|
+
source: "agent-agents",
|
|
86
|
+
runtime: "gemini",
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
const agentHermes = hermesSkillRoot(agentId, opts.hermesProfile);
|
|
90
|
+
|
|
91
|
+
const dirs: SkillRoot[] = [];
|
|
92
|
+
switch (runtimeFamily(opts.runtime)) {
|
|
93
|
+
case "codex":
|
|
94
|
+
dirs.push(agentCodex);
|
|
95
|
+
if (includeGlobal) {
|
|
96
|
+
dirs.push({
|
|
97
|
+
dir: path.join(homedir(), ".codex", "skills"),
|
|
98
|
+
source: "global-codex",
|
|
99
|
+
runtime: "codex",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
case "hermes":
|
|
104
|
+
dirs.push(agentHermes);
|
|
105
|
+
break;
|
|
106
|
+
case "gemini":
|
|
107
|
+
dirs.push(...agentGemini);
|
|
108
|
+
if (includeGlobal) {
|
|
109
|
+
dirs.push(
|
|
110
|
+
{
|
|
111
|
+
dir: path.join(homedir(), ".gemini", "skills"),
|
|
112
|
+
source: "global-gemini",
|
|
113
|
+
runtime: "gemini",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
dir: path.join(homedir(), ".agents", "skills"),
|
|
117
|
+
source: "global-agents",
|
|
118
|
+
runtime: "gemini",
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case "claude":
|
|
124
|
+
dirs.push(agentClaude);
|
|
125
|
+
if (includeGlobal) {
|
|
126
|
+
dirs.push({
|
|
127
|
+
dir: path.join(homedir(), ".claude", "skills"),
|
|
128
|
+
source: "global-claude",
|
|
129
|
+
runtime: "claude-code",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
case "other":
|
|
134
|
+
break;
|
|
71
135
|
}
|
|
72
136
|
|
|
73
137
|
const envDirs = parseSkillDirsEnv(process.env.BOTCORD_SKILL_DIRS);
|
|
74
138
|
for (const dir of [...envDirs, ...(opts.extraDirs ?? [])]) {
|
|
75
|
-
dirs.push({
|
|
139
|
+
dirs.push({
|
|
140
|
+
dir,
|
|
141
|
+
source: "external",
|
|
142
|
+
...(opts.runtime ? { runtime: opts.runtime } : {}),
|
|
143
|
+
...(opts.hermesProfile ? { profile: opts.hermesProfile } : {}),
|
|
144
|
+
});
|
|
76
145
|
}
|
|
77
146
|
|
|
78
147
|
return dedupeDirs(expandSkillRoots(dirs));
|
|
@@ -114,6 +183,8 @@ export function scanSoftSkills(
|
|
|
114
183
|
name: parsed.name,
|
|
115
184
|
path: skillMd,
|
|
116
185
|
source: root.source,
|
|
186
|
+
...(root.runtime ? { runtime: root.runtime } : {}),
|
|
187
|
+
...(root.profile ? { profile: root.profile } : {}),
|
|
117
188
|
description: parsed.description,
|
|
118
189
|
mtimeMs: st.mtimeMs,
|
|
119
190
|
};
|
|
@@ -133,9 +204,14 @@ export function collectAgentSkillSnapshot(
|
|
|
133
204
|
): AgentSkillSnapshot {
|
|
134
205
|
return {
|
|
135
206
|
agentId,
|
|
207
|
+
...(opts.runtime ? { runtime: opts.runtime } : {}),
|
|
136
208
|
skills: scanSoftSkills(agentId, opts).map((skill) => ({
|
|
137
209
|
name: skill.name,
|
|
138
|
-
source: skill.source
|
|
210
|
+
source: snapshotSource(skill.source),
|
|
211
|
+
sourceDetail: skill.source,
|
|
212
|
+
...(skill.runtime ? { runtime: skill.runtime } : {}),
|
|
213
|
+
path: skill.path,
|
|
214
|
+
...(skill.profile ? { profile: skill.profile } : {}),
|
|
139
215
|
...(skill.description ? { description: skill.description } : {}),
|
|
140
216
|
mtimeMs: skill.mtimeMs,
|
|
141
217
|
})),
|
|
@@ -217,66 +293,67 @@ function parseSkillDirsEnv(value: string | undefined): string[] {
|
|
|
217
293
|
}
|
|
218
294
|
|
|
219
295
|
function dedupeDirs(
|
|
220
|
-
dirs:
|
|
221
|
-
):
|
|
296
|
+
dirs: SkillRoot[],
|
|
297
|
+
): SkillRoot[] {
|
|
222
298
|
const seen = new Set<string>();
|
|
223
|
-
const out:
|
|
299
|
+
const out: SkillRoot[] = [];
|
|
224
300
|
for (const entry of dirs) {
|
|
225
301
|
const resolved = path.resolve(entry.dir);
|
|
226
302
|
if (seen.has(resolved)) continue;
|
|
227
303
|
seen.add(resolved);
|
|
228
|
-
out.push({ dir: resolved
|
|
304
|
+
out.push({ ...entry, dir: resolved });
|
|
229
305
|
}
|
|
230
306
|
return out;
|
|
231
307
|
}
|
|
232
308
|
|
|
233
|
-
function expandSkillRoots(
|
|
234
|
-
|
|
235
|
-
): Array<{ dir: string; source: string }> {
|
|
236
|
-
const out: Array<{ dir: string; source: string }> = [];
|
|
309
|
+
function expandSkillRoots(dirs: SkillRoot[]): SkillRoot[] {
|
|
310
|
+
const out: SkillRoot[] = [];
|
|
237
311
|
for (const entry of dirs) {
|
|
238
312
|
out.push(entry);
|
|
239
313
|
if (entry.source.includes("codex")) {
|
|
240
|
-
out.push({ dir: path.join(entry.dir, ".system")
|
|
314
|
+
out.push({ ...entry, dir: path.join(entry.dir, ".system") });
|
|
241
315
|
}
|
|
242
316
|
}
|
|
243
317
|
return out;
|
|
244
318
|
}
|
|
245
319
|
|
|
246
|
-
function
|
|
320
|
+
function hermesSkillRoot(agentId: string, profile: string | undefined): SkillRoot {
|
|
321
|
+
if (profile) {
|
|
322
|
+
try {
|
|
323
|
+
return {
|
|
324
|
+
dir: path.join(hermesProfileHomeDir(profile), "skills"),
|
|
325
|
+
source: "agent-hermes-profile",
|
|
326
|
+
runtime: "hermes-agent",
|
|
327
|
+
profile,
|
|
328
|
+
};
|
|
329
|
+
} catch {
|
|
330
|
+
// Corrupt legacy credentials should not make the whole skill snapshot fail.
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
dir: path.join(agentHermesHomeDir(agentId), "skills"),
|
|
335
|
+
source: "agent-hermes",
|
|
336
|
+
runtime: "hermes-agent",
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function runtimeFamily(runtime: string | undefined): "codex" | "claude" | "gemini" | "hermes" | "other" {
|
|
247
341
|
if (runtime === "codex") return "codex";
|
|
342
|
+
if (runtime === "gemini") return "gemini";
|
|
343
|
+
if (runtime === "hermes-agent") return "hermes";
|
|
344
|
+
if (!runtime) return "claude";
|
|
248
345
|
if (runtime === "claude-code") return "claude";
|
|
249
346
|
return "other";
|
|
250
347
|
}
|
|
251
348
|
|
|
252
|
-
function priority(source: string,
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
case "global-codex":
|
|
258
|
-
return 1;
|
|
259
|
-
case "agent-claude":
|
|
260
|
-
return 2;
|
|
261
|
-
case "global-claude":
|
|
262
|
-
return 3;
|
|
263
|
-
default:
|
|
264
|
-
return 4;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
349
|
+
function priority(source: string, _runtime: string | undefined): number {
|
|
350
|
+
if (source.startsWith("agent-")) return 0;
|
|
351
|
+
if (source.startsWith("global-")) return 1;
|
|
352
|
+
return 2;
|
|
353
|
+
}
|
|
267
354
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return 0;
|
|
271
|
-
case "agent-codex":
|
|
272
|
-
return 1;
|
|
273
|
-
case "global-claude":
|
|
274
|
-
return 2;
|
|
275
|
-
case "global-codex":
|
|
276
|
-
return 3;
|
|
277
|
-
default:
|
|
278
|
-
return 4;
|
|
279
|
-
}
|
|
355
|
+
function snapshotSource(source: string): "workspace" | "runtime-global" {
|
|
356
|
+
return source.startsWith("agent-") ? "workspace" : "runtime-global";
|
|
280
357
|
}
|
|
281
358
|
|
|
282
359
|
function unquote(value: string): string {
|