evolcore 0.0.25 → 0.0.27
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 +632 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +203 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +172 -33
- package/dist/agents/codex/app-server-client.js +76 -31
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +434 -446
- package/dist/agents/ecagent-runner.js +174 -34
- package/dist/agents/gemini-runner.js +8 -7
- package/dist/agents/runner-types.js +75 -19
- package/dist/aun/aid/agentmd.js +151 -36
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +4 -4
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +162 -39
- package/dist/aun/{menu-client.js → menu/client.js} +85 -6
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +85 -19
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +19 -9
- package/dist/aun/msg/upload.js +43 -80
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +842 -318
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +212 -89
- package/dist/cli/agent-create.js +626 -11
- package/dist/cli/agent.js +125 -13
- package/dist/cli/aun-commands.js +487 -337
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +55 -33
- package/dist/cli/contact.js +72 -15
- package/dist/cli/ctl-command.js +24 -24
- package/dist/cli/daemon-commands.js +140 -63
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +70 -70
- package/dist/cli/handoff-command.js +46 -14
- package/dist/cli/index.js +91 -79
- package/dist/cli/init.js +34 -1
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +5 -1
- package/dist/cli/menu-client.js +51 -32
- package/dist/cli/model.js +3 -3
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +31 -31
- package/dist/cli/response.js +32 -32
- package/dist/cli/restart-monitor.js +103 -42
- package/dist/cli/stats.js +51 -51
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +74 -64
- package/dist/config/builtin-roles.js +11 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +160 -0
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +97 -8
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +30 -7
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +7 -1
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +53 -49
- package/dist/core/auth/operation-authorizer.js +90 -7
- package/dist/core/auth/operation-catalog.js +145 -4
- package/dist/core/auth/remote-access-store.js +155 -10
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +111 -20
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +159 -65
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +46 -7
- package/dist/core/command/menu-handler.js +392 -100
- package/dist/core/command/menu-protocol.js +45 -6
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +123 -43
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +146 -34
- package/dist/core/message/message-bridge.js +163 -20
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +99 -41
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +755 -144
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +112 -41
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +108 -17
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +9 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +34 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +588 -217
- package/dist/ipc.js +193 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +2 -0
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +61 -2
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +26 -14
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +196 -23
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +60 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +69 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +379 -367
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +76 -71
- package/kits/docs/evolcore/agent-create.md +202 -165
- package/kits/docs/evolcore/agent.md +99 -67
- package/kits/docs/evolcore/aid.md +68 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +241 -195
- package/kits/docs/evolcore/contact.md +75 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +244 -244
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +267 -152
- package/kits/docs/evolcore/menu-client.md +58 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +169 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +53 -50
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +623 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +269 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +42 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +217 -190
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +166 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +76 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +65 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +451 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +215 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +92 -92
- package/kits/templates/roles/member.json +101 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +90 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +53 -34
- package/kits/templates/system-fragments/channel.md +28 -64
- package/kits/templates/system-fragments/commands.md +36 -28
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/reply.md +56 -0
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +104 -98
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
package/dist/aun/aid/agentmd.js
CHANGED
|
@@ -4,10 +4,47 @@ import { parseDocument } from 'yaml';
|
|
|
4
4
|
import { getAidStore, loadAid, SLOT } from './store.js';
|
|
5
5
|
import { agentMdPath, aidLocalDir, resolveRoot } from '../../paths.js';
|
|
6
6
|
export const DEFAULT_AGENT_DESCRIPTION = 'EvolCore AI agent.';
|
|
7
|
+
/**
|
|
8
|
+
* AUN 主体类型白名单。没有 `ai` / `codeagent` 这类取值:使用大模型且没有
|
|
9
|
+
* 专用主体类型的服务程序默认归为 `agent`。新建 AID 未指定类型时使用 DEFAULT_AGENT_TYPE。
|
|
10
|
+
*/
|
|
11
|
+
export const AGENT_TYPES = ['human', 'agent', 'group', 'service', 'device', 'org', 'host'];
|
|
12
|
+
export const DEFAULT_AGENT_TYPE = 'agent';
|
|
13
|
+
/**
|
|
14
|
+
* 归一化主体类型:大小写不敏感,统一收敛为白名单里的小写形式。
|
|
15
|
+
* `--type AGENT` / `Agent` 都接受,最终写进 agent.md 的一律是小写 `agent`。
|
|
16
|
+
* 返回 undefined 表示输入不是可识别的类型(交由 validateAgentType 报错)。
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeAgentType(type) {
|
|
19
|
+
if (typeof type !== 'string')
|
|
20
|
+
return undefined;
|
|
21
|
+
const lowered = type.trim().toLowerCase();
|
|
22
|
+
return AGENT_TYPES.includes(lowered) ? lowered : undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Return a human-readable validation error for a type value, or null when valid. */
|
|
25
|
+
export function validateAgentType(type) {
|
|
26
|
+
if (typeof type !== 'string' || !type.trim())
|
|
27
|
+
return 'must be a non-empty string';
|
|
28
|
+
if (!normalizeAgentType(type))
|
|
29
|
+
return `must be one of ${AGENT_TYPES.join(', ')}`;
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* agent.md 的尺寸与字段上限,取值必须与 fastaun 的 agent-md-schema 保持一致,
|
|
34
|
+
* 否则本地校验通过、上传时才被 SDK 拒绝(失败点后移且提示不同)。
|
|
35
|
+
* 参考 @agentunion/fastaun dist/agent-md-schema.js。
|
|
36
|
+
*/
|
|
37
|
+
export const AGENT_MD_MAX_PAYLOAD_BYTES = 4096;
|
|
38
|
+
export const AGENT_DESCRIPTION_MAX_LENGTH = 100;
|
|
39
|
+
export const AGENT_AVATAR_MAX_LENGTH = 256;
|
|
40
|
+
/** 按 Unicode 码点计数——与 SDK 的 Array.from(value).length 对齐(代理对算一个字符)。 */
|
|
41
|
+
function codePointLength(value) {
|
|
42
|
+
return Array.from(value).length;
|
|
43
|
+
}
|
|
7
44
|
export const AGENT_TAG_MIN_COUNT = 3;
|
|
8
45
|
export const AGENT_TAG_MAX_COUNT = 6;
|
|
9
46
|
export const AGENT_TAG_MAX_LENGTH = 50;
|
|
10
|
-
const AGENT_TAG_PATTERN = /^[\p{L}\p{N}]+$/u;
|
|
47
|
+
const AGENT_TAG_PATTERN = /^[\p{L}\p{N}-]+$/u;
|
|
11
48
|
/** Return a human-readable validation error for one tag, or null when valid. */
|
|
12
49
|
export function validateAgentTag(tag) {
|
|
13
50
|
if (typeof tag !== 'string' || !tag.trim())
|
|
@@ -17,7 +54,7 @@ export function validateAgentTag(tag) {
|
|
|
17
54
|
return `must be at most ${AGENT_TAG_MAX_LENGTH} characters`;
|
|
18
55
|
}
|
|
19
56
|
if (!AGENT_TAG_PATTERN.test(normalized)) {
|
|
20
|
-
return 'must contain only Unicode letters and
|
|
57
|
+
return 'must contain only Unicode letters, numbers, and hyphens';
|
|
21
58
|
}
|
|
22
59
|
return null;
|
|
23
60
|
}
|
|
@@ -49,6 +86,12 @@ export function validateAgentTags(tags, options = {}) {
|
|
|
49
86
|
}
|
|
50
87
|
return errors;
|
|
51
88
|
}
|
|
89
|
+
function resolveAgentMdAunPath(opts) {
|
|
90
|
+
return opts?.aunPath ?? opts?.store?.aunPath ?? resolveRoot();
|
|
91
|
+
}
|
|
92
|
+
// A process can host agents that deliberately use different AUN keystore
|
|
93
|
+
// roots. Keep their display-name state separate so one root cannot shadow the
|
|
94
|
+
// other with a same-named AID.
|
|
52
95
|
const displayNameCache = new Map();
|
|
53
96
|
const displayNamePending = new Map();
|
|
54
97
|
const displayNameRevision = new Map();
|
|
@@ -64,9 +107,13 @@ export function parseAgentDisplayName(content) {
|
|
|
64
107
|
const name = frontmatter.match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1]?.trim();
|
|
65
108
|
return name || undefined;
|
|
66
109
|
}
|
|
67
|
-
function
|
|
110
|
+
function displayNameKey(aid, aunPath) {
|
|
111
|
+
const root = path.resolve(aunPath ?? resolveRoot());
|
|
112
|
+
return `${root}\u0000${aid.toLowerCase()}`;
|
|
113
|
+
}
|
|
114
|
+
function readLocalAgentDisplayName(aid, aunPath) {
|
|
68
115
|
try {
|
|
69
|
-
return parseAgentDisplayName(fs.readFileSync(agentMdPath(aid), 'utf-8'));
|
|
116
|
+
return parseAgentDisplayName(fs.readFileSync(agentMdPath(aid, aunPath), 'utf-8'));
|
|
70
117
|
}
|
|
71
118
|
catch {
|
|
72
119
|
return undefined;
|
|
@@ -77,60 +124,87 @@ function readLocalAgentDisplayName(aid) {
|
|
|
77
124
|
* Local content is returned immediately; a missing value starts one shared
|
|
78
125
|
* background refresh and remains undefined until a later lookup.
|
|
79
126
|
*/
|
|
80
|
-
export function resolveAgentDisplayName(aid) {
|
|
127
|
+
export function resolveAgentDisplayName(aid, opts) {
|
|
81
128
|
const normalizedAid = normalizeAid(aid);
|
|
82
129
|
if (!normalizedAid)
|
|
83
130
|
return undefined;
|
|
84
|
-
const
|
|
131
|
+
const aunPath = resolveAgentMdAunPath(opts);
|
|
132
|
+
const key = displayNameKey(normalizedAid, aunPath);
|
|
133
|
+
const cached = displayNameCache.get(key);
|
|
85
134
|
if (cached)
|
|
86
135
|
return cached;
|
|
87
|
-
const localName = readLocalAgentDisplayName(normalizedAid);
|
|
136
|
+
const localName = readLocalAgentDisplayName(normalizedAid, aunPath);
|
|
88
137
|
if (localName) {
|
|
89
|
-
displayNameCache.set(
|
|
138
|
+
displayNameCache.set(key, localName);
|
|
90
139
|
return localName;
|
|
91
140
|
}
|
|
92
|
-
void refreshAgentDisplayName(normalizedAid);
|
|
141
|
+
void refreshAgentDisplayName(normalizedAid, opts);
|
|
93
142
|
return undefined;
|
|
94
143
|
}
|
|
95
144
|
/** Fetch agent.md once and update the shared display-name cache. */
|
|
96
|
-
export function refreshAgentDisplayName(aid) {
|
|
145
|
+
export function refreshAgentDisplayName(aid, opts) {
|
|
97
146
|
const normalizedAid = normalizeAid(aid);
|
|
98
147
|
if (!normalizedAid)
|
|
99
148
|
return Promise.resolve(undefined);
|
|
100
|
-
const
|
|
149
|
+
const aunPath = resolveAgentMdAunPath(opts);
|
|
150
|
+
const key = displayNameKey(normalizedAid, aunPath);
|
|
151
|
+
const existing = displayNamePending.get(key);
|
|
101
152
|
if (existing)
|
|
102
153
|
return existing;
|
|
103
|
-
const revision = displayNameRevision.get(
|
|
154
|
+
const revision = displayNameRevision.get(key) ?? 0;
|
|
104
155
|
let pending;
|
|
105
|
-
pending = agentmdGet(normalizedAid)
|
|
156
|
+
pending = agentmdGet(normalizedAid, { aunPath, store: opts?.store })
|
|
106
157
|
.then(content => {
|
|
107
158
|
const name = typeof content === 'string' ? parseAgentDisplayName(content) : undefined;
|
|
108
|
-
if ((displayNameRevision.get(
|
|
159
|
+
if ((displayNameRevision.get(key) ?? 0) !== revision)
|
|
109
160
|
return undefined;
|
|
110
161
|
if (name)
|
|
111
|
-
displayNameCache.set(
|
|
162
|
+
displayNameCache.set(key, name);
|
|
112
163
|
return name;
|
|
113
164
|
})
|
|
114
165
|
.catch(() => undefined)
|
|
115
166
|
.finally(() => {
|
|
116
|
-
if (displayNamePending.get(
|
|
117
|
-
displayNamePending.delete(
|
|
167
|
+
if (displayNamePending.get(key) === pending) {
|
|
168
|
+
displayNamePending.delete(key);
|
|
118
169
|
}
|
|
119
170
|
});
|
|
120
|
-
displayNamePending.set(
|
|
171
|
+
displayNamePending.set(key, pending);
|
|
121
172
|
return pending;
|
|
122
173
|
}
|
|
123
|
-
export function invalidateAgentDisplayName(aid) {
|
|
174
|
+
export function invalidateAgentDisplayName(aid, aunPath) {
|
|
124
175
|
const normalizedAid = normalizeAid(aid);
|
|
125
176
|
if (!normalizedAid)
|
|
126
177
|
return;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
178
|
+
if (aunPath !== undefined) {
|
|
179
|
+
const key = displayNameKey(normalizedAid, aunPath);
|
|
180
|
+
displayNameCache.delete(key);
|
|
181
|
+
displayNamePending.delete(key);
|
|
182
|
+
displayNameRevision.set(key, (displayNameRevision.get(key) ?? 0) + 1);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const suffix = `\u0000${normalizedAid.toLowerCase()}`;
|
|
186
|
+
const keys = new Set([
|
|
187
|
+
...displayNameCache.keys(),
|
|
188
|
+
...displayNamePending.keys(),
|
|
189
|
+
...displayNameRevision.keys(),
|
|
190
|
+
]);
|
|
191
|
+
for (const key of keys) {
|
|
192
|
+
if (!key.endsWith(suffix))
|
|
193
|
+
continue;
|
|
194
|
+
displayNameCache.delete(key);
|
|
195
|
+
displayNamePending.delete(key);
|
|
196
|
+
displayNameRevision.set(key, (displayNameRevision.get(key) ?? 0) + 1);
|
|
197
|
+
}
|
|
130
198
|
}
|
|
131
199
|
export function buildInitialAgentMd(opts) {
|
|
132
200
|
const agentName = opts.name?.trim() || opts.aid.split('.')[0];
|
|
133
|
-
|
|
201
|
+
// 未指定类型时用 DEFAULT_AGENT_TYPE(agent);指定了就必须落在 AGENT_TYPES 白名单内。
|
|
202
|
+
// 大小写不敏感,写进 agent.md 的一律是归一化后的小写形式。
|
|
203
|
+
const requestedType = opts.type?.trim() || DEFAULT_AGENT_TYPE;
|
|
204
|
+
const typeError = validateAgentType(requestedType);
|
|
205
|
+
if (typeError)
|
|
206
|
+
throw new Error(`Invalid agent.md type: ${typeError}`);
|
|
207
|
+
const agentType = normalizeAgentType(requestedType) ?? DEFAULT_AGENT_TYPE;
|
|
134
208
|
const description = opts.description?.trim() || DEFAULT_AGENT_DESCRIPTION;
|
|
135
209
|
const rawTags = opts.tags?.length ? opts.tags : ['evolcore'];
|
|
136
210
|
const tagErrors = validateAgentTags(rawTags);
|
|
@@ -155,8 +229,9 @@ function yamlDoubleQuote(value) {
|
|
|
155
229
|
export function validateAgentMdFrontmatter(content, expectedAid) {
|
|
156
230
|
const errors = [];
|
|
157
231
|
const payload = stripAgentMdSignature(content);
|
|
158
|
-
|
|
159
|
-
|
|
232
|
+
const payloadBytes = Buffer.byteLength(payload, 'utf8');
|
|
233
|
+
if (payloadBytes > AGENT_MD_MAX_PAYLOAD_BYTES) {
|
|
234
|
+
errors.push(`agent.md frontmatter and body must not exceed ${AGENT_MD_MAX_PAYLOAD_BYTES} bytes before the signature block (current: ${payloadBytes} bytes)`);
|
|
160
235
|
}
|
|
161
236
|
const frontmatter = payload.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
162
237
|
if (!frontmatter)
|
|
@@ -185,15 +260,44 @@ export function validateAgentMdFrontmatter(content, expectedAid) {
|
|
|
185
260
|
requiredString('name');
|
|
186
261
|
requiredString('type');
|
|
187
262
|
const version = requiredString('version');
|
|
188
|
-
|
|
263
|
+
// description 是可选字段(fastaun ≥0.5.13 起不再要求非空):缺失或空串都合法,
|
|
264
|
+
// 仅在实际提供时校验类型与长度,与 SDK 的 agent-md-schema 保持一致。
|
|
265
|
+
const rawDescription = values.description;
|
|
266
|
+
let description;
|
|
267
|
+
if (rawDescription !== undefined && rawDescription !== null) {
|
|
268
|
+
if (typeof rawDescription !== 'string') {
|
|
269
|
+
errors.push('agent.md frontmatter description must be a string');
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
description = rawDescription.trim();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
189
275
|
if (expectedAid && aid && aid !== expectedAid) {
|
|
190
276
|
errors.push(`agent.md frontmatter aid must match upload target ${expectedAid}`);
|
|
191
277
|
}
|
|
192
278
|
if (version && !/^\d+\.\d+\.\d+$/.test(version)) {
|
|
193
279
|
errors.push('agent.md frontmatter version must use major.minor.patch format');
|
|
194
280
|
}
|
|
195
|
-
|
|
196
|
-
|
|
281
|
+
// 长度按 Unicode 码点计、且对未 trim 的原值计数——与 SDK 完全一致,
|
|
282
|
+
// 否则含 emoji 或尾随空格的名片会本地放行、上传才被拒。
|
|
283
|
+
if (typeof rawDescription === 'string') {
|
|
284
|
+
const length = codePointLength(rawDescription);
|
|
285
|
+
if (length > AGENT_DESCRIPTION_MAX_LENGTH) {
|
|
286
|
+
errors.push(`agent.md frontmatter description must be at most ${AGENT_DESCRIPTION_MAX_LENGTH} characters (current: ${length})`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// avatar:SDK 有 256 字符上限,本地此前完全没校验。
|
|
290
|
+
const rawAvatar = values.avatar;
|
|
291
|
+
if (rawAvatar !== undefined && rawAvatar !== null) {
|
|
292
|
+
if (typeof rawAvatar !== 'string') {
|
|
293
|
+
errors.push('agent.md frontmatter avatar must be a string');
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const length = codePointLength(rawAvatar);
|
|
297
|
+
if (length > AGENT_AVATAR_MAX_LENGTH) {
|
|
298
|
+
errors.push(`agent.md frontmatter avatar must be at most ${AGENT_AVATAR_MAX_LENGTH} characters (current: ${length})`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
197
301
|
}
|
|
198
302
|
if (values.tags !== undefined) {
|
|
199
303
|
const tagErrors = validateAgentTags(values.tags);
|
|
@@ -281,10 +385,10 @@ function verifyLocal(store, aid, content) {
|
|
|
281
385
|
}
|
|
282
386
|
}
|
|
283
387
|
export async function agentmdGet(aid, opts) {
|
|
284
|
-
const aunPath = opts
|
|
388
|
+
const aunPath = resolveAgentMdAunPath(opts);
|
|
285
389
|
const store = opts?.store ?? await getAidStore({ slotId: SLOT.cli, aunPath });
|
|
286
390
|
const ownStore = !opts?.store;
|
|
287
|
-
const localPath = agentMdPath(aid);
|
|
391
|
+
const localPath = agentMdPath(aid, aunPath);
|
|
288
392
|
try {
|
|
289
393
|
let content;
|
|
290
394
|
let verification;
|
|
@@ -294,6 +398,14 @@ export async function agentmdGet(aid, opts) {
|
|
|
294
398
|
verification = normalizeVerification(r.data.verification);
|
|
295
399
|
}
|
|
296
400
|
else {
|
|
401
|
+
if (opts?.remoteOnly) {
|
|
402
|
+
const code = String(r.error?.code ?? '');
|
|
403
|
+
const message = String(r.error?.message ?? r.error);
|
|
404
|
+
if (code === 'AGENTMD_NOT_FOUND' || /not found|404|missing/i.test(message)) {
|
|
405
|
+
throw Object.assign(new Error(`agent.md not found for ${aid}`), { code: 'AGENTMD_NOT_FOUND' });
|
|
406
|
+
}
|
|
407
|
+
throw new Error(`Remote agent.md verification unavailable for ${aid}`);
|
|
408
|
+
}
|
|
297
409
|
// Network/fetch failed — fall back to local file.
|
|
298
410
|
if (!fs.existsSync(localPath)) {
|
|
299
411
|
throw new Error(`fetch agent.md failed for ${aid}: ${r.error.message}`);
|
|
@@ -326,10 +438,10 @@ export async function agentmdPut(content, opts) {
|
|
|
326
438
|
if (!validation.valid) {
|
|
327
439
|
throw new Error(`invalid agent.md frontmatter: ${validation.errors.join('; ')}`);
|
|
328
440
|
}
|
|
329
|
-
const aunPath = opts
|
|
441
|
+
const aunPath = resolveAgentMdAunPath(opts);
|
|
330
442
|
const store = opts.store ?? await getAidStore({ slotId: SLOT.cli, aunPath });
|
|
331
443
|
const ownStore = !opts.store;
|
|
332
|
-
const dir = aidLocalDir(opts.aid);
|
|
444
|
+
const dir = aidLocalDir(opts.aid, aunPath);
|
|
333
445
|
const filePath = path.join(dir, 'agent.md');
|
|
334
446
|
const existed = fs.existsSync(filePath);
|
|
335
447
|
// 先写本地文件(与旧行为一致:本地内容更新应在上传失败时仍保留)
|
|
@@ -370,10 +482,10 @@ export async function agentmdPut(content, opts) {
|
|
|
370
482
|
* so a freshly-built store reports local_found=false and will fetch.
|
|
371
483
|
*/
|
|
372
484
|
export async function agentmdSync(aid, opts) {
|
|
373
|
-
const aunPath = opts
|
|
485
|
+
const aunPath = resolveAgentMdAunPath(opts);
|
|
374
486
|
const store = opts?.store ?? await getAidStore({ slotId: SLOT.cli, aunPath });
|
|
375
487
|
const ownStore = !opts?.store;
|
|
376
|
-
const localPath = agentMdPath(aid);
|
|
488
|
+
const localPath = agentMdPath(aid, aunPath);
|
|
377
489
|
try {
|
|
378
490
|
// AIDStore owns the agent.md consistency API in fastaun 0.5.x. Keep this
|
|
379
491
|
// runtime guard because callers and test doubles can still accidentally
|
|
@@ -382,9 +494,11 @@ export async function agentmdSync(aid, opts) {
|
|
|
382
494
|
if (typeof candidate.checkAgentMd !== 'function' || typeof candidate.downloadAgentMd !== 'function') {
|
|
383
495
|
throw new TypeError('invalid AIDStore: checkAgentMd/downloadAgentMd unavailable');
|
|
384
496
|
}
|
|
385
|
-
|
|
497
|
+
// A change event can describe Last-Modified alone. Bypass the SDK's
|
|
498
|
+
// independent freshness cache when Core knows its snapshot is stale.
|
|
499
|
+
const check = opts?.forceRefresh ? undefined : await store.checkAgentMd(aid, opts?.ttlDays ?? 30);
|
|
386
500
|
// In sync (cache fresh) — return local file content with cached verification status.
|
|
387
|
-
if (check
|
|
501
|
+
if (check?.ok && !check.data.needs_update && check.data.local_found) {
|
|
388
502
|
const content = fs.existsSync(localPath) ? fs.readFileSync(localPath, 'utf-8') : undefined;
|
|
389
503
|
const verification = check.data.verify_status
|
|
390
504
|
? normalizeVerification({ status: check.data.verify_status, reason: check.data.verify_error || undefined })
|
|
@@ -395,6 +509,7 @@ export async function agentmdSync(aid, opts) {
|
|
|
395
509
|
// SDK's downloadAgentMd persists to disk internally (AgentMdManager.saveRecord → writeContent).
|
|
396
510
|
const fetched = await store.downloadAgentMd(aid);
|
|
397
511
|
if (fetched.ok) {
|
|
512
|
+
invalidateAgentDisplayName(aid);
|
|
398
513
|
return { changed: true, content: fetched.data.content, verification: normalizeVerification(fetched.data.verification) };
|
|
399
514
|
}
|
|
400
515
|
// Fetch failed (network) — fall back to local file if present.
|
package/dist/aun/aid/client.js
CHANGED
|
@@ -39,7 +39,7 @@ export function suppressSdkLogs() {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
// ==================== SDK package ====================
|
|
42
|
-
export const MIN_AUN_CORE_SDK = [0, 5,
|
|
42
|
+
export const MIN_AUN_CORE_SDK = [0, 5, 17];
|
|
43
43
|
export const AUN_CORE_SDK_PKG = '@agentunion/fastaun';
|
|
44
44
|
function compareVersion(a, min) {
|
|
45
45
|
const parts = a.split('.').map(n => parseInt(n, 10));
|
|
@@ -1,10 +1,183 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { parseDocument } from 'yaml';
|
|
2
5
|
import { aidCreate } from './index.js';
|
|
3
6
|
import { DEFAULT_AID_DOMAIN, normalizeAidDomain } from './domain.js';
|
|
4
7
|
import { getAidStore, SLOT } from './store.js';
|
|
8
|
+
import { validateAgentMdDocument, verifyAgentMdUpload } from '@agentunion/fastaun';
|
|
9
|
+
import { agentMdPath, resolvePaths } from '../../paths.js';
|
|
10
|
+
import { PeerIdentityCache } from '../../core/relation/peer-identity.js';
|
|
11
|
+
import { agentmdPut, buildInitialAgentMd, invalidateAgentDisplayName, stripAgentMdSignature } from './agentmd.js';
|
|
5
12
|
import { logger } from '../../utils/logger.js';
|
|
6
13
|
const MAX_ATTEMPTS = 5;
|
|
7
14
|
export { DEFAULT_AID_DOMAIN } from './domain.js';
|
|
15
|
+
/** Human-facing platform label used in the control AID's agent.md name. */
|
|
16
|
+
export function controlHostPlatformLabel(platform = process.platform) {
|
|
17
|
+
switch (String(platform).trim().toLowerCase()) {
|
|
18
|
+
case 'win32':
|
|
19
|
+
case 'windows':
|
|
20
|
+
return 'Win';
|
|
21
|
+
case 'linux':
|
|
22
|
+
return 'Linux';
|
|
23
|
+
case 'darwin':
|
|
24
|
+
case 'macos':
|
|
25
|
+
case 'mac':
|
|
26
|
+
return 'MacOS';
|
|
27
|
+
default: {
|
|
28
|
+
const value = String(platform).trim();
|
|
29
|
+
return value ? `${value[0].toUpperCase()}${value.slice(1)}` : 'Host';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Build the stable display name for a daemon/control AID. */
|
|
34
|
+
export function buildControlAgentName(aid, platform = process.platform) {
|
|
35
|
+
const normalized = String(aid ?? '').trim().replace(/^@/, '');
|
|
36
|
+
const prefix = normalized.split('.', 1)[0] || normalized || 'unknown';
|
|
37
|
+
return `${controlHostPlatformLabel(platform)}主机-${prefix}`;
|
|
38
|
+
}
|
|
39
|
+
const CONTROL_AGENT_DESCRIPTION = 'EvolCore daemon host.';
|
|
40
|
+
const CONTROL_AGENT_TAGS = ['evolcore', 'control', 'host'];
|
|
41
|
+
const controlAgentMdPending = new Map();
|
|
42
|
+
function readJsonFile(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
const value = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
45
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
46
|
+
? value
|
|
47
|
+
: undefined;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function hasCanonicalControlFrontmatter(content, aid, name, aunRoot) {
|
|
54
|
+
try {
|
|
55
|
+
// A frontmatter-only match is insufficient here: an unsigned or malformed
|
|
56
|
+
// local card must be republished so the SDK can produce a valid signature.
|
|
57
|
+
validateAgentMdDocument(content, { expectedAid: aid, requireSignature: true });
|
|
58
|
+
const payload = stripAgentMdSignature(content);
|
|
59
|
+
const frontmatter = payload.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
60
|
+
if (!frontmatter)
|
|
61
|
+
return false;
|
|
62
|
+
const document = parseDocument(frontmatter);
|
|
63
|
+
if (document.errors.length > 0)
|
|
64
|
+
return false;
|
|
65
|
+
const fields = document.toJS();
|
|
66
|
+
if (!fields || typeof fields !== 'object' || Array.isArray(fields))
|
|
67
|
+
return false;
|
|
68
|
+
const values = fields;
|
|
69
|
+
const canonical = typeof values.aid === 'string'
|
|
70
|
+
&& values.aid.trim().toLowerCase() === aid.toLowerCase()
|
|
71
|
+
&& typeof values.name === 'string'
|
|
72
|
+
&& values.name.trim() === name
|
|
73
|
+
&& typeof values.type === 'string'
|
|
74
|
+
&& values.type.trim().toLowerCase() === 'host';
|
|
75
|
+
if (!canonical)
|
|
76
|
+
return false;
|
|
77
|
+
// The SDK validator checks that a signature block is well formed, but it
|
|
78
|
+
// deliberately does not verify the signature against the local cert.
|
|
79
|
+
// A damaged or stale control card must be republished, otherwise peers
|
|
80
|
+
// continue to reject it even though the frontmatter looks canonical.
|
|
81
|
+
const certPath = path.join(aunRoot, 'AIDs', aid, 'public', 'cert.pem');
|
|
82
|
+
const certPem = fs.readFileSync(certPath, 'utf8');
|
|
83
|
+
verifyAgentMdUpload(content, certPem, aid);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function clearControlAgentPeerCaches(aid, root = resolvePaths().root) {
|
|
91
|
+
const agentsDir = path.join(root, 'agents');
|
|
92
|
+
// A first-run installation may not have created any EvolCore agent yet.
|
|
93
|
+
// There is no cache to clear in that state, and ENOENT is not a warning.
|
|
94
|
+
if (!fs.existsSync(agentsDir))
|
|
95
|
+
return;
|
|
96
|
+
try {
|
|
97
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
98
|
+
if (!entry.isDirectory())
|
|
99
|
+
continue;
|
|
100
|
+
PeerIdentityCache.clear('aun', aid, path.join(agentsDir, entry.name));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
logger.warn(`[control-aid] 清理旧身份缓存失败(不影响名片发布): ${error instanceof Error ? error.message : String(error)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Ensure a daemon/control AID has a signed host agent.md.
|
|
109
|
+
*
|
|
110
|
+
* Registration in fastaun creates a default `type: agent` card. This helper
|
|
111
|
+
* upgrades that card, supplements cards missing on older installations, and
|
|
112
|
+
* is idempotent once the local card is canonical. Upload errors are allowed to
|
|
113
|
+
* propagate to the caller so startup can log them without becoming blocked.
|
|
114
|
+
*/
|
|
115
|
+
export async function ensureControlAgentMd(aid, opts = {}) {
|
|
116
|
+
const normalizedAid = String(aid ?? '').trim().replace(/^@/, '');
|
|
117
|
+
if (!normalizedAid)
|
|
118
|
+
throw new Error('control AID is required');
|
|
119
|
+
const aunRoot = opts.aunPath ?? opts.store?.aunPath ?? resolvePaths().root;
|
|
120
|
+
const cacheRoot = opts.cacheRoot ?? resolvePaths().root;
|
|
121
|
+
const pendingKey = path.resolve(aunRoot) + '\u0000' + normalizedAid.toLowerCase();
|
|
122
|
+
const pending = controlAgentMdPending.get(pendingKey);
|
|
123
|
+
if (pending)
|
|
124
|
+
return pending;
|
|
125
|
+
const run = (async () => {
|
|
126
|
+
const name = buildControlAgentName(normalizedAid, opts.platform);
|
|
127
|
+
const localPath = agentMdPath(normalizedAid, aunRoot);
|
|
128
|
+
const metadataPath = path.join(path.dirname(localPath), 'agentmd.json');
|
|
129
|
+
let existing;
|
|
130
|
+
try {
|
|
131
|
+
existing = fs.readFileSync(localPath, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
catch { /* missing */ }
|
|
134
|
+
const metadata = readJsonFile(metadataPath);
|
|
135
|
+
const remoteMissing = String(metadata?.remote_status ?? '').trim().toLowerCase() === 'missing';
|
|
136
|
+
const needsPublish = !existing || !hasCanonicalControlFrontmatter(existing, normalizedAid, name, aunRoot) || remoteMissing;
|
|
137
|
+
if (!needsPublish)
|
|
138
|
+
return { aid: normalizedAid, name, published: false };
|
|
139
|
+
const content = buildInitialAgentMd({
|
|
140
|
+
aid: normalizedAid,
|
|
141
|
+
name,
|
|
142
|
+
type: 'host',
|
|
143
|
+
description: CONTROL_AGENT_DESCRIPTION,
|
|
144
|
+
tags: CONTROL_AGENT_TAGS,
|
|
145
|
+
});
|
|
146
|
+
try {
|
|
147
|
+
await agentmdPut(content, { aid: normalizedAid, store: opts.store, aunPath: aunRoot });
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
// agentmdPut intentionally keeps edits to an existing card on failure;
|
|
151
|
+
// a control-card migration must restore the old card so a transient
|
|
152
|
+
// gateway failure cannot make the local state look successfully migrated.
|
|
153
|
+
try {
|
|
154
|
+
if (existing !== undefined) {
|
|
155
|
+
fs.mkdirSync(path.dirname(localPath), { recursive: true });
|
|
156
|
+
fs.writeFileSync(localPath, existing, 'utf8');
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
fs.unlinkSync(localPath);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch { /* preserve the original upload error */ }
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
// The upload changes the control AID's display name. Drop the process-wide
|
|
166
|
+
// name cache so subsequent context/status rendering cannot keep the legacy
|
|
167
|
+
// `agent` name until the normal TTL refresh.
|
|
168
|
+
invalidateAgentDisplayName(normalizedAid);
|
|
169
|
+
clearControlAgentPeerCaches(normalizedAid, cacheRoot);
|
|
170
|
+
return { aid: normalizedAid, name, published: true };
|
|
171
|
+
})();
|
|
172
|
+
controlAgentMdPending.set(pendingKey, run);
|
|
173
|
+
try {
|
|
174
|
+
return await run;
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
if (controlAgentMdPending.get(pendingKey) === run)
|
|
178
|
+
controlAgentMdPending.delete(pendingKey);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
8
181
|
function environmentValue(name) {
|
|
9
182
|
if (!Object.prototype.hasOwnProperty.call(process.env, name))
|
|
10
183
|
return undefined;
|
|
@@ -66,7 +239,7 @@ async function candidateExists(store, candidate) {
|
|
|
66
239
|
* 查重通过但注册失败时也换候选重试,覆盖查重与注册之间的竞态。
|
|
67
240
|
* - 查重走 GET 证书(见 candidateExists;不拉 agent.md,控制 AID 本就不传 agent.md)
|
|
68
241
|
* - fail-fast:查重探测失败(网关不可达)立即抛错,不掩盖成"均冲突"
|
|
69
|
-
* - agent.md
|
|
242
|
+
* - 注册后补发控制主机 agent.md;失败只告警,不丢弃已经注册的 AID
|
|
70
243
|
*/
|
|
71
244
|
export async function generateControlAid(aidDomain) {
|
|
72
245
|
const finalAidDomain = aidDomain === undefined
|
|
@@ -83,6 +256,12 @@ export async function generateControlAid(aidDomain) {
|
|
|
83
256
|
}
|
|
84
257
|
try {
|
|
85
258
|
const created = await aidCreate(candidate);
|
|
259
|
+
try {
|
|
260
|
+
await ensureControlAgentMd(created.aid, { store: created.store });
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
logger.warn(`[control-aid] ${created.aid} agent.md 发布失败(控制面可继续,后续启动会重试): ${e instanceof Error ? e.message : String(e)}`);
|
|
264
|
+
}
|
|
86
265
|
// 清理 aidCreate 内部另开的 client/store——关闭失败不可丢弃已注册的 AID(否则下次 init
|
|
87
266
|
// 会把它当冲突,白白消耗一次重试)。close 异常降级为 warn。
|
|
88
267
|
try {
|
package/dist/aun/aid/identity.js
CHANGED
|
@@ -76,7 +76,7 @@ export function aidList(aunPath) {
|
|
|
76
76
|
canSign: hasPrivateKey && hasCert && !certExpired && keyMatchesCert === true,
|
|
77
77
|
}),
|
|
78
78
|
hasPrivateKey,
|
|
79
|
-
hasAgentMd: fs.existsSync(agentMdPath(e.name)),
|
|
79
|
+
hasAgentMd: fs.existsSync(agentMdPath(e.name, root)),
|
|
80
80
|
hasCert,
|
|
81
81
|
certExpired,
|
|
82
82
|
keyMatchesCert,
|
|
@@ -114,7 +114,7 @@ export async function verifySignAbility(aid, opts) {
|
|
|
114
114
|
// signAgentMd validates the same frontmatter contract as a published agent.md.
|
|
115
115
|
// Keep the probe minimal, but make it a valid document so self-checks do not
|
|
116
116
|
// reject otherwise healthy identities before exercising sign + verify.
|
|
117
|
-
const probe = `---\naid: "${aid}"\nname: "probe"\ntype: "
|
|
117
|
+
const probe = `---\naid: "${aid}"\nname: "probe"\ntype: "agent"\nversion: "1.0.0"\ndescription: "Local signing self-check"\ntags:\n - evolcore\n---\n`;
|
|
118
118
|
const signRes = aidObj.signAgentMd(probe);
|
|
119
119
|
if (!signRes.ok) {
|
|
120
120
|
return { ok: false, reason: `sign failed: ${String(signRes.error?.message || signRes.error?.code).slice(0, 120)}` };
|
|
@@ -265,7 +265,7 @@ export async function aidShow(aid, opts) {
|
|
|
265
265
|
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
266
266
|
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
267
267
|
const hasPrivateKey = fs.existsSync(path.join(aidDir, 'private'));
|
|
268
|
-
const hasAgentMd = fs.existsSync(agentMdPath(aid));
|
|
268
|
+
const hasAgentMd = fs.existsSync(agentMdPath(aid, aunPath));
|
|
269
269
|
let certExpiresAt = null;
|
|
270
270
|
let certSubject = null;
|
|
271
271
|
let certExpired = false;
|
|
@@ -323,7 +323,7 @@ export async function aidShow(aid, opts) {
|
|
|
323
323
|
}
|
|
324
324
|
if (hasAgentMd) {
|
|
325
325
|
try {
|
|
326
|
-
const content = fs.readFileSync(agentMdPath(aid), 'utf-8');
|
|
326
|
+
const content = fs.readFileSync(agentMdPath(aid, aunPath), 'utf-8');
|
|
327
327
|
if (!content.includes('AUN-SIGNATURE')) {
|
|
328
328
|
agentMdSignature = 'unsigned';
|
|
329
329
|
}
|
package/dist/aun/aid/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AGENT_TAG_MIN_COUNT, AGENT_TAG_MAX_COUNT, AGENT_TAG_MAX_LENGTH, validateAgentTag, validateAgentTags, } from './agentmd.js';
|
|
2
2
|
export { isValidAid, aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, verifySignAbility, probePkiRecoverability, appendAidLifecycle, readAidLifecycle } from './identity.js';
|
|
3
|
-
export { DEFAULT_AGENT_DESCRIPTION, buildInitialAgentMd, validateAgentMdFrontmatter, agentmdGet, agentmdPut, agentmdSync, invalidateAgentDisplayName, parseAgentDisplayName, refreshAgentDisplayName, resolveAgentDisplayName, stripAgentMdSignature, updateAgentMdFrontmatterAvatar, updateAgentMdFrontmatterName, } from './agentmd.js';
|
|
3
|
+
export { AGENT_TYPES, DEFAULT_AGENT_DESCRIPTION, DEFAULT_AGENT_TYPE, normalizeAgentType, validateAgentType, buildInitialAgentMd, validateAgentMdFrontmatter, agentmdGet, agentmdPut, agentmdSync, invalidateAgentDisplayName, parseAgentDisplayName, refreshAgentDisplayName, resolveAgentDisplayName, stripAgentMdSignature, updateAgentMdFrontmatterAvatar, updateAgentMdFrontmatterName, } from './agentmd.js';
|
|
4
4
|
export { MIN_AUN_CORE_SDK, AUN_CORE_SDK_PKG, isAunSdkVersionOk, resolveAunCoreSdkPkg, ensureAunSdk, isAunSdkReady, downloadCaRoot, suppressSdkLogs, } from './client.js';
|
|
5
5
|
export { getAidStore, loadClient, loadAid, AidLoadError, SLOT } from './store.js';
|
package/dist/aun/aid/store.js
CHANGED
|
@@ -80,10 +80,10 @@ export async function loadClient(store, aid) {
|
|
|
80
80
|
/**
|
|
81
81
|
* Enable bounded multi-page group pulls for the long-lived daemon client.
|
|
82
82
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
83
|
+
* Older SDK recovery paths used `maxPages=1`; for a daemon that can strand a
|
|
84
|
+
* backlog after a tail sync. SDK 0.5.15 normally chooses a larger recovery
|
|
85
|
+
* window, but this adapter still expands an explicit single-page request and
|
|
86
|
+
* keeps older clients safe. It is isolated to the client that opts in.
|
|
87
87
|
*/
|
|
88
88
|
export function enableFullGroupPullPagination(client) {
|
|
89
89
|
const target = client;
|
|
@@ -110,13 +110,12 @@ export function enableFullGroupPullPagination(client) {
|
|
|
110
110
|
/**
|
|
111
111
|
* Make SDK pull delivery wait until EvolCore's application handlers finish.
|
|
112
112
|
*
|
|
113
|
-
* fastaun
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* message events before the pull operation commits the sequence.
|
|
113
|
+
* fastaun publishes message events asynchronously, while the sequence tracker
|
|
114
|
+
* is a transport watermark. A daemon restart can therefore acknowledge a
|
|
115
|
+
* pulled message before the application has durably claimed it. SDK 0.5.15
|
|
116
|
+
* split protocol and application queues; prefer its application-only flush so
|
|
117
|
+
* an unrelated protocol event cannot delay the pull commit. Older SDKs fall
|
|
118
|
+
* back to the combined flush method.
|
|
120
119
|
*/
|
|
121
120
|
export function enableReliableMessageDelivery(client) {
|
|
122
121
|
const target = client;
|
|
@@ -124,7 +123,12 @@ export function enableReliableMessageDelivery(client) {
|
|
|
124
123
|
return false;
|
|
125
124
|
const publish = target._publishAppEvent;
|
|
126
125
|
const dispatcher = target._dispatcher;
|
|
127
|
-
|
|
126
|
+
const flushApplication = typeof dispatcher?.flushApplication === 'function'
|
|
127
|
+
? dispatcher.flushApplication.bind(dispatcher)
|
|
128
|
+
: typeof dispatcher?.flush === 'function'
|
|
129
|
+
? dispatcher.flush.bind(dispatcher)
|
|
130
|
+
: undefined;
|
|
131
|
+
if (typeof publish !== 'function' || !flushApplication)
|
|
128
132
|
return false;
|
|
129
133
|
const wrappedPublish = async function (event, payload, source, ...rest) {
|
|
130
134
|
const result = await publish.call(this, event, payload, source, ...rest);
|
|
@@ -135,7 +139,7 @@ export function enableReliableMessageDelivery(client) {
|
|
|
135
139
|
&& source !== 'push'
|
|
136
140
|
&& source !== 'inline-push';
|
|
137
141
|
if (reliable)
|
|
138
|
-
await
|
|
142
|
+
await flushApplication();
|
|
139
143
|
return result;
|
|
140
144
|
};
|
|
141
145
|
Object.defineProperty(target, RELIABLE_MESSAGE_DELIVERY_PATCH, {
|