attention-manifest-protocol 0.4.4 → 0.4.6
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/CHANGELOG.md +15 -0
- package/CHANGELOG.zh-CN.md +15 -0
- package/README.md +3 -1
- package/README.zh-CN.md +7 -3
- package/lib/context/workspaceService.d.ts +9 -0
- package/lib/context/workspaceService.js +9 -0
- package/lib/discover/kinds.d.ts +1 -1
- package/lib/discover/kinds.js +1 -1
- package/lib/discover/tree.js +121 -11
- package/lib/discover/types.d.ts +14 -1
- package/lib/global/service.d.ts +6 -0
- package/lib/global/service.js +3 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +3 -0
- package/lib/knowledge/index.d.ts +2 -0
- package/lib/knowledge/index.js +1 -0
- package/lib/knowledge/registry.d.ts +19 -0
- package/lib/knowledge/registry.js +39 -0
- package/lib/protocol/index.d.ts +1 -0
- package/lib/protocol/index.js +1 -0
- package/lib/protocol/registry.d.ts +20 -0
- package/lib/protocol/registry.js +46 -0
- package/lib/protocol/workspace.js +1 -1
- package/lib/registry/index.d.ts +2 -0
- package/lib/registry/index.js +1 -0
- package/lib/registry/memory.d.ts +17 -0
- package/lib/registry/memory.js +33 -0
- package/lib/skill/index.d.ts +2 -0
- package/lib/skill/index.js +1 -0
- package/lib/skill/registry.d.ts +20 -0
- package/lib/skill/registry.js +37 -0
- package/package.json +72 -72
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
|
|
6
6
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.6] - 2026-11-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Host-owned `SkillRegistry`, `KnowledgeRegistry` and `ProtocolRegistry` with validated registration, duplicate rejection, defensive copies and deterministic listing.
|
|
13
|
+
- Metadata-only `skills`, `knowledge` and `protocols` discovery scopes, with registry injection through workspace and global agent services. Disabled skills and protocols are excluded from discovery.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Share in-memory registry storage and query mechanics through `InMemoryRegistry` while keeping validation and list policies in each domain.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Reserve discovery node capacity for ancestors before visiting descendants so tight limits preserve tree structure and accurate summary counts.
|
|
22
|
+
|
|
8
23
|
## [Unreleased]
|
|
9
24
|
|
|
10
25
|
### Added
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循
|
|
6
6
|
[语义化版本](https://semver.org/lang/zh-CN/)。
|
|
7
7
|
|
|
8
|
+
## [0.4.6] - 2026-11-02
|
|
9
|
+
|
|
10
|
+
### 新增
|
|
11
|
+
|
|
12
|
+
- 宿主维护的 `SkillRegistry`、`KnowledgeRegistry` 与 `ProtocolRegistry`,支持登记校验、重复 ID 拒绝、防御性副本与稳定列表。
|
|
13
|
+
- 只返回元数据的 `skills`、`knowledge`、`protocols` 发现范围,并贯通 workspace/global agent 服务的注册中心注入;发现时排除禁用的 skill 与 protocol。
|
|
14
|
+
|
|
15
|
+
### 变更
|
|
16
|
+
|
|
17
|
+
- 通过 `InMemoryRegistry` 复用内存存储与查询机制,各领域保留独立校验和列表策略。
|
|
18
|
+
|
|
19
|
+
### 修复
|
|
20
|
+
|
|
21
|
+
- 发现树先为祖先预留节点容量,紧凑预算下仍保留树结构并准确统计节点。
|
|
22
|
+
|
|
8
23
|
## [未发布]
|
|
9
24
|
|
|
10
25
|
### 新增
|
package/README.md
CHANGED
|
@@ -53,7 +53,9 @@ Offline parsers live in `tools/support/`. The runtime stays database-free and us
|
|
|
53
53
|
|
|
54
54
|
### Discovery
|
|
55
55
|
|
|
56
|
-
`amp_tool_workspace_discover` returns one structural tree over
|
|
56
|
+
`amp_tool_workspace_discover` returns one structural tree over authorized projects, host components, skills, knowledge and protocols. File nodes carry a module kind (`service`, `tool`, `controller`, `route`, `repository`, `model`, `config`, `test`, `middleware`, `component`, `util`), an extension and bounded content matches. Hosts register projects and components through `HostCatalog`, reusable instructions through `SkillRegistry`, source-aware entries through `KnowledgeRegistry`, and protocol metadata through `ProtocolRegistry`. Discovery exposes skill/knowledge/protocol metadata only; full entries are fetched from their registries by ID. Discovery is read-only, never widens `projectIds`, and returns snippets as discovery evidence rather than as a Frame-allocated detail read.
|
|
57
|
+
|
|
58
|
+
These registries are domain-owned catalogs, not a mandate to duplicate every concept as a generic registry. Existing runtime state and policies for ability, cognition, progress and behavior should stay in their domain models; add a read-only catalog/discovery projection only when enumeration is needed. Agents should not write directly to active registries by default. A future contribution flow should create a sourced, versioned proposal and require host authorization, review and audit before activation.
|
|
57
59
|
|
|
58
60
|
## Quick start
|
|
59
61
|
|
package/README.zh-CN.md
CHANGED
|
@@ -38,7 +38,7 @@ Context 使用结构树和类型化关系图。项目依赖、导入、调用与
|
|
|
38
38
|
- MCP 执行、参数 Schema 校验、摘要固定与旧式握手回退,以及 A2A 发现与消息绑定。
|
|
39
39
|
- 项目树、项目依赖图、TS/JS 的部分静态导入/调用/引用图,以及知识库词法检索。
|
|
40
40
|
- Agent 工作区:`File`/`Directory` 树(指纹、字符集、bigint 行数/字节数、时间、描述/摘要/用途);分页读、CAS 原子写、按策略提取的大纲(代码/项目/文章/Office);import/export/dependency 图(Tarjan SCC、拓扑序、有界闭包);Session 身份与上下文隔离;`src/hook` 组合层;SQLite 实体与仓储。
|
|
41
|
-
- 宿主发现:以一棵结构树返回获准项目、内部模块(service/tool/controller/route/repository/model/config/test
|
|
41
|
+
- 宿主发现:以一棵结构树返回获准项目、内部模块(service/tool/controller/route/repository/model/config/test/...)、文件名、有界内容匹配,以及宿主注册的插件、服务、工具、skills 和 knowledge。项目节点带描述、用途与简介;skill/knowledge 节点只暴露元数据,详情由注册中心按 ID 查询。
|
|
42
42
|
- Markdown、TXT、DOCX、XLSX、PPTX、TeX/LaTeX/BibTeX 的结构提取、原生定位与摘要/详情分层。
|
|
43
43
|
- `amp_protocol_workspace` v1 服务、8 个 agent 工具、本地运行时接入与 MCP stdio 服务端。
|
|
44
44
|
- 带显式策略的指纹:值使用 RFC 8785 规范化 JSON,文件按字节哈希,目录树使用域分隔的 Merkle 根,`verify` 比较算法、`kind` 与策略,而不是只比对裸十六进制字符串。未配对代理项与 `-0` 被拒绝,而不是被静默改写。
|
|
@@ -53,7 +53,9 @@ Context 使用结构树和类型化关系图。项目依赖、导入、调用与
|
|
|
53
53
|
|
|
54
54
|
### 发现
|
|
55
55
|
|
|
56
|
-
`amp_tool_workspace_discover`
|
|
56
|
+
`amp_tool_workspace_discover` 以一棵结构树返回获准项目、宿主组件、skill、knowledge 与 protocol。文件节点带模块分类(`service`、`tool`、`controller`、`route`、`repository`、`model`、`config`、`test`、`middleware`、`component`、`util`)、扩展名与有界内容匹配。宿主通过 `HostCatalog` 登记项目与插件/服务/工具,通过 `SkillRegistry`、`KnowledgeRegistry`、`ProtocolRegistry` 登记可复用指令、知识条目与协议元数据。发现只暴露 skill/knowledge/protocol 元数据,不返回指令或正文;注册中心按 ID 提供完整条目。发现是只读的,不会扩大 `projectIds`;内容匹配只是发现证据,不能替代 Frame 分配后的详情读取。
|
|
57
|
+
|
|
58
|
+
这些 registry 是各自领域的宿主目录,不要求每个概念都复制成同构 registry。Ability、cognition、progress 等若已有运行时状态、策略或事件模型,应由现有领域模块维护;需要统一枚举时增加只读 catalog/discovery 投影即可。Agent 默认只读正式目录;可选的登记工作流应先创建带来源、版本和提案状态的候选项,再经宿主权限校验、人工审核与审计后发布,不授予模型直接改写已生效条目的能力。
|
|
57
59
|
|
|
58
60
|
## 快速开始
|
|
59
61
|
|
|
@@ -220,11 +222,13 @@ Frame、快照、ContentStore 与后备执行器由宿主提供;将 `tools` /
|
|
|
220
222
|
| [src/naming](src/naming/) | 冻结的 ID 表、ID 文法、兼容别名与 catalog 摘要 |
|
|
221
223
|
| [src/context](src/context/) | Context 生命周期、树/图投影、CAS、工作区事实、上下文装配与 agent 服务 |
|
|
222
224
|
| [src/session](src/session/) | 身份、令牌、TTL、上下文隔离、fork/revoke/rotate |
|
|
225
|
+
| [src/skill](src/skill/) | 可复用 agent skill 注册、校验、查询与隔离副本 |
|
|
226
|
+
| [src/knowledge](src/knowledge/) | 带来源元数据的 knowledge 注册、校验、查询与隔离副本 |
|
|
227
|
+
| [src/protocol](src/protocol/) | 线上协议契约、通道,以及宿主维护的协议元数据注册中心 |
|
|
223
228
|
| [src/file](src/file/) | File/Directory 树、元数据、分页读、原子写、会话运行时/服务、模块图与 ZIP/CFB 容器 |
|
|
224
229
|
| [src/syntax](src/syntax/) | 字符集检测/编解码、字节/行索引、语法注册表与无损只读语法树 |
|
|
225
230
|
| [src/outline](src/outline/) | 代码/文档大纲、范围与标签索引、关键字/策略注册表、React/Shell/SQL/Visual Basic 策略与 Office 解析 |
|
|
226
231
|
| [src/hook](src/hook/) | 面向 agent 的组合 hooks 与运行记录 |
|
|
227
|
-
| [src/protocol](src/protocol/) | 线上契约:信封、A2A、通道与 `amp_protocol_workspace` 接口 |
|
|
228
232
|
| [src/module](src/module/) | 模型/工具端口、MCP 适配器与执行策略 |
|
|
229
233
|
| [src/runtime](src/runtime/) | agent 回合、工具循环与治理接入 |
|
|
230
234
|
| [src/governance](src/governance/) | 清单、凭据、预算、工作流、签名与审计 |
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Frame } from "../frame/frame.js";
|
|
2
2
|
import { HostCatalog } from "../discover/host.js";
|
|
3
|
+
import type { KnowledgeRegistry } from "../knowledge/registry.js";
|
|
4
|
+
import type { ProtocolRegistry } from "../protocol/registry.js";
|
|
5
|
+
import type { SkillRegistry } from "../skill/registry.js";
|
|
3
6
|
import type { ToolCatalog } from "../naming/index.js";
|
|
4
7
|
import type { WorkspaceErrorCode, WorkspaceProjectAction, WorkspaceResponse, WorkspaceToolDefinition } from "../protocol/workspace.js";
|
|
5
8
|
import type { Receipt } from "../receipt/receipt.js";
|
|
@@ -116,6 +119,9 @@ export interface WorkspaceServiceOptions {
|
|
|
116
119
|
* components are filtered against `projectIds` before discovery sees them.
|
|
117
120
|
*/
|
|
118
121
|
host?: HostCatalog;
|
|
122
|
+
skills?: SkillRegistry;
|
|
123
|
+
knowledge?: KnowledgeRegistry;
|
|
124
|
+
protocols?: ProtocolRegistry;
|
|
119
125
|
}
|
|
120
126
|
export declare class WorkspaceAgentService {
|
|
121
127
|
private readonly agentId;
|
|
@@ -127,6 +133,9 @@ export declare class WorkspaceAgentService {
|
|
|
127
133
|
private readonly roots;
|
|
128
134
|
private readonly definitions;
|
|
129
135
|
private readonly host;
|
|
136
|
+
private readonly skills?;
|
|
137
|
+
private readonly knowledge?;
|
|
138
|
+
private readonly protocols?;
|
|
130
139
|
private readonly projectIds;
|
|
131
140
|
private readonly store;
|
|
132
141
|
private readonly writer?;
|
|
@@ -468,6 +468,9 @@ export class WorkspaceAgentService {
|
|
|
468
468
|
roots;
|
|
469
469
|
definitions = workspaceToolDefinitions();
|
|
470
470
|
host;
|
|
471
|
+
skills;
|
|
472
|
+
knowledge;
|
|
473
|
+
protocols;
|
|
471
474
|
projectIds;
|
|
472
475
|
store;
|
|
473
476
|
writer;
|
|
@@ -493,6 +496,9 @@ export class WorkspaceAgentService {
|
|
|
493
496
|
}
|
|
494
497
|
this.agentId = options.agentId;
|
|
495
498
|
this.host = options.host ?? new HostCatalog();
|
|
499
|
+
this.skills = options.skills;
|
|
500
|
+
this.knowledge = options.knowledge;
|
|
501
|
+
this.protocols = options.protocols;
|
|
496
502
|
this.projectIds = new Set(options.projectIds);
|
|
497
503
|
this.writer = options.writer;
|
|
498
504
|
this.runner = options.runner;
|
|
@@ -824,6 +830,9 @@ export class WorkspaceAgentService {
|
|
|
824
830
|
projects,
|
|
825
831
|
components,
|
|
826
832
|
builtIn: this.builtInComponents(),
|
|
833
|
+
...(this.skills === (void 0) ? {} : { skills: this.skills }),
|
|
834
|
+
...(this.knowledge === (void 0) ? {} : { knowledge: this.knowledge }),
|
|
835
|
+
...(this.protocols === (void 0) ? {} : { protocols: this.protocols }),
|
|
827
836
|
query,
|
|
828
837
|
contentOf: (entity) => {
|
|
829
838
|
if (entity.detailRef === (void 0)) {
|
package/lib/discover/kinds.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare const ModuleKinds: readonly ["service", "tool", "controller", "ro
|
|
|
8
8
|
export type ModuleKind = (typeof ModuleKinds)[number];
|
|
9
9
|
export declare const ComponentKinds: readonly ["plugin", "service", "tool", "module"];
|
|
10
10
|
export type ComponentKind = (typeof ComponentKinds)[number];
|
|
11
|
-
export declare const DiscoveryScopes: readonly ["all", "projects", "host"];
|
|
11
|
+
export declare const DiscoveryScopes: readonly ["all", "projects", "host", "skills", "knowledge", "protocols"];
|
|
12
12
|
export type DiscoveryScope = (typeof DiscoveryScopes)[number];
|
|
13
13
|
export declare const ComponentStatuses: readonly ["active", "disabled", "deprecated"];
|
|
14
14
|
export type ComponentStatus = (typeof ComponentStatuses)[number];
|
package/lib/discover/kinds.js
CHANGED
|
@@ -19,5 +19,5 @@ export const ModuleKinds = [
|
|
|
19
19
|
"unknown",
|
|
20
20
|
];
|
|
21
21
|
export const ComponentKinds = ["plugin", "service", "tool", "module"];
|
|
22
|
-
export const DiscoveryScopes = ["all", "projects", "host"];
|
|
22
|
+
export const DiscoveryScopes = ["all", "projects", "host", "skills", "knowledge", "protocols"];
|
|
23
23
|
export const ComponentStatuses = ["active", "disabled", "deprecated"];
|
package/lib/discover/tree.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { KnowledgeRegistry } from "../knowledge/registry.js";
|
|
2
|
+
import { ProtocolRegistry } from "../protocol/registry.js";
|
|
3
|
+
import { SkillRegistry } from "../skill/registry.js";
|
|
1
4
|
import { classifyModule, extensionOf, normalizeExtension } from "./classify.js";
|
|
2
5
|
import { ComponentKinds, DiscoveryScopes, ModuleKinds } from "./kinds.js";
|
|
3
6
|
const DefaultLimit = 100;
|
|
@@ -45,6 +48,9 @@ const normalizeQuery = (input = {}) => {
|
|
|
45
48
|
const metadataText = (entity) => `${entity.label} ${entity.source.uri} ${entity.summary} ${(entity.tags ?? []).join(" ")} ${(entity.searchTerms ?? []).join(" ")}`.toLowerCase();
|
|
46
49
|
const componentText = (component) => `${component.id} ${component.name} ${component.description} ${component.purpose ?? ""} ${component.version ?? ""} ${component.endpoint ?? ""} ${(component.capabilities ?? []).join(" ")}`.toLowerCase();
|
|
47
50
|
const projectText = (project) => `${project.id} ${project.name} ${project.description} ${project.purpose} ${project.summary} ${(project.tags ?? []).join(" ")}`.toLowerCase();
|
|
51
|
+
const skillText = (skill) => `${skill.id} ${skill.name} ${skill.description} ${(skill.tags ?? []).join(" ")} ${(skill.capabilities ?? []).join(" ")}`.toLowerCase();
|
|
52
|
+
const knowledgeText = (knowledge) => `${knowledge.id} ${knowledge.title} ${knowledge.summary} ${knowledge.sourceUri ?? ""} ${(knowledge.tags ?? []).join(" ")}`.toLowerCase();
|
|
53
|
+
const protocolText = (protocol) => `${protocol.id} ${protocol.name} ${protocol.version} ${protocol.description} ${protocol.status ?? "active"} ${protocol.endpoint ?? ""} ${(protocol.capabilities ?? []).join(" ")}`.toLowerCase();
|
|
48
54
|
const passesStructuralFilters = (entity, query) => {
|
|
49
55
|
if (entity.kind !== "file") {
|
|
50
56
|
return true;
|
|
@@ -92,12 +98,7 @@ const contentMatches = (entity, query, state, contentOf) => {
|
|
|
92
98
|
state.contentCache.set(entity.id, matches);
|
|
93
99
|
return matches;
|
|
94
100
|
};
|
|
95
|
-
const makeEntityNode = (entity,
|
|
96
|
-
if (state.used >= query.limit) {
|
|
97
|
-
state.truncated = true;
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
state.used += 1;
|
|
101
|
+
const makeEntityNode = (entity, state, matched, matches, children, truncated, hostProjectByRoot, usedHostProjects) => {
|
|
101
102
|
const hostProject = entity.kind === "project" ? hostProjectByRoot.get(entity.id) : undefined;
|
|
102
103
|
const node = {
|
|
103
104
|
id: entity.id,
|
|
@@ -224,6 +225,9 @@ export const buildDiscoveryTree = (input) => {
|
|
|
224
225
|
plugins: 0,
|
|
225
226
|
services: 0,
|
|
226
227
|
tools: 0,
|
|
228
|
+
skills: 0,
|
|
229
|
+
knowledge: 0,
|
|
230
|
+
protocols: 0,
|
|
227
231
|
moduleCounts: {},
|
|
228
232
|
contentReads: 0,
|
|
229
233
|
contentCache: new Map(),
|
|
@@ -297,6 +301,15 @@ export const buildDiscoveryTree = (input) => {
|
|
|
297
301
|
const fileMatched = entity.kind === "file" && structural && (query.text === "" || textMatched || matches.length > 0);
|
|
298
302
|
const projectMatched = entity.kind === "project" && query.text === "" && !structuralFiltersActive(query);
|
|
299
303
|
const selfMatched = fileMatched || projectMatched || textMatched;
|
|
304
|
+
if (state.used >= query.limit) {
|
|
305
|
+
const matched = selfMatched || hasMatchInSubtree(entity);
|
|
306
|
+
if (matched) {
|
|
307
|
+
state.truncated = true;
|
|
308
|
+
}
|
|
309
|
+
return { node: null, matched, cut: matched };
|
|
310
|
+
}
|
|
311
|
+
// Reserve an ancestor before walking descendants; release it if none match.
|
|
312
|
+
state.used += 1;
|
|
300
313
|
const childEntities = childrenByParent.get(entity.id) ?? [];
|
|
301
314
|
const children = [];
|
|
302
315
|
let childMatched = false;
|
|
@@ -321,17 +334,18 @@ export const buildDiscoveryTree = (input) => {
|
|
|
321
334
|
}
|
|
322
335
|
}
|
|
323
336
|
if (!selfMatched && !childMatched && !cut) {
|
|
337
|
+
state.used -= 1;
|
|
324
338
|
return { node: null, matched: false, cut: false };
|
|
325
339
|
}
|
|
326
340
|
if (cut) {
|
|
327
341
|
state.truncated = true;
|
|
328
342
|
}
|
|
329
|
-
const node = makeEntityNode(entity,
|
|
330
|
-
return
|
|
343
|
+
const node = makeEntityNode(entity, state, selfMatched, matches, children, cut, hostProjectByRoot, usedHostProjects);
|
|
344
|
+
return { node, matched: true, cut };
|
|
331
345
|
};
|
|
332
346
|
const projectNodes = [];
|
|
333
|
-
const includeProjects = query.scope !== "host" && query.componentKind === (void 0);
|
|
334
|
-
const includeHost = query.scope
|
|
347
|
+
const includeProjects = query.scope !== "host" && query.scope !== "skills" && query.scope !== "knowledge" && query.scope !== "protocols" && query.componentKind === (void 0);
|
|
348
|
+
const includeHost = (query.scope === "all" || query.scope === "host") && !structuralFiltersActive(query);
|
|
335
349
|
if (includeProjects) {
|
|
336
350
|
for (let index = 0; index < projectEntities.length; index += 1) {
|
|
337
351
|
const result = walk(projectEntities[index], 0);
|
|
@@ -375,11 +389,94 @@ export const buildDiscoveryTree = (input) => {
|
|
|
375
389
|
componentNodes.set(component.kind, group);
|
|
376
390
|
}
|
|
377
391
|
}
|
|
392
|
+
const protocolNodes = [];
|
|
393
|
+
if (query.scope === "all" || query.scope === "protocols") {
|
|
394
|
+
const protocols = input.protocols === (void 0) ? [] : input.protocols instanceof ProtocolRegistry ? input.protocols.list() : input.protocols;
|
|
395
|
+
for (let index = 0; index < protocols.length; index += 1) {
|
|
396
|
+
const protocol = protocols[index];
|
|
397
|
+
if (protocol.status === "disabled" || (query.text !== "" && !protocolText(protocol).includes(query.text.toLowerCase()))) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (state.used >= query.limit) {
|
|
401
|
+
state.truncated = true;
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
state.used += 1;
|
|
405
|
+
state.protocols += 1;
|
|
406
|
+
protocolNodes.push({
|
|
407
|
+
id: protocol.id,
|
|
408
|
+
kind: "protocol",
|
|
409
|
+
label: protocol.name,
|
|
410
|
+
description: protocol.description,
|
|
411
|
+
version: protocol.version,
|
|
412
|
+
...(protocol.endpoint === (void 0) ? {} : { endpoint: protocol.endpoint }),
|
|
413
|
+
...(protocol.capabilities === (void 0) ? {} : { capabilities: [...protocol.capabilities] }),
|
|
414
|
+
protocolStatus: protocol.status ?? "active",
|
|
415
|
+
matched: true,
|
|
416
|
+
children: [],
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const skillNodes = [];
|
|
421
|
+
if (query.scope === "all" || query.scope === "skills") {
|
|
422
|
+
const skills = input.skills === (void 0) ? [] : input.skills instanceof SkillRegistry ? input.skills.list({ enabledOnly: true }) : input.skills;
|
|
423
|
+
for (let index = 0; index < skills.length; index += 1) {
|
|
424
|
+
const skill = skills[index];
|
|
425
|
+
if (skill.enabled === false || (query.text !== "" && !skillText(skill).includes(query.text.toLowerCase()))) {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (state.used >= query.limit) {
|
|
429
|
+
state.truncated = true;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
state.used += 1;
|
|
433
|
+
state.skills += 1;
|
|
434
|
+
skillNodes.push({
|
|
435
|
+
id: skill.id,
|
|
436
|
+
kind: "skill",
|
|
437
|
+
label: skill.name,
|
|
438
|
+
description: skill.description,
|
|
439
|
+
...(skill.version === (void 0) ? {} : { version: skill.version }),
|
|
440
|
+
...(skill.capabilities === (void 0) ? {} : { capabilities: [...skill.capabilities] }),
|
|
441
|
+
...(skill.tags === (void 0) ? {} : { tags: [...skill.tags] }),
|
|
442
|
+
matched: true,
|
|
443
|
+
children: [],
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const knowledgeNodes = [];
|
|
448
|
+
if (query.scope === "all" || query.scope === "knowledge") {
|
|
449
|
+
const knowledgeEntries = input.knowledge === (void 0) ? [] : input.knowledge instanceof KnowledgeRegistry ? input.knowledge.list() : input.knowledge;
|
|
450
|
+
for (let index = 0; index < knowledgeEntries.length; index += 1) {
|
|
451
|
+
const knowledge = knowledgeEntries[index];
|
|
452
|
+
if (query.text !== "" && !knowledgeText(knowledge).includes(query.text.toLowerCase())) {
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (state.used >= query.limit) {
|
|
456
|
+
state.truncated = true;
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
state.used += 1;
|
|
460
|
+
state.knowledge += 1;
|
|
461
|
+
knowledgeNodes.push({
|
|
462
|
+
id: knowledge.id,
|
|
463
|
+
kind: "knowledge",
|
|
464
|
+
label: knowledge.title,
|
|
465
|
+
description: knowledge.summary,
|
|
466
|
+
...(knowledge.sourceUri === (void 0) ? {} : { sourceUri: knowledge.sourceUri }),
|
|
467
|
+
...(knowledge.version === (void 0) ? {} : { version: knowledge.version }),
|
|
468
|
+
...(knowledge.tags === (void 0) ? {} : { tags: [...knowledge.tags] }),
|
|
469
|
+
...(knowledge.skillIds === (void 0) ? {} : { skillIds: [...knowledge.skillIds] }),
|
|
470
|
+
matched: true,
|
|
471
|
+
children: [],
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
378
475
|
const root = {
|
|
379
476
|
id: "discover:host",
|
|
380
477
|
kind: "host",
|
|
381
478
|
label: "host",
|
|
382
|
-
description: "Authorized projects,
|
|
479
|
+
description: "Authorized projects, host components, skills, knowledge and protocols.",
|
|
383
480
|
matched: true,
|
|
384
481
|
children: [],
|
|
385
482
|
};
|
|
@@ -401,6 +498,16 @@ export const buildDiscoveryTree = (input) => {
|
|
|
401
498
|
root.children.push({ id: `discover:${groupLabels[kind]}`, kind: "group", label: groupLabels[kind], matched: true, children: nodes });
|
|
402
499
|
}
|
|
403
500
|
}
|
|
501
|
+
for (const [label, nodes] of [
|
|
502
|
+
["skills", skillNodes],
|
|
503
|
+
["knowledge", knowledgeNodes],
|
|
504
|
+
["protocols", protocolNodes],
|
|
505
|
+
]) {
|
|
506
|
+
if (nodes.length > 0) {
|
|
507
|
+
nodes.sort((left, right) => left.label.localeCompare(right.label) || left.id.localeCompare(right.id));
|
|
508
|
+
root.children.push({ id: `discover:${label}`, kind: "group", label, matched: true, children: nodes });
|
|
509
|
+
}
|
|
510
|
+
}
|
|
404
511
|
const summary = {
|
|
405
512
|
projects: state.projects,
|
|
406
513
|
modules: state.modules,
|
|
@@ -409,6 +516,9 @@ export const buildDiscoveryTree = (input) => {
|
|
|
409
516
|
plugins: state.plugins,
|
|
410
517
|
services: state.services,
|
|
411
518
|
tools: state.tools,
|
|
519
|
+
skills: state.skills,
|
|
520
|
+
knowledge: state.knowledge,
|
|
521
|
+
protocols: state.protocols,
|
|
412
522
|
nodes: state.used,
|
|
413
523
|
truncated: state.truncated,
|
|
414
524
|
};
|
package/lib/discover/types.d.ts
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* authorized workspace snapshot.
|
|
4
4
|
*/
|
|
5
5
|
import type { WorkspaceEntity, WorkspaceEntityKind } from "../context/workspace.js";
|
|
6
|
+
import type { KnowledgeEntry, KnowledgeRegistry } from "../knowledge/registry.js";
|
|
7
|
+
import type { ProtocolEntry, ProtocolRegistry } from "../protocol/registry.js";
|
|
8
|
+
import type { SkillEntry, SkillRegistry } from "../skill/registry.js";
|
|
6
9
|
import type { ComponentKind, ComponentStatus, DiscoveryScope, ModuleKind } from "./kinds.js";
|
|
7
10
|
/**
|
|
8
11
|
* Host-registered project metadata. The workspace snapshot already carries a
|
|
@@ -41,7 +44,7 @@ export interface DiscoveryMatch {
|
|
|
41
44
|
line: number;
|
|
42
45
|
text: string;
|
|
43
46
|
}
|
|
44
|
-
export type DiscoveryNodeKind = "host" | "group" | WorkspaceEntityKind | ComponentKind;
|
|
47
|
+
export type DiscoveryNodeKind = "host" | "group" | WorkspaceEntityKind | ComponentKind | "skill" | "knowledge" | "protocol";
|
|
45
48
|
/**
|
|
46
49
|
* One node of the discovery tree. Project nodes carry description, purpose and
|
|
47
50
|
* summary; file nodes carry module classification, extension and bounded
|
|
@@ -62,6 +65,9 @@ export interface DiscoveryNode {
|
|
|
62
65
|
endpoint?: string;
|
|
63
66
|
capabilities?: string[];
|
|
64
67
|
projectId?: string;
|
|
68
|
+
tags?: string[];
|
|
69
|
+
skillIds?: string[];
|
|
70
|
+
protocolStatus?: "active" | "deprecated" | "disabled";
|
|
65
71
|
matched: boolean;
|
|
66
72
|
truncated?: boolean;
|
|
67
73
|
contentMatches?: DiscoveryMatch[];
|
|
@@ -90,6 +96,10 @@ export interface DiscoverySummary {
|
|
|
90
96
|
plugins: number;
|
|
91
97
|
services: number;
|
|
92
98
|
tools: number;
|
|
99
|
+
/** Optional for consumers constructing pre-registry discovery summaries. */
|
|
100
|
+
skills?: number;
|
|
101
|
+
knowledge?: number;
|
|
102
|
+
protocols?: number;
|
|
93
103
|
nodes: number;
|
|
94
104
|
truncated: boolean;
|
|
95
105
|
}
|
|
@@ -110,6 +120,9 @@ export interface DiscoveryInput {
|
|
|
110
120
|
* `amp.workspace` service and its tools. Host components win on id clashes.
|
|
111
121
|
*/
|
|
112
122
|
builtIn?: readonly HostComponent[];
|
|
123
|
+
skills?: readonly SkillEntry[] | SkillRegistry;
|
|
124
|
+
knowledge?: readonly KnowledgeEntry[] | KnowledgeRegistry;
|
|
125
|
+
protocols?: readonly ProtocolEntry[] | ProtocolRegistry;
|
|
113
126
|
query?: DiscoveryQuery;
|
|
114
127
|
contentOf?: (entity: WorkspaceEntity) => string | undefined;
|
|
115
128
|
}
|
package/lib/global/service.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import type { WorkspaceRunner, WorkspaceServiceLimits, WorkspaceWriter } from ".
|
|
|
3
3
|
import type { ContentStore } from "../context/contentStore.js";
|
|
4
4
|
import type { WorkspaceSnapshot } from "../context/workspace.js";
|
|
5
5
|
import type { HostCatalog } from "../discover/host.js";
|
|
6
|
+
import type { KnowledgeRegistry } from "../knowledge/registry.js";
|
|
7
|
+
import type { ProtocolRegistry } from "../protocol/registry.js";
|
|
8
|
+
import type { SkillRegistry } from "../skill/registry.js";
|
|
6
9
|
import type { Frame } from "../frame/frame.js";
|
|
7
10
|
import type { ContextSnapshot } from "../context/lifecycle.js";
|
|
8
11
|
import type { Receipt } from "../receipt/receipt.js";
|
|
@@ -17,6 +20,9 @@ export interface GlobalServiceOptions {
|
|
|
17
20
|
*/
|
|
18
21
|
projectIds?: readonly string[];
|
|
19
22
|
host?: HostCatalog;
|
|
23
|
+
skills?: SkillRegistry;
|
|
24
|
+
knowledge?: KnowledgeRegistry;
|
|
25
|
+
protocols?: ProtocolRegistry;
|
|
20
26
|
limits?: Partial<WorkspaceServiceLimits>;
|
|
21
27
|
/**
|
|
22
28
|
* Optional persistence port forwarded to the underlying workspace service.
|
package/lib/global/service.js
CHANGED
|
@@ -25,6 +25,9 @@ export class GlobalAgentService {
|
|
|
25
25
|
projectIds,
|
|
26
26
|
store: options.store,
|
|
27
27
|
...(options.host === (void 0) ? {} : { host: options.host }),
|
|
28
|
+
...(options.skills === (void 0) ? {} : { skills: options.skills }),
|
|
29
|
+
...(options.knowledge === (void 0) ? {} : { knowledge: options.knowledge }),
|
|
30
|
+
...(options.protocols === (void 0) ? {} : { protocols: options.protocols }),
|
|
28
31
|
...(options.limits === (void 0) ? {} : { limits: options.limits }),
|
|
29
32
|
...(options.writer === (void 0) ? {} : { writer: options.writer }),
|
|
30
33
|
...(options.runner === (void 0) ? {} : { runner: options.runner }),
|
package/lib/index.d.ts
CHANGED
|
@@ -16,5 +16,9 @@ export * as session from "./session/index.js";
|
|
|
16
16
|
export * from "./frame/index.js";
|
|
17
17
|
export * from "./ledger/index.js";
|
|
18
18
|
export * from "./manifest/index.js";
|
|
19
|
+
export { ProtocolRegistry } from "./protocol/registry.js";
|
|
20
|
+
export type { ProtocolEntry, ProtocolStatus } from "./protocol/registry.js";
|
|
21
|
+
export * from "./skill/index.js";
|
|
22
|
+
export * from "./knowledge/index.js";
|
|
19
23
|
export * from "./receipt/index.js";
|
|
20
24
|
export * from "./warrant/index.js";
|
package/lib/index.js
CHANGED
|
@@ -16,5 +16,8 @@ export * as session from "./session/index.js";
|
|
|
16
16
|
export * from "./frame/index.js";
|
|
17
17
|
export * from "./ledger/index.js";
|
|
18
18
|
export * from "./manifest/index.js";
|
|
19
|
+
export { ProtocolRegistry } from "./protocol/registry.js";
|
|
20
|
+
export * from "./skill/index.js";
|
|
21
|
+
export * from "./knowledge/index.js";
|
|
19
22
|
export * from "./receipt/index.js";
|
|
20
23
|
export * from "./warrant/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { KnowledgeRegistry } from "./registry.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Registry for source-aware, discoverable knowledge entries. */
|
|
2
|
+
export interface KnowledgeEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
summary: string;
|
|
6
|
+
content: string;
|
|
7
|
+
sourceUri?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
tags?: string[];
|
|
10
|
+
skillIds?: string[];
|
|
11
|
+
updatedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class KnowledgeRegistry {
|
|
14
|
+
private readonly entries;
|
|
15
|
+
register(knowledge: KnowledgeEntry): KnowledgeEntry;
|
|
16
|
+
get(id: string): KnowledgeEntry | undefined;
|
|
17
|
+
list(): KnowledgeEntry[];
|
|
18
|
+
has(id: string): boolean;
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { InMemoryRegistry } from "../registry/memory.js";
|
|
2
|
+
const cloneKnowledge = (knowledge) => ({
|
|
3
|
+
...knowledge,
|
|
4
|
+
...(knowledge.tags === (void 0) ? {} : { tags: [...knowledge.tags] }),
|
|
5
|
+
...(knowledge.skillIds === (void 0) ? {} : { skillIds: [...knowledge.skillIds] }),
|
|
6
|
+
});
|
|
7
|
+
const validateKnowledge = (knowledge) => {
|
|
8
|
+
for (const [field, value] of Object.entries({ id: knowledge.id, title: knowledge.title, summary: knowledge.summary, content: knowledge.content })) {
|
|
9
|
+
if (typeof (value) !== "string" || value.trim().length === 0) {
|
|
10
|
+
throw new Error(`knowledge ${field} must be a non-empty string`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
for (const [field, values] of Object.entries({ tags: knowledge.tags, skillIds: knowledge.skillIds })) {
|
|
14
|
+
if (values !== (void 0) && (!Array.isArray(values) || values.some((value) => typeof (value) !== "string" || value.trim().length === 0))) {
|
|
15
|
+
throw new Error(`knowledge ${field} must contain non-empty strings`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (knowledge.sourceUri !== (void 0) && knowledge.sourceUri.trim().length === 0) {
|
|
19
|
+
throw new Error("knowledge sourceUri must be a non-empty string");
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export class KnowledgeRegistry {
|
|
23
|
+
entries = new InMemoryRegistry(cloneKnowledge, (id) => new Error(`knowledge ${id} is already registered`));
|
|
24
|
+
register(knowledge) {
|
|
25
|
+
validateKnowledge(knowledge);
|
|
26
|
+
return this.entries.register(knowledge);
|
|
27
|
+
}
|
|
28
|
+
get(id) {
|
|
29
|
+
return this.entries.get(id);
|
|
30
|
+
}
|
|
31
|
+
list() {
|
|
32
|
+
return this.entries.list({
|
|
33
|
+
compare: (left, right) => left.title.localeCompare(right.title) || left.id.localeCompare(right.id),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
has(id) {
|
|
37
|
+
return this.entries.has(id);
|
|
38
|
+
}
|
|
39
|
+
}
|
package/lib/protocol/index.d.ts
CHANGED
package/lib/protocol/index.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Host-owned catalog of protocol metadata exposed through discovery. */
|
|
2
|
+
export type ProtocolStatus = "active" | "deprecated" | "disabled";
|
|
3
|
+
export interface ProtocolEntry {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
description: string;
|
|
8
|
+
status?: ProtocolStatus;
|
|
9
|
+
endpoint?: string;
|
|
10
|
+
capabilities?: string[];
|
|
11
|
+
}
|
|
12
|
+
export declare class ProtocolRegistry {
|
|
13
|
+
private readonly entries;
|
|
14
|
+
register(protocol: ProtocolEntry): ProtocolEntry;
|
|
15
|
+
get(id: string): ProtocolEntry | undefined;
|
|
16
|
+
list(options?: {
|
|
17
|
+
includeDisabled?: boolean;
|
|
18
|
+
}): ProtocolEntry[];
|
|
19
|
+
has(id: string): boolean;
|
|
20
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { InMemoryRegistry } from "../registry/memory.js";
|
|
2
|
+
const cloneProtocol = (protocol) => ({
|
|
3
|
+
...protocol,
|
|
4
|
+
...(protocol.capabilities === (void 0) ? {} : { capabilities: [...protocol.capabilities] }),
|
|
5
|
+
});
|
|
6
|
+
const validateProtocol = (protocol) => {
|
|
7
|
+
for (const [field, value] of Object.entries({
|
|
8
|
+
id: protocol.id,
|
|
9
|
+
name: protocol.name,
|
|
10
|
+
version: protocol.version,
|
|
11
|
+
description: protocol.description,
|
|
12
|
+
})) {
|
|
13
|
+
if (typeof (value) !== "string" || value.trim().length === 0) {
|
|
14
|
+
throw new Error(`protocol ${field} must be a non-empty string`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (protocol.status !== (void 0) && !["active", "deprecated", "disabled"].includes(protocol.status)) {
|
|
18
|
+
throw new Error(`unknown protocol status ${protocol.status}`);
|
|
19
|
+
}
|
|
20
|
+
if (protocol.endpoint !== (void 0) && protocol.endpoint.trim().length === 0) {
|
|
21
|
+
throw new Error("protocol endpoint must be a non-empty string");
|
|
22
|
+
}
|
|
23
|
+
if (protocol.capabilities !== (void 0) &&
|
|
24
|
+
(!Array.isArray(protocol.capabilities) || protocol.capabilities.some((value) => typeof (value) !== "string" || value.trim().length === 0))) {
|
|
25
|
+
throw new Error("protocol capabilities must contain non-empty strings");
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export class ProtocolRegistry {
|
|
29
|
+
entries = new InMemoryRegistry(cloneProtocol, (id) => new Error(`protocol ${id} is already registered`));
|
|
30
|
+
register(protocol) {
|
|
31
|
+
validateProtocol(protocol);
|
|
32
|
+
return this.entries.register(protocol);
|
|
33
|
+
}
|
|
34
|
+
get(id) {
|
|
35
|
+
return this.entries.get(id);
|
|
36
|
+
}
|
|
37
|
+
list(options = {}) {
|
|
38
|
+
return this.entries.list({
|
|
39
|
+
filter: (protocol) => options.includeDisabled === true || protocol.status !== "disabled",
|
|
40
|
+
compare: (left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
has(id) {
|
|
44
|
+
return this.entries.has(id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -115,7 +115,7 @@ const Definitions = [
|
|
|
115
115
|
relationKind: { type: "string", enum: Kinds },
|
|
116
116
|
...Page,
|
|
117
117
|
}, ["revision", "nodeId", "direction"]),
|
|
118
|
-
definition(ToolIds.workspaceDiscover, "read", "Discover authorized projects, internal modules (service/tool/...), file names and bounded content matches, plus host-registered plugins/services/tools, as one structural tree.
|
|
118
|
+
definition(ToolIds.workspaceDiscover, "read", "Discover authorized projects, internal modules (service/tool/...), file names and bounded content matches, plus host-registered plugins/services/tools and registered skills/knowledge/protocols, as one structural tree. Registry nodes expose metadata only. Read-only; snippets are discovery evidence, not a detail grant.", {
|
|
119
119
|
revision: Key,
|
|
120
120
|
text: { type: "string", maxLength: 512 },
|
|
121
121
|
scope: { type: "string", enum: DiscoveryScopes },
|
package/lib/registry/index.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ export { attest, declareConcept, declareModule, dependencies, hasDependencyCycle
|
|
|
2
2
|
export type { AttestationResult, ConceptInput, ConceptLinkRole, DeclarationResult, DependencyRow, ModuleInput, ModuleKind, RegistryStatus, } from "./registry.js";
|
|
3
3
|
export { collectDirectory, diffDirectory, digestDirectory } from "./content.js";
|
|
4
4
|
export type { ContentEntry } from "./content.js";
|
|
5
|
+
export { InMemoryRegistry } from "./memory.js";
|
|
6
|
+
export type { InMemoryRegistryListOptions } from "./memory.js";
|
package/lib/registry/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { attest, declareConcept, declareModule, dependencies, hasDependencyCycle, linkConcept, linkDependency, verifyModuleContent, verifyRegistry, } from "./registry.js";
|
|
2
2
|
export { collectDirectory, diffDirectory, digestDirectory } from "./content.js";
|
|
3
|
+
export { InMemoryRegistry } from "./memory.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Small in-memory registry primitive with defensive cloning. */
|
|
2
|
+
export interface InMemoryRegistryListOptions<T> {
|
|
3
|
+
filter?: (entry: T) => boolean;
|
|
4
|
+
compare?: (left: T, right: T) => number;
|
|
5
|
+
}
|
|
6
|
+
export declare class InMemoryRegistry<T extends {
|
|
7
|
+
id: string;
|
|
8
|
+
}> {
|
|
9
|
+
private readonly entries;
|
|
10
|
+
private readonly cloneEntry;
|
|
11
|
+
private readonly duplicateError;
|
|
12
|
+
constructor(cloneEntry: (entry: T) => T, duplicateError: (id: string) => Error);
|
|
13
|
+
register(entry: T): T;
|
|
14
|
+
get(id: string): T | undefined;
|
|
15
|
+
list(options?: InMemoryRegistryListOptions<T>): T[];
|
|
16
|
+
has(id: string): boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class InMemoryRegistry {
|
|
2
|
+
entries = new Map();
|
|
3
|
+
cloneEntry;
|
|
4
|
+
duplicateError;
|
|
5
|
+
constructor(cloneEntry, duplicateError) {
|
|
6
|
+
this.cloneEntry = cloneEntry;
|
|
7
|
+
this.duplicateError = duplicateError;
|
|
8
|
+
}
|
|
9
|
+
register(entry) {
|
|
10
|
+
if (this.entries.has(entry.id)) {
|
|
11
|
+
throw this.duplicateError(entry.id);
|
|
12
|
+
}
|
|
13
|
+
const stored = this.cloneEntry(entry);
|
|
14
|
+
this.entries.set(stored.id, stored);
|
|
15
|
+
return this.cloneEntry(stored);
|
|
16
|
+
}
|
|
17
|
+
get(id) {
|
|
18
|
+
const entry = this.entries.get(id);
|
|
19
|
+
return entry === (void 0) ? undefined : this.cloneEntry(entry);
|
|
20
|
+
}
|
|
21
|
+
list(options = {}) {
|
|
22
|
+
const entries = [...this.entries.values()]
|
|
23
|
+
.filter((entry) => options.filter === (void 0) || options.filter(entry))
|
|
24
|
+
.map(this.cloneEntry);
|
|
25
|
+
if (options.compare !== (void 0)) {
|
|
26
|
+
entries.sort(options.compare);
|
|
27
|
+
}
|
|
28
|
+
return entries;
|
|
29
|
+
}
|
|
30
|
+
has(id) {
|
|
31
|
+
return this.entries.has(id);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SkillRegistry } from "./registry.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Registry for reusable agent skills. */
|
|
2
|
+
export interface SkillEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
instructions: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
tags?: string[];
|
|
9
|
+
capabilities?: string[];
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class SkillRegistry {
|
|
13
|
+
private readonly entries;
|
|
14
|
+
register(skill: SkillEntry): SkillEntry;
|
|
15
|
+
get(id: string): SkillEntry | undefined;
|
|
16
|
+
list(options?: {
|
|
17
|
+
enabledOnly?: boolean;
|
|
18
|
+
}): SkillEntry[];
|
|
19
|
+
has(id: string): boolean;
|
|
20
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { InMemoryRegistry } from "../registry/memory.js";
|
|
2
|
+
const cloneSkill = (skill) => ({
|
|
3
|
+
...skill,
|
|
4
|
+
...(skill.tags === (void 0) ? {} : { tags: [...skill.tags] }),
|
|
5
|
+
...(skill.capabilities === (void 0) ? {} : { capabilities: [...skill.capabilities] }),
|
|
6
|
+
});
|
|
7
|
+
const validateSkill = (skill) => {
|
|
8
|
+
for (const [field, value] of Object.entries({ id: skill.id, name: skill.name, description: skill.description, instructions: skill.instructions })) {
|
|
9
|
+
if (typeof (value) !== "string" || value.trim().length === 0) {
|
|
10
|
+
throw new Error(`skill ${field} must be a non-empty string`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
for (const [field, values] of Object.entries({ tags: skill.tags, capabilities: skill.capabilities })) {
|
|
14
|
+
if (values !== (void 0) && (!Array.isArray(values) || values.some((value) => typeof (value) !== "string" || value.trim().length === 0))) {
|
|
15
|
+
throw new Error(`skill ${field} must contain non-empty strings`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export class SkillRegistry {
|
|
20
|
+
entries = new InMemoryRegistry(cloneSkill, (id) => new Error(`skill ${id} is already registered`));
|
|
21
|
+
register(skill) {
|
|
22
|
+
validateSkill(skill);
|
|
23
|
+
return this.entries.register(skill);
|
|
24
|
+
}
|
|
25
|
+
get(id) {
|
|
26
|
+
return this.entries.get(id);
|
|
27
|
+
}
|
|
28
|
+
list(options = {}) {
|
|
29
|
+
return this.entries.list({
|
|
30
|
+
filter: (skill) => options.enabledOnly !== true || skill.enabled !== false,
|
|
31
|
+
compare: (left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
has(id) {
|
|
35
|
+
return this.entries.has(id);
|
|
36
|
+
}
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "attention-manifest-protocol",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"files": [
|
|
5
|
-
"lib",
|
|
6
|
-
"docs/schemas",
|
|
7
|
-
"README.md",
|
|
8
|
-
"README.zh-CN.md",
|
|
9
|
-
"CHANGELOG.md",
|
|
10
|
-
"CHANGELOG.zh-CN.md",
|
|
11
|
-
"LICENSE",
|
|
12
|
-
"NOTICE"
|
|
13
|
-
],
|
|
14
|
-
"private": false,
|
|
15
|
-
"description": "A metacognitive protocol for agent attention and warrant: signed manifests, attention frames with explicit exclusions, receipts, T0-T4 evidence tiers, MCP execution, federation, persistence, agent governance (manifests, credentials, budgets, workflows) and multi-agent delegation.",
|
|
16
|
-
"keywords": [
|
|
17
|
-
"agent-protocol",
|
|
18
|
-
"attention",
|
|
19
|
-
"metacognition",
|
|
20
|
-
"context-engineering",
|
|
21
|
-
"mcp",
|
|
22
|
-
"a2a",
|
|
23
|
-
"provenance",
|
|
24
|
-
"multi-agent",
|
|
25
|
-
"governance"
|
|
26
|
-
],
|
|
27
|
-
"license": "Apache-2.0",
|
|
28
|
-
"author": "Eloy Kim",
|
|
29
|
-
"type": "module",
|
|
30
|
-
"main": "./lib/index.js",
|
|
31
|
-
"types": "./lib/index.d.ts",
|
|
32
|
-
"exports": {
|
|
33
|
-
".": {
|
|
34
|
-
"types": "./lib/index.d.ts",
|
|
35
|
-
"default": "./lib/index.js"
|
|
36
|
-
},
|
|
37
|
-
"./package.json": "./package.json",
|
|
38
|
-
"./schemas/*": "./docs/schemas/*",
|
|
39
|
-
"./*.js": {
|
|
40
|
-
"types": "./lib/*.d.ts",
|
|
41
|
-
"default": "./lib/*.js"
|
|
42
|
-
},
|
|
43
|
-
"./*": {
|
|
44
|
-
"types": "./lib/*/index.d.ts",
|
|
45
|
-
"default": "./lib/*/index.js"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
"engines": {
|
|
49
|
-
"node": ">=24"
|
|
50
|
-
},
|
|
51
|
-
"scripts": {
|
|
52
|
-
"dev": "vite",
|
|
53
|
-
"build": "tsc && vite build",
|
|
54
|
-
"build:lib": "tsc -p tsconfig.build.json && node tools/rewriteDeclarationExtensions.ts",
|
|
55
|
-
"prebuild:lib": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
|
|
56
|
-
"preview": "vite preview",
|
|
57
|
-
"prepublishOnly": "npm run build:lib"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"@stylistic/eslint-plugin": "^5.10.0",
|
|
61
|
-
"@types/node": "^26.6.5",
|
|
62
|
-
"@typescript-eslint/utils": "^8.72.0",
|
|
63
|
-
"eslint": "^10.13.0",
|
|
64
|
-
"fast-xml-parser": "^5.11.2",
|
|
65
|
-
"fflate": "^0.8.3",
|
|
66
|
-
"jiti": "^2.7.0",
|
|
67
|
-
"prettier": "^3.9.10",
|
|
68
|
-
"typescript": "~6.0.3",
|
|
69
|
-
"typescript-eslint": "^8.72.0",
|
|
70
|
-
"vite": "^8.3.4"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "attention-manifest-protocol",
|
|
3
|
+
"version": "0.4.6",
|
|
4
|
+
"files": [
|
|
5
|
+
"lib",
|
|
6
|
+
"docs/schemas",
|
|
7
|
+
"README.md",
|
|
8
|
+
"README.zh-CN.md",
|
|
9
|
+
"CHANGELOG.md",
|
|
10
|
+
"CHANGELOG.zh-CN.md",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"NOTICE"
|
|
13
|
+
],
|
|
14
|
+
"private": false,
|
|
15
|
+
"description": "A metacognitive protocol for agent attention and warrant: signed manifests, attention frames with explicit exclusions, receipts, T0-T4 evidence tiers, MCP execution, federation, persistence, agent governance (manifests, credentials, budgets, workflows) and multi-agent delegation.",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"agent-protocol",
|
|
18
|
+
"attention",
|
|
19
|
+
"metacognition",
|
|
20
|
+
"context-engineering",
|
|
21
|
+
"mcp",
|
|
22
|
+
"a2a",
|
|
23
|
+
"provenance",
|
|
24
|
+
"multi-agent",
|
|
25
|
+
"governance"
|
|
26
|
+
],
|
|
27
|
+
"license": "Apache-2.0",
|
|
28
|
+
"author": "Eloy Kim",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./lib/index.js",
|
|
31
|
+
"types": "./lib/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./lib/index.d.ts",
|
|
35
|
+
"default": "./lib/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json",
|
|
38
|
+
"./schemas/*": "./docs/schemas/*",
|
|
39
|
+
"./*.js": {
|
|
40
|
+
"types": "./lib/*.d.ts",
|
|
41
|
+
"default": "./lib/*.js"
|
|
42
|
+
},
|
|
43
|
+
"./*": {
|
|
44
|
+
"types": "./lib/*/index.d.ts",
|
|
45
|
+
"default": "./lib/*/index.js"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=24"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"dev": "vite",
|
|
53
|
+
"build": "tsc && vite build",
|
|
54
|
+
"build:lib": "tsc -p tsconfig.build.json && node tools/rewriteDeclarationExtensions.ts",
|
|
55
|
+
"prebuild:lib": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
|
|
56
|
+
"preview": "vite preview",
|
|
57
|
+
"prepublishOnly": "npm run build:lib"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
61
|
+
"@types/node": "^26.6.5",
|
|
62
|
+
"@typescript-eslint/utils": "^8.72.0",
|
|
63
|
+
"eslint": "^10.13.0",
|
|
64
|
+
"fast-xml-parser": "^5.11.2",
|
|
65
|
+
"fflate": "^0.8.3",
|
|
66
|
+
"jiti": "^2.7.0",
|
|
67
|
+
"prettier": "^3.9.10",
|
|
68
|
+
"typescript": "~6.0.3",
|
|
69
|
+
"typescript-eslint": "^8.72.0",
|
|
70
|
+
"vite": "^8.3.4"
|
|
71
|
+
}
|
|
72
|
+
}
|