@agentunion/fastaun 0.5.28 → 0.5.30

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.
Files changed (101) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/_packed_docs/CHANGELOG.md +41 -0
  3. package/_packed_docs/INDEX.md +20 -6
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +14 -11
  5. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +18 -1
  6. package/_packed_docs/cli//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241CLI/345/274/200/345/217/221/344/270/216/344/275/277/347/224/250/346/214/207/345/215/227.md +869 -0
  7. package/_packed_docs/sdk/0.5.27-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +408 -0
  8. package/_packed_docs/sdk/0.5.27-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +410 -0
  9. package/_packed_docs/sdk/0.5.28-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +228 -0
  10. package/_packed_docs/sdk/0.5.28-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +146 -0
  11. package/_packed_docs/sdk/0.5.29-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +180 -0
  12. package/_packed_docs/sdk/0.5.29-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +164 -0
  13. package/_packed_docs/sdk/0.5.30-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +61 -0
  14. package/_packed_docs/sdk/0.5.30-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +68 -0
  15. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +90 -90
  16. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +7 -3
  17. package/_packed_docs/sdk/INDEX.md +20 -4
  18. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +1 -1
  19. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +1 -1
  20. package/_packed_docs//346/216/247/345/210/266/346/266/210/346/201/257/344/270/216/350/256/276/345/244/207/350/203/275/345/212/233/345/215/217/345/225/206/346/226/271/346/241/210.md +426 -0
  21. package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +279 -229
  22. package/_packed_docs//351/231/214/347/224/237/344/272/272/346/213/222/347/273/235/345/215/217/350/256/256TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +138 -0
  23. package/_packed_docs//351/231/214/347/224/237/344/272/272/346/213/222/347/273/235/345/215/217/350/256/256/350/257/246/347/273/206/350/256/276/350/256/241.md +231 -0
  24. package/_packed_docs//351/243/216/346/216/247/345/223/215/345/272/224/344/270/216SDK/345/215/217/345/220/214/346/226/271/346/241/210.md +381 -0
  25. package/dist/agent-md-changes.d.ts +2 -14
  26. package/dist/agent-md-changes.js +41 -212
  27. package/dist/agent-md-changes.js.map +1 -1
  28. package/dist/agent-md-schema.js +2 -2
  29. package/dist/agent-md-schema.js.map +1 -1
  30. package/dist/agent-md.d.ts +4 -6
  31. package/dist/agent-md.js +66 -57
  32. package/dist/agent-md.js.map +1 -1
  33. package/dist/aid-store.d.ts +3 -1
  34. package/dist/aid-store.js +65 -42
  35. package/dist/aid-store.js.map +1 -1
  36. package/dist/client/control-messages.d.ts +0 -1
  37. package/dist/client/control-messages.js +90 -70
  38. package/dist/client/control-messages.js.map +1 -1
  39. package/dist/client/delivery.js +2 -1
  40. package/dist/client/delivery.js.map +1 -1
  41. package/dist/client/group-state.js +2 -3
  42. package/dist/client/group-state.js.map +1 -1
  43. package/dist/client/lifecycle.js +0 -2
  44. package/dist/client/lifecycle.js.map +1 -1
  45. package/dist/client/rpc-pipeline.js +8 -0
  46. package/dist/client/rpc-pipeline.js.map +1 -1
  47. package/dist/client/v2-e2ee.js +15 -11
  48. package/dist/client/v2-e2ee.js.map +1 -1
  49. package/dist/client.d.ts +2 -2
  50. package/dist/client.js +101 -51
  51. package/dist/client.js.map +1 -1
  52. package/dist/config.js +23 -18
  53. package/dist/config.js.map +1 -1
  54. package/dist/discovery.js +2 -1
  55. package/dist/discovery.js.map +1 -1
  56. package/dist/facades.d.ts +20 -0
  57. package/dist/facades.js +9 -0
  58. package/dist/facades.js.map +1 -1
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/keystore/aid-db.js +14 -2
  62. package/dist/keystore/aid-db.js.map +1 -1
  63. package/dist/keystore/index.d.ts +3 -0
  64. package/dist/keystore/index.js +61 -1
  65. package/dist/keystore/index.js.map +1 -1
  66. package/dist/keystore/local-identity-store.js +112 -76
  67. package/dist/keystore/local-identity-store.js.map +1 -1
  68. package/dist/keystore/local-token-store.js +15 -26
  69. package/dist/keystore/local-token-store.js.map +1 -1
  70. package/dist/ownership-v21.d.ts +2 -1
  71. package/dist/ownership-v21.js +17 -3
  72. package/dist/ownership-v21.js.map +1 -1
  73. package/dist/ownership-workflow.js +13 -8
  74. package/dist/ownership-workflow.js.map +1 -1
  75. package/dist/register-flow.js +3 -2
  76. package/dist/register-flow.js.map +1 -1
  77. package/dist/risk-control.js +2 -2
  78. package/dist/risk-control.js.map +1 -1
  79. package/dist/secret-store/file-store.js +68 -56
  80. package/dist/secret-store/file-store.js.map +1 -1
  81. package/dist/semantic-facade.js +4 -2
  82. package/dist/semantic-facade.js.map +1 -1
  83. package/dist/semantic-protocol.d.ts +2 -12
  84. package/dist/semantic-protocol.js +33 -48
  85. package/dist/semantic-protocol.js.map +1 -1
  86. package/dist/storage/lowlevel.d.ts +4 -0
  87. package/dist/storage/lowlevel.js +58 -1
  88. package/dist/storage/lowlevel.js.map +1 -1
  89. package/dist/storage/vfs.d.ts +4 -0
  90. package/dist/storage/vfs.js +57 -12
  91. package/dist/storage/vfs.js.map +1 -1
  92. package/dist/tools/cross-sdk-agent.d.ts +1 -1
  93. package/dist/tools/cross-sdk-agent.js +26 -35
  94. package/dist/tools/cross-sdk-agent.js.map +1 -1
  95. package/dist/transport.js +1 -1
  96. package/dist/transport.js.map +1 -1
  97. package/dist/validators.js +9 -8
  98. package/dist/validators.js.map +1 -1
  99. package/dist/version.d.ts +1 -1
  100. package/dist/version.js +1 -1
  101. package/package.json +8 -8
