@gt-fe/eap-runtime 0.0.8 → 0.0.11
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/README.md +15 -20
- package/dist/api/handlers/invoke.handler.js +7 -3
- package/dist/api/handlers/messages.handler.js +0 -1
- package/dist/api/handlers/stream.handler.js +8 -4
- package/dist/api/routes/agent.routes.d.ts +2 -2
- package/dist/api/routes/agent.routes.js +2 -2
- package/dist/checkpoint/checkpoint-ref-notify.d.ts +10 -0
- package/dist/checkpoint/checkpoint-ref-notify.js +59 -0
- package/dist/checkpoint/index.d.ts +1 -0
- package/dist/checkpoint/index.js +1 -0
- package/dist/checkpoint/pg-checkpoint-saver.js +25 -2
- package/dist/common/agent-code.d.ts +2 -4
- package/dist/common/agent-code.js +4 -5
- package/dist/common/types.d.ts +5 -5
- package/dist/common/types.js +2 -2
- package/dist/contracts/permission-checker.d.ts +1 -1
- package/dist/contracts/trace-collector.d.ts +16 -2
- package/dist/debug/llm-turn-log.d.ts +100 -0
- package/dist/debug/llm-turn-log.js +130 -0
- package/dist/debug/pg-llm-turn-log.d.ts +22 -0
- package/dist/debug/pg-llm-turn-log.js +57 -0
- package/dist/governance/governance-client.d.ts +1 -1
- package/dist/governance/governance-client.js +40 -16
- package/dist/governance/index.d.ts +2 -2
- package/dist/governance/index.js +1 -1
- package/dist/governance/permission-guard.d.ts +2 -1
- package/dist/governance/permission-guard.js +13 -4
- package/dist/graph/adapters/langgraph-checkpointer.js +3 -1
- package/dist/graph/adapters/langgraph.adapter.d.ts +1 -0
- package/dist/graph/adapters/langgraph.adapter.js +153 -92
- package/dist/graph/adapters/skill-read.d.ts +12 -0
- package/dist/graph/adapters/skill-read.js +63 -0
- package/dist/graph/adapters/subgraph-compiler.js +5 -0
- package/dist/graph/contracts/executable-graph.d.ts +11 -9
- package/dist/graph/contracts/executable-graph.js +1 -1
- package/dist/graph/hitl/hitl-handler.d.ts +10 -0
- package/dist/graph/hitl/hitl-handler.js +50 -6
- package/dist/graph/nodes/llm-node.d.ts +14 -0
- package/dist/graph/nodes/skill-bind-node.js +1 -2
- package/dist/graph/nodes/tool-node.d.ts +2 -0
- package/dist/graph/nodes/tool-node.js +50 -10
- package/dist/graph/trace-span.d.ts +22 -0
- package/dist/graph/trace-span.js +69 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/memory/compression/compression.repository.d.ts +1 -15
- package/dist/providers/echo-llm-provider.d.ts +1 -1
- package/dist/providers/echo-llm-provider.js +4 -3
- package/dist/providers/http-llm-provider.d.ts +4 -0
- package/dist/providers/http-llm-provider.js +129 -4
- package/dist/providers/local-llm-provider.d.ts +5 -1
- package/dist/providers/local-llm-provider.js +14 -6
- package/dist/providers/routing-llm-provider.d.ts +4 -0
- package/dist/providers/routing-llm-provider.js +12 -2
- package/dist/registry/agent-models.d.ts +1 -1
- package/dist/registry/agent-models.js +1 -1
- package/dist/registry/agent-registry-client.d.ts +3 -3
- package/dist/registry/deployment-snapshot.d.ts +17 -5
- package/dist/registry/deployment-snapshot.js +97 -49
- package/dist/registry/graph-loader.d.ts +2 -2
- package/dist/registry/graph-loader.js +43 -80
- package/dist/registry/index.d.ts +2 -2
- package/dist/registry/index.js +2 -2
- package/dist/registry/preload-errors.d.ts +1 -1
- package/dist/registry/preload-errors.js +1 -1
- package/dist/registry/skill-io-guard.js +1 -1
- package/dist/registry/skill-tree.d.ts +3 -0
- package/dist/registry/skill-tree.js +41 -3
- package/dist/runtime/agent-runtime.d.ts +42 -3
- package/dist/runtime/agent-runtime.js +129 -39
- package/dist/runtime/dev-runtime.d.ts +7 -4
- package/dist/runtime/dev-runtime.js +24 -21
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/storage-profile.d.ts +19 -10
- package/dist/runtime/storage-profile.js +42 -29
- package/dist/runtime/types.d.ts +17 -19
- package/dist/server.js +2 -2
- package/dist/session/session.service.d.ts +5 -0
- package/dist/session/session.service.js +12 -0
- package/dist/sse/events/index.d.ts +5 -3
- package/dist/sse/events/index.js +2 -0
- package/dist/sse/events/skill-events.d.ts +12 -1
- package/dist/sse/events/skill-events.js +1 -1
- package/dist/sse/trace-collector.d.ts +10 -0
- package/dist/sse/trace-collector.js +1 -0
- package/dist/token/token-budget.service.d.ts +2 -2
- package/dist/token/token-budget.service.js +1 -1
- package/dist/tool/create-tool-executor.d.ts +1 -1
- package/dist/tool/create-tool-executor.js +3 -2
- package/dist/tool/dev-http-executor.d.ts +1 -1
- package/dist/tool/dev-http-executor.js +10 -7
- package/dist/tool/dev-mcp-executor.js +5 -3
- package/dist/tool/dev-tool-executor.d.ts +1 -1
- package/dist/tool/dev-tool-executor.js +2 -2
- package/dist/tool/harness-command.d.ts +32 -0
- package/dist/tool/harness-command.js +276 -0
- package/dist/tool/harness-primitives.d.ts +54 -0
- package/dist/tool/harness-primitives.js +492 -0
- package/dist/tool/http-tool-executor.js +16 -21
- package/dist/tool/index.d.ts +4 -2
- package/dist/tool/index.js +4 -2
- package/dist/tool/local-mcp-client.d.ts +1 -1
- package/dist/tool/local-mcp-client.js +54 -23
- package/dist/tool/local-tool-executor.d.ts +4 -4
- package/dist/tool/local-tool-executor.js +18 -16
- package/dist/tool/mcp-tool-executor.js +23 -7
- package/dist/tool/skill-script-refs.d.ts +20 -0
- package/dist/tool/skill-script-refs.js +62 -0
- package/dist/tool/system-prompt-builder.d.ts +61 -25
- package/dist/tool/system-prompt-builder.js +198 -92
- package/dist/tool/timeout.d.ts +14 -0
- package/dist/tool/timeout.js +36 -0
- package/dist/tool/tool-confirmation.js +2 -1
- package/dist/tool/tool-execution-router.d.ts +1 -1
- package/dist/tool/tool-execution-router.js +2 -2
- package/dist/tool/tool-executor.interface.d.ts +23 -7
- package/dist/tool/tool-orchestrator.d.ts +1 -1
- package/dist/tool/tool-orchestrator.js +6 -3
- package/dist/utils/format-error.d.ts +2 -2
- package/dist/utils/format-error.js +2 -2
- package/dist/utils/http-error.d.ts +2 -2
- package/dist/utils/http-error.js +2 -2
- package/package.json +3 -3
- package/dist/common/concurrency.d.ts +0 -79
- package/dist/common/concurrency.js +0 -121
- package/dist/common/queue-consumer.d.ts +0 -125
- package/dist/common/queue-consumer.js +0 -159
- package/dist/tool/mock-tool-executor.d.ts +0 -28
- package/dist/tool/mock-tool-executor.js +0 -65
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
* {root}/agents/<agentCode>/<version>/users/<userId>/skills/<skillCode>/
|
|
8
8
|
*
|
|
9
9
|
* 命名:agentCode / toolsetCode / skillCode / toolName 均为语义化小写标识;
|
|
10
|
-
* Skill
|
|
10
|
+
* Skill 目录无版本层:包内必含 SKILL.md(Agent Skills)。
|
|
11
11
|
*/
|
|
12
12
|
import { readdir, readFile, access } from 'node:fs/promises';
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { constants as fsConstants } from 'node:fs';
|
|
16
|
+
import { parseSkillMd } from '@eap/contracts';
|
|
17
|
+
import { findSkillEntryFile } from './skill-tree.js';
|
|
16
18
|
import { preloadMissing, preloadPackageCorrupt, } from './preload-errors.js';
|
|
17
19
|
import { isRequireChecksum, resolvePreloadBehaviorFlags, } from './preload-flags.js';
|
|
18
20
|
async function pathExists(p) {
|
|
@@ -138,29 +140,51 @@ async function pickLatestVersionDir(parent) {
|
|
|
138
140
|
dirs.sort();
|
|
139
141
|
return path.join(parent, dirs[dirs.length - 1]);
|
|
140
142
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
function asArray(value) {
|
|
144
|
+
return Array.isArray(value) ? value : [];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Agent 清单装配读取:现行 `skills`,兼容 CLI `skillRefs`。
|
|
148
|
+
* 项身份:`code` / `skill` / `skillId`。两边都有时现行字段先写入;同名只补 version/name 等空位。
|
|
149
|
+
*/
|
|
150
|
+
export function skillRefsFromManifest(manifest) {
|
|
145
151
|
const out = [];
|
|
146
|
-
|
|
152
|
+
const byId = new Map();
|
|
153
|
+
const upsert = (ref) => {
|
|
154
|
+
const prev = byId.get(ref.skillId);
|
|
155
|
+
if (!prev) {
|
|
156
|
+
byId.set(ref.skillId, ref);
|
|
157
|
+
out.push(ref);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!prev.version && ref.version)
|
|
161
|
+
prev.version = ref.version;
|
|
162
|
+
if (!prev.name && ref.name)
|
|
163
|
+
prev.name = ref.name;
|
|
164
|
+
if (!prev.description && ref.description)
|
|
165
|
+
prev.description = ref.description;
|
|
166
|
+
if (!prev.sha256 && ref.sha256)
|
|
167
|
+
prev.sha256 = ref.sha256;
|
|
168
|
+
};
|
|
169
|
+
for (const item of [...asArray(manifest.skills), ...asArray(manifest.skillRefs)]) {
|
|
147
170
|
if (typeof item === 'string') {
|
|
148
|
-
|
|
171
|
+
if (item)
|
|
172
|
+
upsert({ skillId: item });
|
|
149
173
|
continue;
|
|
150
174
|
}
|
|
151
|
-
if (item
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
175
|
+
if (!item || typeof item !== 'object')
|
|
176
|
+
continue;
|
|
177
|
+
const o = item;
|
|
178
|
+
const skillId = String(o.code ?? o.skill ?? o.skillId ?? '');
|
|
179
|
+
if (!skillId)
|
|
180
|
+
continue;
|
|
181
|
+
upsert({
|
|
182
|
+
skillId,
|
|
183
|
+
name: o.name != null ? String(o.name) : undefined,
|
|
184
|
+
version: o.version != null ? String(o.version) : undefined,
|
|
185
|
+
description: o.description != null ? String(o.description) : undefined,
|
|
186
|
+
sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
|
|
187
|
+
});
|
|
164
188
|
}
|
|
165
189
|
return out;
|
|
166
190
|
}
|
|
@@ -171,8 +195,8 @@ function parseStringList(value) {
|
|
|
171
195
|
return out.length > 0 ? out : undefined;
|
|
172
196
|
}
|
|
173
197
|
/**
|
|
174
|
-
*
|
|
175
|
-
* 含 type/execution 的视为内联定义;仅 toolset/
|
|
198
|
+
* 装配引用 vs 内联完整 ToolManifest。
|
|
199
|
+
* 含 type/execution 的视为内联定义;仅 code/toolset/version/enabled 等视为引用。
|
|
176
200
|
*/
|
|
177
201
|
export function isInlineToolDeclaration(item) {
|
|
178
202
|
if (!item || typeof item !== 'object' || Array.isArray(item))
|
|
@@ -189,7 +213,7 @@ function parseToolAssemblyRef(item) {
|
|
|
189
213
|
if (isInlineToolDeclaration(item))
|
|
190
214
|
return null;
|
|
191
215
|
const o = item;
|
|
192
|
-
const name = String(o.
|
|
216
|
+
const name = String(o.code ?? o.toolset ?? '');
|
|
193
217
|
if (!name)
|
|
194
218
|
return null;
|
|
195
219
|
return {
|
|
@@ -197,14 +221,17 @@ function parseToolAssemblyRef(item) {
|
|
|
197
221
|
toolId: o.toolId != null ? String(o.toolId) : undefined,
|
|
198
222
|
version: o.version != null ? String(o.version) : undefined,
|
|
199
223
|
sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
|
|
200
|
-
enabledTools: parseStringList(o.enabledTools),
|
|
224
|
+
enabledTools: parseStringList(o.enabled) ?? parseStringList(o.enabledTools),
|
|
201
225
|
autoApprove: parseStringList(o.autoApprove),
|
|
202
226
|
};
|
|
203
227
|
}
|
|
204
228
|
/**
|
|
205
|
-
* 从
|
|
229
|
+
* 从 Agent 清单收集工具集装配引用。
|
|
230
|
+
* 现行 `toolsets`;兼容 CLI `toolRefs` 与更旧的 `tools`(内联完整 manifest 会跳过)。
|
|
231
|
+
* 项身份:`code` / `toolset`(字符串项即 code)。不用展示名 `name`。白名单:`enabled` / `enabledTools`。
|
|
232
|
+
* 两边都有时现行字段先写入;同名条目的 enabled/autoApprove 以先写入为准。
|
|
206
233
|
*/
|
|
207
|
-
function
|
|
234
|
+
export function toolsetsFromManifest(manifest) {
|
|
208
235
|
const out = [];
|
|
209
236
|
const byName = new Map();
|
|
210
237
|
const upsert = (ref) => {
|
|
@@ -214,11 +241,6 @@ function toolRefsFromManifest(manifest) {
|
|
|
214
241
|
out.push(ref);
|
|
215
242
|
return;
|
|
216
243
|
}
|
|
217
|
-
// 后写补全白名单等字段,不覆盖已有显式值
|
|
218
|
-
if (!prev.enabledTools && ref.enabledTools)
|
|
219
|
-
prev.enabledTools = ref.enabledTools;
|
|
220
|
-
if (!prev.autoApprove && ref.autoApprove)
|
|
221
|
-
prev.autoApprove = ref.autoApprove;
|
|
222
244
|
if (!prev.version && ref.version)
|
|
223
245
|
prev.version = ref.version;
|
|
224
246
|
if (!prev.sha256 && ref.sha256)
|
|
@@ -226,12 +248,11 @@ function toolRefsFromManifest(manifest) {
|
|
|
226
248
|
if (!prev.toolId && ref.toolId)
|
|
227
249
|
prev.toolId = ref.toolId;
|
|
228
250
|
};
|
|
229
|
-
for (const item of
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
for (const item of Array.isArray(manifest.tools) ? manifest.tools : []) {
|
|
251
|
+
for (const item of [
|
|
252
|
+
...asArray(manifest.toolsets),
|
|
253
|
+
...asArray(manifest.toolRefs),
|
|
254
|
+
...asArray(manifest.tools),
|
|
255
|
+
]) {
|
|
235
256
|
const ref = parseToolAssemblyRef(item);
|
|
236
257
|
if (ref)
|
|
237
258
|
upsert(ref);
|
|
@@ -239,12 +260,12 @@ function toolRefsFromManifest(manifest) {
|
|
|
239
260
|
return out;
|
|
240
261
|
}
|
|
241
262
|
/**
|
|
242
|
-
* 将 agent.manifest
|
|
263
|
+
* 将 agent.manifest 装配项上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
|
|
243
264
|
*/
|
|
244
265
|
export function overlayToolRefPolicies(snapTools, manifest) {
|
|
245
266
|
if (!manifest)
|
|
246
267
|
return snapTools;
|
|
247
|
-
const fromManifest =
|
|
268
|
+
const fromManifest = toolsetsFromManifest(manifest);
|
|
248
269
|
if (fromManifest.length === 0)
|
|
249
270
|
return snapTools;
|
|
250
271
|
const byName = new Map(fromManifest.map((r) => [r.name, r]));
|
|
@@ -259,6 +280,12 @@ export function overlayToolRefPolicies(snapTools, manifest) {
|
|
|
259
280
|
};
|
|
260
281
|
});
|
|
261
282
|
}
|
|
283
|
+
function nonemptyRefs(refs) {
|
|
284
|
+
return refs && refs.length > 0 ? refs : undefined;
|
|
285
|
+
}
|
|
286
|
+
function nonemptySkillRefs(refs) {
|
|
287
|
+
return refs && refs.length > 0 ? refs : undefined;
|
|
288
|
+
}
|
|
262
289
|
function normalizeSnapshotToolRefs(raw) {
|
|
263
290
|
if (!Array.isArray(raw))
|
|
264
291
|
return undefined;
|
|
@@ -281,7 +308,7 @@ function normalizeSnapshotSkillRefs(raw) {
|
|
|
281
308
|
}
|
|
282
309
|
if (item && typeof item === 'object') {
|
|
283
310
|
const o = item;
|
|
284
|
-
const skillId = String(o.
|
|
311
|
+
const skillId = String(o.code ?? o.skillId ?? '');
|
|
285
312
|
if (!skillId)
|
|
286
313
|
continue;
|
|
287
314
|
out.push({
|
|
@@ -417,8 +444,8 @@ export class FileSystemDeploymentSnapshot {
|
|
|
417
444
|
return {
|
|
418
445
|
agentCode,
|
|
419
446
|
version: String(snap.version ?? resolvedVersion),
|
|
420
|
-
tools: normalizeSnapshotToolRefs(snap.tools) ??
|
|
421
|
-
skills: normalizeSnapshotSkillRefs(snap.skills) ?? skillRefsFromManifest(manifest ?? {}),
|
|
447
|
+
tools: nonemptyRefs(normalizeSnapshotToolRefs(snap.tools)) ?? toolsetsFromManifest(manifest ?? {}),
|
|
448
|
+
skills: nonemptySkillRefs(normalizeSnapshotSkillRefs(snap.skills)) ?? skillRefsFromManifest(manifest ?? {}),
|
|
422
449
|
graph,
|
|
423
450
|
agentDir,
|
|
424
451
|
manifest: manifest ?? undefined,
|
|
@@ -428,7 +455,7 @@ export class FileSystemDeploymentSnapshot {
|
|
|
428
455
|
return {
|
|
429
456
|
agentCode,
|
|
430
457
|
version: resolvedVersion,
|
|
431
|
-
tools:
|
|
458
|
+
tools: toolsetsFromManifest(manifest ?? {}),
|
|
432
459
|
skills: skillRefsFromManifest(manifest ?? {}),
|
|
433
460
|
graph,
|
|
434
461
|
agentDir,
|
|
@@ -497,10 +524,9 @@ export class FileSystemDeploymentSnapshot {
|
|
|
497
524
|
if (!(await pathExists(bundlePath)))
|
|
498
525
|
continue;
|
|
499
526
|
await this.assertReadyIfRequired(bundlePath, `skill ${ref.skillId}`);
|
|
527
|
+
const entryFile = await findSkillEntryFile(bundlePath);
|
|
500
528
|
const manifestPathCandidates = [
|
|
501
529
|
path.join(bundlePath, 'skill.manifest.json'),
|
|
502
|
-
path.join(bundlePath, 'skill.definition.json'),
|
|
503
|
-
path.join(bundlePath, 'manifest.json'),
|
|
504
530
|
];
|
|
505
531
|
let manifest = null;
|
|
506
532
|
let manifestPath = null;
|
|
@@ -512,22 +538,44 @@ export class FileSystemDeploymentSnapshot {
|
|
|
512
538
|
break;
|
|
513
539
|
}
|
|
514
540
|
}
|
|
541
|
+
if (!manifest && entryFile) {
|
|
542
|
+
const parsed = parseSkillMd(await readFile(entryFile, 'utf8'));
|
|
543
|
+
if (!parsed)
|
|
544
|
+
continue;
|
|
545
|
+
manifest = {
|
|
546
|
+
code: parsed.frontmatter.name,
|
|
547
|
+
name: parsed.frontmatter.name,
|
|
548
|
+
description: parsed.frontmatter.description,
|
|
549
|
+
...(parsed.frontmatter.license ? { license: parsed.frontmatter.license } : {}),
|
|
550
|
+
};
|
|
551
|
+
manifestPath = entryFile;
|
|
552
|
+
}
|
|
515
553
|
if (!manifest || !manifestPath)
|
|
516
554
|
continue;
|
|
517
|
-
|
|
555
|
+
if (!manifest.description && entryFile) {
|
|
556
|
+
const parsed = parseSkillMd(await readFile(entryFile, 'utf8'));
|
|
557
|
+
if (parsed?.frontmatter.description) {
|
|
558
|
+
manifest = { ...manifest, description: parsed.frontmatter.description };
|
|
559
|
+
if (!manifest.name)
|
|
560
|
+
manifest.name = parsed.frontmatter.name;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
518
563
|
const isUserOverridePath = bundlePath.includes('/users/') || bundlePath.includes('\\users\\');
|
|
519
564
|
const isAuthorOverlay = extraRoots.some((root) => root && isPathInside(root, bundlePath));
|
|
520
|
-
if (ref.sha256 && !isUserOverridePath && !isAuthorOverlay) {
|
|
565
|
+
if (ref.sha256 && !isUserOverridePath && !isAuthorOverlay && manifestPath.endsWith('.json')) {
|
|
521
566
|
const actual = await sha256OfFile(manifestPath);
|
|
522
567
|
await assertDigestMatch(ref.sha256, actual, `skill ${ref.skillId}`, { path: manifestPath });
|
|
523
568
|
}
|
|
524
|
-
const skillId = String(manifest.code ??
|
|
569
|
+
const skillId = String(manifest.code ?? ref.skillId);
|
|
525
570
|
return {
|
|
526
571
|
skillId,
|
|
527
572
|
name: String(manifest.name ?? ref.name ?? skillId),
|
|
528
573
|
version: String(manifest.version ?? ref.version ?? path.basename(bundlePath)),
|
|
529
574
|
description: manifest.description ?? ref.description,
|
|
530
|
-
manifest
|
|
575
|
+
manifest: {
|
|
576
|
+
...manifest,
|
|
577
|
+
...(entryFile ? { skillEntryFile: entryFile } : {}),
|
|
578
|
+
},
|
|
531
579
|
bundlePath,
|
|
532
580
|
};
|
|
533
581
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { GraphDSL } from '../graph/contracts/executable-graph.js';
|
|
8
8
|
import type { AgentRegistryClient } from './agent-registry-client.js';
|
|
9
9
|
import type { DeploymentContext } from '../tool/tool-execution-router.js';
|
|
10
|
-
import type { ILocalToolInstallStore } from '@
|
|
10
|
+
import type { ILocalToolInstallStore } from '@eap/contracts';
|
|
11
11
|
import { type LoadedToolDefinition } from '../tool/loaded-tool-definition.js';
|
|
12
12
|
import type { LoadedSkillInfo } from '../tool/system-prompt-builder.js';
|
|
13
13
|
import { type IDeploymentSnapshot } from './deployment-snapshot.js';
|
|
@@ -111,7 +111,7 @@ export declare class GraphLoader {
|
|
|
111
111
|
loadToolDefinitions(agentCode: string, options?: LoadToolDefinitionsOptions): Promise<LoadedToolDefinition[]>;
|
|
112
112
|
private loadToolDefinitionsFromSource;
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
114
|
+
* 加载已装配 Skill:SKILL.md 目录(Agent Skills)或可选 skill.manifest.json。
|
|
115
115
|
* @param options.userId 用于解析 users/<userId>/skills(优先于 preinstall/skills)
|
|
116
116
|
* @param options.allowMissingSkills 缺失时跳过而非抛错(warm 预热用)
|
|
117
117
|
*/
|
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readFile } from 'node:fs/promises';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
-
import { resolveAgentModelAllowlist,
|
|
9
|
+
import { resolveAgentModelAllowlist, resolveAgentDefaultModel } from './agent-models.js';
|
|
10
|
+
import { DEFAULT_HTTP_TOOL_TIMEOUT_SEC, DEFAULT_TOOL_TIMEOUT_SEC } from '../tool/timeout.js';
|
|
10
11
|
import { createDeploymentSnapshotFromEnv, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
11
12
|
import { preloadGraphNotFound, preloadManifestNotFound, preloadSkillNotFound, preloadToolNotFound, } from './preload-errors.js';
|
|
12
13
|
import { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, } from './definition-cache.js';
|
|
13
|
-
import { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, } from './skill-tree.js';
|
|
14
|
-
function
|
|
15
|
-
if (!
|
|
14
|
+
import { inspectAgentSkillTree, listSkillDirs, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, } from './skill-tree.js';
|
|
15
|
+
function applyDefaultModelToGraph(graph, defaultModel) {
|
|
16
|
+
if (!defaultModel)
|
|
16
17
|
return graph;
|
|
17
18
|
let changed = false;
|
|
18
19
|
const nodes = graph.nodes.map((node) => {
|
|
@@ -22,7 +23,7 @@ function applyPrimaryModelToGraph(graph, primary) {
|
|
|
22
23
|
if (current && current.toLowerCase() !== 'default')
|
|
23
24
|
return node;
|
|
24
25
|
changed = true;
|
|
25
|
-
return { ...node, config: { ...node.config, model:
|
|
26
|
+
return { ...node, config: { ...node.config, model: defaultModel } };
|
|
26
27
|
});
|
|
27
28
|
return changed ? { ...graph, nodes } : graph;
|
|
28
29
|
}
|
|
@@ -41,7 +42,7 @@ function assertGraphModelsAllowed(graph, manifest) {
|
|
|
41
42
|
return graph;
|
|
42
43
|
}
|
|
43
44
|
function finalizeLoadedGraph(graph, manifest) {
|
|
44
|
-
return assertGraphModelsAllowed(
|
|
45
|
+
return assertGraphModelsAllowed(applyDefaultModelToGraph(graph, resolveAgentDefaultModel((manifest ?? {}))), manifest);
|
|
45
46
|
}
|
|
46
47
|
function asGraphDsl(value) {
|
|
47
48
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
@@ -94,57 +95,8 @@ async function resolveSkillPrompt(manifest, bundlePath) {
|
|
|
94
95
|
}
|
|
95
96
|
return raw;
|
|
96
97
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* scripts 为可选/非标字段:Skill 包仅强制要求 skill.md,其余文件结构不限;
|
|
100
|
-
* 存在 scripts 声明时才物化为可调用的本地 Tool。
|
|
101
|
-
*/
|
|
102
|
-
function resolveSkillScripts(manifest, bundlePath) {
|
|
103
|
-
const scripts = manifest.scripts;
|
|
104
|
-
if (!Array.isArray(scripts))
|
|
105
|
-
return [];
|
|
106
|
-
const tools = [];
|
|
107
|
-
for (const script of scripts) {
|
|
108
|
-
if (!script || typeof script !== 'object')
|
|
109
|
-
continue;
|
|
110
|
-
const s = script;
|
|
111
|
-
const name = s.name;
|
|
112
|
-
const command = s.command;
|
|
113
|
-
if (!name || !command)
|
|
114
|
-
continue;
|
|
115
|
-
const args = Array.isArray(s.args) ? s.args.map(String) : [];
|
|
116
|
-
tools.push({
|
|
117
|
-
toolId: `script:${name}`,
|
|
118
|
-
name,
|
|
119
|
-
manifest: {
|
|
120
|
-
id: `script:${name}`,
|
|
121
|
-
name,
|
|
122
|
-
version: '0.0.0',
|
|
123
|
-
type: 'code',
|
|
124
|
-
status: 'active',
|
|
125
|
-
description: s.description ?? `Skill script: ${name}`,
|
|
126
|
-
execution: {
|
|
127
|
-
runtime: command === 'python3' || command === 'python' ? 'python'
|
|
128
|
-
: command === 'node' ? 'node'
|
|
129
|
-
: 'executable',
|
|
130
|
-
handler: args[0] ?? command,
|
|
131
|
-
args: args.slice(1),
|
|
132
|
-
timeout: 30000,
|
|
133
|
-
sandbox: false,
|
|
134
|
-
bundlePath,
|
|
135
|
-
command,
|
|
136
|
-
/** 标记为 Skill 虚拟脚本:Router 优先本机执行,不经 Gateway */
|
|
137
|
-
localPreferred: true,
|
|
138
|
-
source: 'skill-script',
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
inputSchema: { type: 'object', properties: {}, additionalProperties: true },
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
return tools;
|
|
145
|
-
}
|
|
146
|
-
function extractSkillToolRefs(manifest) {
|
|
147
|
-
const refs = manifest.toolRefs ?? manifest.tools;
|
|
98
|
+
function extractSkillToolsets(manifest) {
|
|
99
|
+
const refs = manifest.toolsets;
|
|
148
100
|
if (!Array.isArray(refs))
|
|
149
101
|
return undefined;
|
|
150
102
|
const out = [];
|
|
@@ -156,14 +108,15 @@ function extractSkillToolRefs(manifest) {
|
|
|
156
108
|
if (!item || typeof item !== 'object')
|
|
157
109
|
continue;
|
|
158
110
|
const o = item;
|
|
111
|
+
const code = o.code != null ? String(o.code) : undefined;
|
|
112
|
+
const enabled = Array.isArray(o.enabled)
|
|
113
|
+
? o.enabled.filter((x) => typeof x === 'string')
|
|
114
|
+
: undefined;
|
|
159
115
|
out.push({
|
|
160
|
-
|
|
161
|
-
name: o.name != null ? String(o.name) : o.toolset != null ? String(o.toolset) : undefined,
|
|
116
|
+
name: o.name != null ? String(o.name) : code,
|
|
162
117
|
version: o.version != null ? String(o.version) : undefined,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
? o.enabledTools.filter((x) => typeof x === 'string')
|
|
166
|
-
: undefined,
|
|
118
|
+
code,
|
|
119
|
+
enabled,
|
|
167
120
|
autoApprove: Array.isArray(o.autoApprove)
|
|
168
121
|
? o.autoApprove.filter((x) => typeof x === 'string')
|
|
169
122
|
: undefined,
|
|
@@ -305,7 +258,7 @@ function fromPreinstallTool(pre) {
|
|
|
305
258
|
* 以工具集为管理单元:单个 MCP 服务 / 单个代码包 = 一个工具集,可含多个子工具;
|
|
306
259
|
* 子工具继承集级 server/package 配置,合成各自的 execution。
|
|
307
260
|
* 无 tools[] 时回退为单工具 manifest(tool.manifest.json 结构)。
|
|
308
|
-
*
|
|
261
|
+
* enabled 为可选白名单(agent.manifest toolsets[].enabled);缺省启用全部子工具。
|
|
309
262
|
*/
|
|
310
263
|
function expandPreinstallToolset(pre, options) {
|
|
311
264
|
const m = pre.manifest;
|
|
@@ -348,7 +301,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
348
301
|
baseUrl: st.baseUrl ?? gateway.baseUrl,
|
|
349
302
|
pathTemplate: st.pathTemplate,
|
|
350
303
|
allowedHosts: gateway.allowedHosts,
|
|
351
|
-
timeout: st.timeout ?? gateway.timeout ??
|
|
304
|
+
timeout: st.timeout ?? gateway.timeout ?? DEFAULT_HTTP_TOOL_TIMEOUT_SEC,
|
|
352
305
|
};
|
|
353
306
|
}
|
|
354
307
|
else if (setType === 'mcp') {
|
|
@@ -358,7 +311,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
358
311
|
transport: server?.transport ?? (server?.url ? 'streamable_http' : 'stdio'),
|
|
359
312
|
server,
|
|
360
313
|
toolName: name,
|
|
361
|
-
timeout: st.timeout ?? server?.timeout ??
|
|
314
|
+
timeout: st.timeout ?? server?.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
|
|
362
315
|
};
|
|
363
316
|
}
|
|
364
317
|
else {
|
|
@@ -367,7 +320,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
367
320
|
runtime: st.runtime ?? 'node',
|
|
368
321
|
handler: st.handler,
|
|
369
322
|
args: st.args,
|
|
370
|
-
timeout: st.timeout ??
|
|
323
|
+
timeout: st.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
|
|
371
324
|
sandbox: st.sandbox ?? pkg?.sandbox ?? false,
|
|
372
325
|
bundlePath: pre.bundlePath,
|
|
373
326
|
};
|
|
@@ -659,7 +612,7 @@ export class GraphLoader {
|
|
|
659
612
|
if (graphFromManifest && typeof graphFromManifest === 'object') {
|
|
660
613
|
return finalizeLoadedGraph(yamlGraphToDsl(agentCode, graphFromManifest), manifest);
|
|
661
614
|
}
|
|
662
|
-
const model =
|
|
615
|
+
const model = resolveAgentDefaultModel(manifest) ?? 'default';
|
|
663
616
|
return {
|
|
664
617
|
...DEFAULT_GRAPH_DSL,
|
|
665
618
|
name: agentCode,
|
|
@@ -851,7 +804,7 @@ export class GraphLoader {
|
|
|
851
804
|
return definitions;
|
|
852
805
|
}
|
|
853
806
|
/**
|
|
854
|
-
*
|
|
807
|
+
* 加载已装配 Skill:SKILL.md 目录(Agent Skills)或可选 skill.manifest.json。
|
|
855
808
|
* @param options.userId 用于解析 users/<userId>/skills(优先于 preinstall/skills)
|
|
856
809
|
* @param options.allowMissingSkills 缺失时跳过而非抛错(warm 预热用)
|
|
857
810
|
*/
|
|
@@ -887,10 +840,8 @@ export class GraphLoader {
|
|
|
887
840
|
const workflow = asGraphDsl(pre.manifest.workflow) ??
|
|
888
841
|
asGraphDsl(pre.manifest.graph) ??
|
|
889
842
|
asGraphDsl(pre.manifest.definitionSnapshot);
|
|
890
|
-
// 解析 prompt:支持文件路径引用(./ 开头)
|
|
891
843
|
const prompt = await resolveSkillPrompt(pre.manifest, pre.bundlePath);
|
|
892
|
-
|
|
893
|
-
const scriptTools = resolveSkillScripts(pre.manifest, pre.bundlePath);
|
|
844
|
+
const entryFile = typeof pre.manifest.skillEntryFile === 'string' ? pre.manifest.skillEntryFile : undefined;
|
|
894
845
|
skills.push({
|
|
895
846
|
skillId: pre.skillId,
|
|
896
847
|
name: pre.name,
|
|
@@ -898,10 +849,11 @@ export class GraphLoader {
|
|
|
898
849
|
version: pre.version,
|
|
899
850
|
workflow,
|
|
900
851
|
prompt,
|
|
901
|
-
|
|
852
|
+
bundlePath: pre.bundlePath,
|
|
853
|
+
entryFile,
|
|
854
|
+
toolsets: extractSkillToolsets(pre.manifest),
|
|
902
855
|
inputDef: pre.manifest.inputDef,
|
|
903
856
|
outputDef: pre.manifest.outputDef,
|
|
904
|
-
scriptTools: scriptTools.length > 0 ? scriptTools : undefined,
|
|
905
857
|
});
|
|
906
858
|
}
|
|
907
859
|
else if (!this.strictPreinstall) {
|
|
@@ -940,16 +892,25 @@ export class GraphLoader {
|
|
|
940
892
|
* 磁盘多出来的未声明目录不进选择清单;正文热加载仍看已装配目录的 mtime。
|
|
941
893
|
*/
|
|
942
894
|
async resolveSkillRefs(snap, agentDir, userId) {
|
|
895
|
+
const byId = new Map();
|
|
896
|
+
const add = (ref) => {
|
|
897
|
+
if (ref.skillId && !byId.has(ref.skillId))
|
|
898
|
+
byId.set(ref.skillId, ref);
|
|
899
|
+
};
|
|
943
900
|
if (agentDir) {
|
|
944
901
|
const assembly = await readSkillAssembly(agentDir, userId);
|
|
945
902
|
if (assembly && assembly.skills.length > 0) {
|
|
946
|
-
|
|
903
|
+
for (const skillId of assembly.skills)
|
|
904
|
+
add({ skillId });
|
|
947
905
|
}
|
|
948
906
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
907
|
+
if (byId.size === 0) {
|
|
908
|
+
for (const ref of snap?.skills ?? [])
|
|
909
|
+
add(ref);
|
|
910
|
+
}
|
|
911
|
+
for (const root of this.localSkillRoots()) {
|
|
912
|
+
for (const skillId of await listSkillDirs(root))
|
|
913
|
+
add({ skillId });
|
|
953
914
|
}
|
|
954
915
|
return [...byId.values()];
|
|
955
916
|
}
|
|
@@ -981,5 +942,7 @@ export class GraphLoader {
|
|
|
981
942
|
}
|
|
982
943
|
function resolveLocalSkillsDir(explicit) {
|
|
983
944
|
const candidate = explicit?.trim() || process.env.EAP_LOCAL_SKILLS_DIR?.trim();
|
|
984
|
-
|
|
945
|
+
if (candidate)
|
|
946
|
+
return path.resolve(candidate);
|
|
947
|
+
return path.resolve(process.cwd(), 'skills');
|
|
985
948
|
}
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { resolveAgentDefaultModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
|
|
2
2
|
export { createAgentRegistryClient, type AgentRegistryClient, type AgentRegistryRecord, type AgentManifest } from './agent-registry-client.js';
|
|
3
3
|
export { GraphLoader, type GraphLoaderConfig, type LoadToolDefinitionsOptions, type LoadAgentOptions } from './graph-loader.js';
|
|
4
4
|
export { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, type CachedAgentDefinitions, } from './definition-cache.js';
|
|
5
5
|
export { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, watchAgentSkillDirs, watchPreinstallSkillRoot, watchSkillRoots, } from './skill-tree.js';
|
|
6
|
-
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, type IDeploymentSnapshot, type AgentSnapshotMeta, type SnapshotToolRef, type SnapshotSkillRef, type PreinstallToolManifest, type PreinstallSkillManifest, type DeploymentSnapshotOptions, } from './deployment-snapshot.js';
|
|
6
|
+
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, toolsetsFromManifest, skillRefsFromManifest, type IDeploymentSnapshot, type AgentSnapshotMeta, type SnapshotToolRef, type SnapshotSkillRef, type PreinstallToolManifest, type PreinstallSkillManifest, type DeploymentSnapshotOptions, } from './deployment-snapshot.js';
|
|
7
7
|
export { preloadError, preloadMissing, preloadManifestNotFound, preloadGraphNotFound, preloadToolNotFound, preloadSkillNotFound, preloadPackageCorrupt, isRequireReady, } from './preload-errors.js';
|
|
8
8
|
export { resolvePreloadBehaviorFlags, isValidateSkillIo, isRequireChecksum, type PreloadBehaviorFlags, } from './preload-flags.js';
|
|
9
9
|
export { assertSkillIoIfEnabled, coerceSkillInputFromMessages, resolveSkillInputFromInvokeInput, } from './skill-io-guard.js';
|
package/dist/registry/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { resolveAgentDefaultModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
|
|
2
2
|
export { createAgentRegistryClient } from './agent-registry-client.js';
|
|
3
3
|
export { GraphLoader } from './graph-loader.js';
|
|
4
4
|
export { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, } from './definition-cache.js';
|
|
5
5
|
export { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, watchAgentSkillDirs, watchPreinstallSkillRoot, watchSkillRoots, } from './skill-tree.js';
|
|
6
|
-
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
6
|
+
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, toolsetsFromManifest, skillRefsFromManifest, } from './deployment-snapshot.js';
|
|
7
7
|
export { preloadError, preloadMissing, preloadManifestNotFound, preloadGraphNotFound, preloadToolNotFound, preloadSkillNotFound, preloadPackageCorrupt, isRequireReady, } from './preload-errors.js';
|
|
8
8
|
export { resolvePreloadBehaviorFlags, isValidateSkillIo, isRequireChecksum, } from './preload-flags.js';
|
|
9
9
|
export { assertSkillIoIfEnabled, coerceSkillInputFromMessages, resolveSkillInputFromInvokeInput, } from './skill-io-guard.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 预装加载错误 — 对齐 runtime.preload.* / 联调契约
|
|
3
3
|
*/
|
|
4
|
-
import { AppError, type ErrorCode } from '@
|
|
4
|
+
import { AppError, type ErrorCode } from '@eap/contracts';
|
|
5
5
|
export declare function preloadError(code: ErrorCode, message: string, details?: unknown): AppError;
|
|
6
6
|
export declare function preloadMissing(message: string, details?: unknown): AppError;
|
|
7
7
|
export declare function preloadManifestNotFound(message: string, details?: unknown): AppError;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 预装加载错误 — 对齐 runtime.preload.* / 联调契约
|
|
3
3
|
*/
|
|
4
|
-
import { AppError, ErrorCodes } from '@
|
|
4
|
+
import { AppError, ErrorCodes } from '@eap/contracts';
|
|
5
5
|
export function preloadError(code, message, details) {
|
|
6
6
|
return new AppError(code, message, {
|
|
7
7
|
exposeMessage: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Skill inputDef / outputDef 轻量校验(默认开启;EAP_PRELOAD_VALIDATE_SKILL_IO=0 关闭)
|
|
3
3
|
*/
|
|
4
|
-
import { AppError, ErrorCodes } from '@
|
|
4
|
+
import { AppError, ErrorCodes } from '@eap/contracts';
|
|
5
5
|
import { isValidateSkillIo } from './preload-flags.js';
|
|
6
6
|
function asRecord(value) {
|
|
7
7
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
@@ -3,6 +3,9 @@ export interface AgentSkillTree {
|
|
|
3
3
|
/** `${count}:${maxMtimeMs}`;增删改任一 skill 文件都会变 */
|
|
4
4
|
stamp: string;
|
|
5
5
|
}
|
|
6
|
+
/** Agent Skills 入口:目录内的 SKILL.md(规范名优先)。 */
|
|
7
|
+
export declare function findSkillEntryFile(bundlePath: string): Promise<string | null>;
|
|
8
|
+
export declare function listSkillDirs(root: string): Promise<string[]>;
|
|
6
9
|
export interface SkillAssembly {
|
|
7
10
|
skills: string[];
|
|
8
11
|
source: string;
|
|
@@ -10,6 +10,7 @@ import { readdir, stat, access, readFile } from 'node:fs/promises';
|
|
|
10
10
|
import { watch } from 'node:fs';
|
|
11
11
|
import { constants as fsConstants } from 'node:fs';
|
|
12
12
|
import path from 'node:path';
|
|
13
|
+
import { SKILL_ENTRY_CANDIDATES } from '@eap/contracts';
|
|
13
14
|
const SKILL_CODE = /^[a-z0-9][a-z0-9-]*$/;
|
|
14
15
|
async function exists(p) {
|
|
15
16
|
try {
|
|
@@ -20,6 +21,43 @@ async function exists(p) {
|
|
|
20
21
|
return false;
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
/** Agent Skills 入口:目录内的 SKILL.md(规范名优先)。 */
|
|
25
|
+
export async function findSkillEntryFile(bundlePath) {
|
|
26
|
+
for (const name of SKILL_ENTRY_CANDIDATES) {
|
|
27
|
+
const candidate = path.join(bundlePath, name);
|
|
28
|
+
if (await exists(candidate))
|
|
29
|
+
return candidate;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const files = await readdir(bundlePath);
|
|
33
|
+
const hit = files.find((file) => file.toLowerCase() === 'skill.md');
|
|
34
|
+
return hit ? path.join(bundlePath, hit) : null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function listSkillDirs(root) {
|
|
41
|
+
let names = [];
|
|
42
|
+
try {
|
|
43
|
+
names = await readdir(root);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const codes = [];
|
|
49
|
+
for (const name of names) {
|
|
50
|
+
if (!SKILL_CODE.test(name))
|
|
51
|
+
continue;
|
|
52
|
+
const bundle = path.join(root, name);
|
|
53
|
+
const info = await stat(bundle).catch(() => undefined);
|
|
54
|
+
if (!info?.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
if (await findSkillEntryFile(bundle))
|
|
57
|
+
codes.push(name);
|
|
58
|
+
}
|
|
59
|
+
return codes.sort();
|
|
60
|
+
}
|
|
23
61
|
async function maxMtime(filePath, fallback = 0) {
|
|
24
62
|
try {
|
|
25
63
|
const info = await stat(filePath);
|
|
@@ -101,9 +139,9 @@ export async function inspectAgentSkillTree(agentDir, userId, extraRoots = []) {
|
|
|
101
139
|
const bundleStat = await stat(bundle).catch(() => undefined);
|
|
102
140
|
if (!bundleStat?.isDirectory())
|
|
103
141
|
continue;
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (!
|
|
142
|
+
const hasEntry = await findSkillEntryFile(bundle);
|
|
143
|
+
const hasOverlay = await exists(path.join(bundle, 'skill.manifest.json'));
|
|
144
|
+
if (!hasEntry && !hasOverlay)
|
|
107
145
|
continue;
|
|
108
146
|
codes.add(name);
|
|
109
147
|
latest = Math.max(latest, bundleStat.mtimeMs);
|