@botcord/daemon 0.2.89 → 0.2.90
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/provision.d.ts +1 -0
- package/dist/provision.js +83 -7
- package/dist/runtime-models.js +46 -0
- package/dist/skill-index.d.ts +14 -2
- package/dist/skill-index.js +81 -34
- 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__/runtime-discovery.test.ts +6 -3
- package/src/__tests__/runtime-models.test.ts +53 -0
- package/src/__tests__/skill-index.test.ts +89 -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/provision.ts +90 -12
- package/src/runtime-models.ts +47 -0
- package/src/skill-index.ts +103 -47
- 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,89 @@ 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 agentHermes = hermesSkillRoot(agentId, opts.hermesProfile);
|
|
78
|
+
|
|
79
|
+
const dirs: SkillRoot[] = [];
|
|
80
|
+
switch (runtimeFamily(opts.runtime)) {
|
|
81
|
+
case "codex":
|
|
82
|
+
dirs.push(agentCodex);
|
|
83
|
+
if (includeGlobal) {
|
|
84
|
+
dirs.push({
|
|
85
|
+
dir: path.join(homedir(), ".codex", "skills"),
|
|
86
|
+
source: "global-codex",
|
|
87
|
+
runtime: "codex",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case "hermes":
|
|
92
|
+
dirs.push(agentHermes);
|
|
93
|
+
break;
|
|
94
|
+
case "claude":
|
|
95
|
+
dirs.push(agentClaude);
|
|
96
|
+
if (includeGlobal) {
|
|
97
|
+
dirs.push({
|
|
98
|
+
dir: path.join(homedir(), ".claude", "skills"),
|
|
99
|
+
source: "global-claude",
|
|
100
|
+
runtime: "claude-code",
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
case "other":
|
|
105
|
+
break;
|
|
71
106
|
}
|
|
72
107
|
|
|
73
108
|
const envDirs = parseSkillDirsEnv(process.env.BOTCORD_SKILL_DIRS);
|
|
74
109
|
for (const dir of [...envDirs, ...(opts.extraDirs ?? [])]) {
|
|
75
|
-
dirs.push({
|
|
110
|
+
dirs.push({
|
|
111
|
+
dir,
|
|
112
|
+
source: "external",
|
|
113
|
+
...(opts.runtime ? { runtime: opts.runtime } : {}),
|
|
114
|
+
...(opts.hermesProfile ? { profile: opts.hermesProfile } : {}),
|
|
115
|
+
});
|
|
76
116
|
}
|
|
77
117
|
|
|
78
118
|
return dedupeDirs(expandSkillRoots(dirs));
|
|
@@ -114,6 +154,8 @@ export function scanSoftSkills(
|
|
|
114
154
|
name: parsed.name,
|
|
115
155
|
path: skillMd,
|
|
116
156
|
source: root.source,
|
|
157
|
+
...(root.runtime ? { runtime: root.runtime } : {}),
|
|
158
|
+
...(root.profile ? { profile: root.profile } : {}),
|
|
117
159
|
description: parsed.description,
|
|
118
160
|
mtimeMs: st.mtimeMs,
|
|
119
161
|
};
|
|
@@ -133,9 +175,14 @@ export function collectAgentSkillSnapshot(
|
|
|
133
175
|
): AgentSkillSnapshot {
|
|
134
176
|
return {
|
|
135
177
|
agentId,
|
|
178
|
+
...(opts.runtime ? { runtime: opts.runtime } : {}),
|
|
136
179
|
skills: scanSoftSkills(agentId, opts).map((skill) => ({
|
|
137
180
|
name: skill.name,
|
|
138
|
-
source: skill.source
|
|
181
|
+
source: snapshotSource(skill.source),
|
|
182
|
+
sourceDetail: skill.source,
|
|
183
|
+
...(skill.runtime ? { runtime: skill.runtime } : {}),
|
|
184
|
+
path: skill.path,
|
|
185
|
+
...(skill.profile ? { profile: skill.profile } : {}),
|
|
139
186
|
...(skill.description ? { description: skill.description } : {}),
|
|
140
187
|
mtimeMs: skill.mtimeMs,
|
|
141
188
|
})),
|
|
@@ -217,68 +264,77 @@ function parseSkillDirsEnv(value: string | undefined): string[] {
|
|
|
217
264
|
}
|
|
218
265
|
|
|
219
266
|
function dedupeDirs(
|
|
220
|
-
dirs:
|
|
221
|
-
):
|
|
267
|
+
dirs: SkillRoot[],
|
|
268
|
+
): SkillRoot[] {
|
|
222
269
|
const seen = new Set<string>();
|
|
223
|
-
const out:
|
|
270
|
+
const out: SkillRoot[] = [];
|
|
224
271
|
for (const entry of dirs) {
|
|
225
272
|
const resolved = path.resolve(entry.dir);
|
|
226
273
|
if (seen.has(resolved)) continue;
|
|
227
274
|
seen.add(resolved);
|
|
228
|
-
out.push({ dir: resolved
|
|
275
|
+
out.push({ ...entry, dir: resolved });
|
|
229
276
|
}
|
|
230
277
|
return out;
|
|
231
278
|
}
|
|
232
279
|
|
|
233
|
-
function expandSkillRoots(
|
|
234
|
-
|
|
235
|
-
): Array<{ dir: string; source: string }> {
|
|
236
|
-
const out: Array<{ dir: string; source: string }> = [];
|
|
280
|
+
function expandSkillRoots(dirs: SkillRoot[]): SkillRoot[] {
|
|
281
|
+
const out: SkillRoot[] = [];
|
|
237
282
|
for (const entry of dirs) {
|
|
238
283
|
out.push(entry);
|
|
239
284
|
if (entry.source.includes("codex")) {
|
|
240
|
-
out.push({ dir: path.join(entry.dir, ".system")
|
|
285
|
+
out.push({ ...entry, dir: path.join(entry.dir, ".system") });
|
|
241
286
|
}
|
|
242
287
|
}
|
|
243
288
|
return out;
|
|
244
289
|
}
|
|
245
290
|
|
|
246
|
-
function
|
|
291
|
+
function hermesSkillRoot(agentId: string, profile: string | undefined): SkillRoot {
|
|
292
|
+
if (profile) {
|
|
293
|
+
try {
|
|
294
|
+
return {
|
|
295
|
+
dir: path.join(hermesProfileHomeDir(profile), "skills"),
|
|
296
|
+
source: "agent-hermes-profile",
|
|
297
|
+
runtime: "hermes-agent",
|
|
298
|
+
profile,
|
|
299
|
+
};
|
|
300
|
+
} catch {
|
|
301
|
+
// Corrupt legacy credentials should not make the whole skill snapshot fail.
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
dir: path.join(agentHermesHomeDir(agentId), "skills"),
|
|
306
|
+
source: "agent-hermes",
|
|
307
|
+
runtime: "hermes-agent",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function runtimeFamily(runtime: string | undefined): "codex" | "claude" | "hermes" | "other" {
|
|
247
312
|
if (runtime === "codex") return "codex";
|
|
313
|
+
if (runtime === "hermes-agent") return "hermes";
|
|
314
|
+
if (!runtime) return "claude";
|
|
248
315
|
if (runtime === "claude-code") return "claude";
|
|
249
316
|
return "other";
|
|
250
317
|
}
|
|
251
318
|
|
|
252
|
-
function priority(source: string,
|
|
253
|
-
if (runtimeFamily(runtime) === "codex") {
|
|
254
|
-
switch (source) {
|
|
255
|
-
case "agent-codex":
|
|
256
|
-
return 0;
|
|
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
|
-
}
|
|
267
|
-
|
|
319
|
+
function priority(source: string, _runtime: string | undefined): number {
|
|
268
320
|
switch (source) {
|
|
269
321
|
case "agent-claude":
|
|
270
|
-
return 0;
|
|
271
322
|
case "agent-codex":
|
|
272
|
-
|
|
323
|
+
case "agent-hermes":
|
|
324
|
+
case "agent-hermes-profile":
|
|
325
|
+
return 0;
|
|
273
326
|
case "global-claude":
|
|
274
|
-
return 2;
|
|
275
327
|
case "global-codex":
|
|
276
|
-
return
|
|
328
|
+
return 1;
|
|
277
329
|
default:
|
|
278
|
-
return
|
|
330
|
+
return 2;
|
|
279
331
|
}
|
|
280
332
|
}
|
|
281
333
|
|
|
334
|
+
function snapshotSource(source: string): "workspace" | "runtime-global" {
|
|
335
|
+
return source.startsWith("agent-") ? "workspace" : "runtime-global";
|
|
336
|
+
}
|
|
337
|
+
|
|
282
338
|
function unquote(value: string): string {
|
|
283
339
|
const trimmed = value.trim();
|
|
284
340
|
if (
|