package/dist/client.d.ts CHANGED
@@ -89,6 +89,7 @@ export declare class AUNClient {
89
89
  private _ownershipStorage;
90
90
  private _ownershipFiles;
91
91
  private _ownershipWorkflow;
92
+ private _ownershipConsensusCache;
92
93
  private _getOwnershipStorage;
93
94
  private _getOwnershipFiles;
94
95
  private _createOwnershipFiles;
@@ -210,7 +211,6 @@ export declare class AUNClient {
210
211
  private _v2RuntimeGeneration;
211
212
  private _controlMessageCoordinator?;
212
213
  private _agentMdChanges?;
213
- private _agentMdCommitUnsubscribe?;
214
214
  private _installAgentMdChangeHooks;
215
215
  private _getAgentMdChanges;
216
216
  private _onSdkControl;
@@ -302,7 +302,7 @@ export declare class AUNClient {
302
302
  private _localOwnershipOperation;
303
303
  releaseSubaid(subAid: string): Promise<OwnershipTaskResult>;
304
304
  transferSubaid(subAid: string, newOwnerAid: string): Promise<OwnershipTaskResult>;
305
- checkOwnershipConsensus(subAid?: string): Promise<OwnershipConsensusResult>;
305
+ checkOwnershipConsensus(subAid?: string, force?: boolean): Promise<OwnershipConsensusResult>;
306
306
  private _checkOwnershipConsensusFresh;
307
307
  bindAid(subjectAid: string, options?: {
308
308
  subjectType?: string;
package/dist/client.js CHANGED
@@ -51,7 +51,7 @@ import { isJsonObject, ConnectionState, STATE_TO_PUBLIC, } from './types.js';
51
51
  import { AID } from './aid.js';
52
52
  import { certFingerprint, certMatchesFingerprint, normalizeFingerprintHex, publicKeyMatchesFingerprint } from './cert-utils.js';
53
53
  import { validateAgentMdCertificate, validateAgentMdDocument } from './agent-md-schema.js';
54
- import { OwnershipFiles, OwnershipStorageAdapter, ownershipAid, ownershipFailure } from './ownership-v21.js';
54
+ import { OwnershipFiles, OwnershipStorageAdapter, ownershipAid, ownershipFailure, ownershipSha256, parseOwnershipFile } from './ownership-v21.js';
55
55
  import { OwnershipWorkflow, OWNERSHIP_SDK_MESSAGE_TYPE, parseOwnershipMessage } from './ownership-workflow.js';
56
56
  import { canonicalJson, createCredential, createMemberCredential, signMembershipBinding, digest, validateMembershipBinding, verifyMembershipBinding, verifyCredentialSignature, createRepresentationProof, verifyServiceEvent, buildRequestBinding, validateRequestBinding, CredentialRenewal } from './org-protocol.js';
57
57
  import { SemanticProtocolError } from './semantic-protocol.js';
@@ -345,7 +345,7 @@ function createAgentMdManagerForRuntime(opts) {
345
345
  return new AgentMdManager({
346
346
  aunPath: opts.config().aunPath,
347
347
  verifySsl: opts.config().verifySsl,
348
- onChanged: (aid) => opts.dispatcher().enqueue('agentmd.changed', aid),
348
+ onChanged: (aid) => opts.dispatcher().enqueue('agentmd.changed', { aid }),
349
349
  discoveryPort: opts.config().discoveryPort,
350
350
  uploadViaGatewayHost: true,
351
351
  logger: opts.logger(),
@@ -489,6 +489,7 @@ export class AUNClient {
489
489
  _ownershipStorage = null;
490
490
  _ownershipFiles = null;
491
491
  _ownershipWorkflow = null;
492
+ _ownershipConsensusCache = new Map();
492
493
  _getOwnershipStorage() {
493
494
  return this._ownershipStorage ??= new OwnershipStorageAdapter({ currentAid: () => this._aid, call: (method, params) => this.call(method, params), httpPut: (url, data, headers) => this.storage.lowlevel.httpPut(url, data, headers) });
494
495
  }
@@ -500,6 +501,10 @@ export class AUNClient {
500
501
  currentAid: () => { if (!this._currentAid)
501
502
  throw ownershipFailure('forbidden', 'ownership requires a loaded identity'); return this._currentAid; },
502
503
  currentType: () => this.getType(),
504
+ currentExttype: () => {
505
+ const metadata = this._tokenStore.loadMetadata?.(String(this._aid ?? ''));
506
+ return String(metadata?.identity_exttype ?? metadata?.registration_intent?.exttype ?? '');
507
+ },
503
508
  now: () => Math.trunc(Date.now() / 1000),
504
509
  readAgentMdFresh,
505
510
  submitAgentMdRaw: (subAid, raw, condition, assertActive, stage) => this._agentMdManager.submitOwnershipRaw(subAid, raw, condition, assertActive, stage),
@@ -515,40 +520,59 @@ export class AUNClient {
515
520
  currentType: () => this.getType(), assertCurrent: () => this._ownershipOperationGuard?.(),
516
521
  recoverRequest: (operationId) => this._recoverOwnershipRequest(operationId),
517
522
  send: (to, payload, messageId) => this.call('message.send', { to, encrypt: true, message_id: messageId, payload: payload }),
518
- emit: (event, payload) => this._dispatcher.enqueue(event, payload),
523
+ emit: (event, payload) => { this._ownershipConsensusCache = new Map(); this._dispatcher.enqueue(event, payload); },
519
524
  });
520
525
  }
521
526
  async _recoverOwnershipRequest(operationId) {
522
527
  const identity = this._aid, version = this._serviceEventIdentityVersion;
523
528
  const current = () => { if (this._aid !== identity || this._serviceEventIdentityVersion !== version)
524
529
  throw ownershipFailure('conflict', 'ownership request identity changed'); };
525
- const catalog = await this.call('message.peers', { filter: 'all', limit: 200 });
526
- current();
527
- for (const peer of Array.isArray(catalog.peers) ? catalog.peers.slice(0, 200) : []) {
528
- const sender = String(peer.sender_aid ?? '');
529
- const history = await this.call('message.history', { sender_aid: sender, before_seq: Number.MAX_SAFE_INTEGER, limit: 200 });
530
+ const query = { filter: 'all', limit: 200 }, tokens = new Set();
531
+ for (;;) {
532
+ const catalog = await this.call('message.peers', query);
530
533
  current();
531
- for (const row of Array.isArray(history.messages) ? history.messages : []) {
532
- const envelope = row, content = envelope.payload ?? envelope;
533
- const raw = decryptedOwnershipJsonText(content) ?? content;
534
- let value = raw;
535
- if (typeof raw === 'string') {
536
- try {
537
- value = JSON.parse(raw);
538
- }
539
- catch {
540
- continue;
534
+ for (const peer of Array.isArray(catalog.peers) ? catalog.peers : []) {
535
+ const sender = String(peer.sender_aid ?? ''), head = Number(peer.head_seq);
536
+ const snapshot = Number.isSafeInteger(head) && head > 0 && head < Number.MAX_SAFE_INTEGER ? { snapshot_head_seq: head } : {};
537
+ let before = snapshot.snapshot_head_seq === undefined ? Number.MAX_SAFE_INTEGER : head + 1;
538
+ for (;;) {
539
+ const history = await this.call('message.history', { sender_aid: sender, before_seq: before, ...snapshot, limit: 200 });
540
+ current();
541
+ for (const row of Array.isArray(history.messages) ? history.messages : []) {
542
+ const envelope = row, content = envelope.payload ?? envelope;
543
+ const raw = decryptedOwnershipJsonText(content) ?? content;
544
+ let value = raw;
545
+ if (typeof raw === 'string') {
546
+ try {
547
+ value = JSON.parse(raw);
548
+ }
549
+ catch {
550
+ continue;
551
+ }
552
+ }
553
+ if (!isJsonObject(value) || value.type !== OWNERSHIP_SDK_MESSAGE_TYPE || value.operation_id !== operationId || !['bind.request', 'transfer.request'].includes(String(value.action)))
554
+ continue;
555
+ const authenticated = String(envelope.from_aid ?? envelope.from ?? envelope.sender_aid ?? '');
556
+ if (authenticated !== sender)
557
+ throw ownershipFailure('forbidden', 'ownership history sender changed');
558
+ return { from: authenticated, payload: parseOwnershipMessage(raw, { authenticated_from_aid: authenticated, local_aid: identity }) };
541
559
  }
560
+ if (history.has_older !== true)
561
+ break;
562
+ const next = Number(history.next_before_seq);
563
+ if (!Number.isSafeInteger(next) || next <= 0 || next >= before)
564
+ throw ownershipFailure('unavailable', 'ownership history pagination did not advance');
565
+ before = next;
542
566
  }
543
- if (!isJsonObject(value) || value.type !== OWNERSHIP_SDK_MESSAGE_TYPE || value.operation_id !== operationId || !['bind.request', 'transfer.request'].includes(String(value.action)))
544
- continue;
545
- const authenticated = String(envelope.from_aid ?? envelope.from ?? envelope.sender_aid ?? '');
546
- if (authenticated !== sender)
547
- throw ownershipFailure('forbidden', 'ownership history sender changed');
548
- return { from: authenticated, payload: parseOwnershipMessage(raw, { authenticated_from_aid: authenticated, local_aid: identity }) };
549
567
  }
568
+ if (catalog.has_more !== true)
569
+ return null;
570
+ const token = catalog.next_page_token;
571
+ if (typeof token !== 'string' || !token || tokens.has(token))
572
+ throw ownershipFailure('unavailable', 'peer directory pagination did not advance');
573
+ tokens.add(token);
574
+ query.page_token = token;
550
575
  }
551
- return null;
552
576
  }
553
577
  _restoreIdentityType() {
554
578
  const aid = String(this._aid ?? '').trim();
@@ -934,15 +958,8 @@ export class AUNClient {
934
958
  _v2RuntimeGeneration = 0;
935
959
  _controlMessageCoordinator;
936
960
  _agentMdChanges;
937
- _agentMdCommitUnsubscribe;
938
961
  _installAgentMdChangeHooks() {
939
- this._agentMdCommitUnsubscribe?.();
940
- this._agentMdCommitUnsubscribe = AgentMdManager.subscribeCommits(this._configModel.aunPath, () => {
941
- const coordinator = this._getAgentMdChanges();
942
- if (this._state === 'ready')
943
- void coordinator.flushNotifications().catch((error) => this._clientLog.debug(String(error)));
944
- coordinator.schedule();
945
- });
962
+ this._agentMdManager.setOnCommitted((aid, notice) => this._getAgentMdChanges().committed(aid, notice));
946
963
  }
947
964
  _getAgentMdChanges() {
948
965
  return this._agentMdChanges ??= new AgentMdChangeCoordinator(this);
@@ -1066,6 +1083,7 @@ export class AUNClient {
1066
1083
  this._ownershipStorage = null;
1067
1084
  this._ownershipFiles = null;
1068
1085
  this._ownershipWorkflow = null;
1086
+ this._ownershipConsensusCache = new Map();
1069
1087
  this._slotId = inputAid?.slotId || 'default';
1070
1088
  this._connectDeliveryMode = normalizeDeliveryModeConfig({ mode: 'fanout' });
1071
1089
  this._defaultConnectDeliveryMode = { ...this._connectDeliveryMode };
@@ -1306,12 +1324,12 @@ export class AUNClient {
1306
1324
  }
1307
1325
  async _localOwnershipOperation(sub, next) {
1308
1326
  const sources = [this, sub, ...(next ? [next] : [])];
1309
- if (sources.some((source) => !(source instanceof AUNClient) || !source._currentAid?.isPrivateKeyValid() || !source._currentAid.isCertValid() || !source._currentAid.privateKeyPem || source._currentAid.aid !== source._aid || source.getType() !== 'agent') || new Set(sources.map((source) => source._aid)).size !== sources.length)
1310
- throw ownershipFailure('forbidden', 'local ownership requires distinct agent clients with private identities');
1327
+ if (sources.some((source, index) => !(source instanceof AUNClient) || !source._currentAid?.isPrivateKeyValid() || !source._currentAid.isCertValid() || !source._currentAid.privateKeyPem || source._currentAid.aid !== source._aid || (index === 1 ? source.getType() !== 'agent' : !['human', 'agent'].includes(source.getType()))) || new Set(sources.map((source) => source._aid)).size !== sources.length)
1328
+ throw ownershipFailure('forbidden', 'local ownership requires a distinct agent subaid and human or agent owners with private identities');
1311
1329
  const identities = sources.map((source) => [source._aid, source._currentAid, source._serviceEventIdentityVersion]);
1312
1330
  const guard = () => { if (sources.some((source, index) => source._aid !== identities[index][0] || source._currentAid !== identities[index][1] || source._serviceEventIdentityVersion !== identities[index][2]))
1313
1331
  throw ownershipFailure('conflict', 'local ownership source identity changed'); };
1314
- for (const source of sources) {
1332
+ for (const [index, source] of sources.entries()) {
1315
1333
  guard();
1316
1334
  const document = await source._agentMdManager.readAgentMdFresh(source._aid);
1317
1335
  guard();
@@ -1319,8 +1337,8 @@ export class AUNClient {
1319
1337
  throw ownershipFailure('forbidden', 'local ownership requires a published agent document');
1320
1338
  const verified = await source._getOwnershipFiles().verifyFile(document.content, 'agent', source._aid);
1321
1339
  guard();
1322
- if (verified.frontmatter.type !== 'agent')
1323
- throw ownershipFailure('forbidden', 'local ownership requires verified agent identities');
1340
+ if ((index === 1 ? verified.frontmatter.type !== 'agent' : typeof verified.frontmatter.type !== 'string' || !['human', 'agent'].includes(verified.frontmatter.type)))
1341
+ throw ownershipFailure('forbidden', 'local ownership requires an agent subaid and human or agent owners');
1324
1342
  }
1325
1343
  const slot = `ownership-${crypto.randomUUID()}`, clients = [];
1326
1344
  try {
@@ -1342,13 +1360,48 @@ export class AUNClient {
1342
1360
  }
1343
1361
  async releaseSubaid(subAid) { return this._getOwnershipWorkflow().releaseSubaid(subAid); }
1344
1362
  async transferSubaid(subAid, newOwnerAid) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid); }
1345
- async checkOwnershipConsensus(subAid) {
1363
+ async checkOwnershipConsensus(subAid, force = false) {
1346
1364
  const target = ownershipAid(subAid ?? this._aid, 'sub_aid');
1347
- const result = await this._createOwnershipFiles((aid) => this._agentMdManager._readOwnershipQuery(aid)).checkConsensus(target);
1348
- return result.status === 'consensus' ? result : this._checkOwnershipConsensusFresh(target);
1365
+ const record = this._agentMdManager.loadRecord(target);
1366
+ const observedEtag = String(record?.remote_etag ?? '');
1367
+ const cache = this._ownershipConsensusCache ??= new Map();
1368
+ const cached = cache.get(target);
1369
+ if (!force && cached?.result.status === 'consensus' && record?.remote_status !== 'missing'
1370
+ && (observedEtag === cached.observedEtag || observedEtag === cached.result.agent_md_etag)) {
1371
+ cached.observedEtag = observedEtag;
1372
+ return { ...cached.result };
1373
+ }
1374
+ cache.delete(target);
1375
+ const result = { status: 'unavailable', sub_aid: target, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '' };
1376
+ const entry = { observedEtag, result: { ...result } };
1377
+ cache.set(target, entry);
1378
+ try {
1379
+ const snapshot = await this._agentMdManager.readOwnershipFresh(target);
1380
+ Object.assign(result, { relation_version: snapshot.relation_version, lock: snapshot.lock, agent_md_etag: snapshot.etag,
1381
+ agent_md_sha256: snapshot.exists ? ownershipSha256(snapshot.content) : '' });
1382
+ if (snapshot.ownership_status)
1383
+ result.ownership_status = snapshot.ownership_status;
1384
+ const statement = snapshot.exists ? parseOwnershipFile(snapshot.content, 'agent', { expectedSubAid: target }).statement : undefined;
1385
+ if (snapshot.relation_version !== (statement?.relation_version ?? 0) || snapshot.lock === 'locked' && !statement
1386
+ || snapshot.ownership_status === 'pending' && snapshot.lock !== 'unlocked')
1387
+ throw ownershipFailure('unavailable', 'NS relationship metadata does not match agent.md', true);
1388
+ result.status = snapshot.ownership_status === 'pending' ? 'single_sided' : statement ? snapshot.lock === 'locked' ? 'consensus' : 'released' : 'unbound';
1389
+ result.owner_aid = result.status === 'consensus' ? statement.owner_aid : null;
1390
+ }
1391
+ catch (error) {
1392
+ const code = error instanceof StateError && error.stringCode ? error.stringCode : error instanceof ValidationError ? 'invalid' : 'unavailable';
1393
+ result.status = code === 'not_applicable' ? 'not_applicable' : code === 'invalid' ? 'invalid' : 'unavailable';
1394
+ result.owner_aid = null;
1395
+ result.code = code;
1396
+ result.reason = error instanceof Error ? error.message : String(error);
1397
+ result.retryable = result.status === 'unavailable';
1398
+ }
1399
+ if (cache.get(target) === entry)
1400
+ entry.result = { ...result };
1401
+ return result;
1349
1402
  }
1350
1403
  async _checkOwnershipConsensusFresh(subAid) {
1351
- return this._getOwnershipWorkflow().checkOwnershipConsensus(subAid);
1404
+ return this.checkOwnershipConsensus(subAid, true);
1352
1405
  }
1353
1406
  async bindAid(subjectAid, options = {}) {
1354
1407
  throw ownershipFailure('unsupported_protocol', 'legacy bindAid is unsupported; use bindSubaid');
@@ -1533,6 +1586,7 @@ export class AUNClient {
1533
1586
  this._ownershipStorage = null;
1534
1587
  this._ownershipFiles = null;
1535
1588
  this._ownershipWorkflow = null;
1589
+ this._ownershipConsensusCache = new Map();
1536
1590
  this._auth = new AuthFlow({
1537
1591
  tokenStore,
1538
1592
  crypto: new CryptoProvider(),
@@ -1921,7 +1975,7 @@ export class AUNClient {
1921
1975
  }
1922
1976
  async _ensureInitialAgentMd() {
1923
1977
  const aid = this._aid;
1924
- if (!aid || !this._currentAid)
1978
+ if (!aid || !this._currentAid || this.getType() !== 'human')
1925
1979
  return false;
1926
1980
  const observed = await this._agentMdManager.readAgentMdFresh(aid);
1927
1981
  if (observed.exists || String(this._agentMdManager._loadRecord?.(aid, true)?.local_draft_content ?? this._agentMdManager.loadRecord(aid)?.local_draft_content ?? '') || this._agentMdManager.pendingUpload(aid))
@@ -2072,7 +2126,7 @@ export class AUNClient {
2072
2126
  this._aidStore = store;
2073
2127
  let identity = store.load(orgAid);
2074
2128
  if (!identity.ok) {
2075
- const registered = await store.register(orgAid, { type: 'org', owner: owner.aid });
2129
+ const registered = await store._registerIdentity(orgAid, { type: 'org', owner: owner.aid, exttype: String(params.exttype ?? '') });
2076
2130
  if (!registered.ok)
2077
2131
  throw ownershipFailure('unavailable', registered.error.message, true);
2078
2132
  identity = store.load(orgAid);
@@ -2290,7 +2344,7 @@ export class AUNClient {
2290
2344
  return;
2291
2345
  const identity = this._localEntityCertificate(orgAid);
2292
2346
  const content = String(params.org_agent_md ?? buildDefaultAgentMd(orgAid, { type: 'org', owner: owner.aid, entityCertFingerprint: identity.certFingerprint, name: String(params.name ?? orgAid) }));
2293
- const uploaded = await store.uploadAgentMd(orgAid, content, { uploaderAid: owner.aid, entityOwnerResolver: (aid, type) => this._resolveEntityAgentMdOwner(aid, type, bootstrap), entityIdentityGetter: (aid) => this._freshEntityCertificate(aid, 'org') });
2347
+ const uploaded = await store._uploadAgentMd(orgAid, content, { uploaderAid: owner.aid, entityOwnerResolver: (aid, type) => this._resolveEntityAgentMdOwner(aid, type, bootstrap), entityIdentityGetter: (aid) => this._freshEntityCertificate(aid, 'org') }, (aid, notice, manager) => this._getAgentMdChanges().committed(aid, notice, manager));
2294
2348
  if (!uploaded.ok) {
2295
2349
  const code = ['invalid', 'unavailable', 'forbidden', 'conflict', 'persistence_unavailable'].includes(uploaded.error.code) ? uploaded.error.code : uploaded.error.code === 'NETWORK_ERROR' ? 'unavailable' : 'invalid';
2296
2350
  throw ownershipFailure(code, uploaded.error.message, code === 'unavailable');
@@ -2491,6 +2545,7 @@ export class AUNClient {
2491
2545
  aunPath: store.aunPath,
2492
2546
  verifySsl: identityStore._verifySsl,
2493
2547
  logger: identityStore._log.for('aun_core.agent_md'),
2548
+ onCommitted: (aid, notice) => this._getAgentMdChanges().committed(aid, notice, manager),
2494
2549
  uploadViaGatewayHost: true,
2495
2550
  ownerAidGetter: () => identity.aid,
2496
2551
  currentAidGetter: () => identity,
@@ -2518,7 +2573,7 @@ export class AUNClient {
2518
2573
  const bootstrap = initialCertificate ? { aid: groupAid, ownerAid: String(group.owner_aid ?? '').trim(), certFingerprint: certFingerprint(initialCertificate), type: 'group' } : undefined;
2519
2574
  if (await this._resumeGroupAgentMdUpload(store, groupAid, bootstrap))
2520
2575
  return;
2521
- const uploaded = await store.uploadAgentMd(groupAid, this._groupAgentMdContent(groupAid, params, group), { uploaderAid, entityOwnerResolver: (aid, type) => this._resolveEntityAgentMdOwner(aid, type, bootstrap), entityIdentityGetter: (aid) => this._freshEntityCertificate(aid) });
2576
+ const uploaded = await store._uploadAgentMd(groupAid, this._groupAgentMdContent(groupAid, params, group), { uploaderAid, entityOwnerResolver: (aid, type) => this._resolveEntityAgentMdOwner(aid, type, bootstrap), entityIdentityGetter: (aid) => this._freshEntityCertificate(aid) }, (aid, notice, manager) => this._getAgentMdChanges().committed(aid, notice, manager));
2522
2577
  if (!uploaded.ok) {
2523
2578
  const code = ['invalid', 'unavailable', 'forbidden', 'conflict', 'persistence_unavailable'].includes(uploaded.error.code) ? uploaded.error.code : uploaded.error.code === 'NETWORK_ERROR' ? 'unavailable' : 'invalid';
2524
2579
  throw ownershipFailure(code, `group agent.md upload failed: ${uploaded.error.message}`, code === 'unavailable');
@@ -2996,10 +3051,6 @@ export class AUNClient {
2996
3051
  const messageEvent = event === 'message.received' || event === 'message.recalled' || event === 'message.batch';
2997
3052
  const hadMessageConsumer = messageEvent && [...this._dispatcher._snapshotApplicationHandlers(['message.received', 'message.recalled', 'message.batch']).values()].some((handlers) => handlers.length > 0);
2998
3053
  const result = this._dispatcher.subscribe(event, handler);
2999
- if (event === 'agent_md_changed') {
3000
- this._getAgentMdChanges().schedule();
3001
- void this._getAgentMdChanges().deliverEvents().catch((error) => this._clientLog.debug(String(error)));
3002
- }
3003
3054
  if (messageEvent) {
3004
3055
  if (this._p2pPeerPullEnabled && !hadMessageConsumer)
3005
3056
  this._delivery.refreshPendingPeers();
@@ -4421,7 +4472,6 @@ export class AUNClient {
4421
4472
  this._safeAsync(this._controlMessages().recover());
4422
4473
  this._agentMdChanges?.close();
4423
4474
  this._agentMdChanges = new AgentMdChangeCoordinator(this);
4424
- this._agentMdChanges.schedule();
4425
4475
  // connect/reconnect 成功后自动触发一次 P2P message.v2.pull,补齐离线期间积压
4426
4476
  // 群消息按惰性触发,不在此处主动 pull
4427
4477
  if (backgroundSyncEnabled) {