@the-ai-company/cbio-node-runtime 1.56.0 → 1.57.0

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 (128) hide show
  1. package/README.md +25 -20
  2. package/dist/clients/agent/client.d.ts +2 -2
  3. package/dist/clients/agent/contracts.d.ts +3 -2
  4. package/dist/clients/owner/client.d.ts +7 -10
  5. package/dist/clients/owner/client.js +16 -32
  6. package/dist/clients/owner/client.js.map +1 -1
  7. package/dist/clients/owner/contracts.d.ts +11 -9
  8. package/dist/vault-core/contracts.d.ts +48 -35
  9. package/dist/vault-core/contracts.js.map +1 -1
  10. package/dist/vault-core/core.d.ts +15 -21
  11. package/dist/vault-core/core.js +209 -152
  12. package/dist/vault-core/core.js.map +1 -1
  13. package/dist/vault-core/defaults.d.ts +8 -20
  14. package/dist/vault-core/defaults.js +14 -37
  15. package/dist/vault-core/defaults.js.map +1 -1
  16. package/dist/vault-core/index.d.ts +3 -3
  17. package/dist/vault-core/index.js +1 -1
  18. package/dist/vault-core/index.js.map +1 -1
  19. package/dist/vault-core/persistence.d.ts +8 -6
  20. package/dist/vault-core/persistence.js +16 -8
  21. package/dist/vault-core/persistence.js.map +1 -1
  22. package/dist/vault-core/ports.d.ts +8 -20
  23. package/dist/vault-ingress/defaults.d.ts +2 -2
  24. package/dist/vault-ingress/index.d.ts +14 -33
  25. package/dist/vault-ingress/index.js +18 -31
  26. package/dist/vault-ingress/index.js.map +1 -1
  27. package/dist/vault-ingress/remote-transport.d.ts +2 -2
  28. package/dist/vault-ingress/remote-transport.js.map +1 -1
  29. package/docs/MIGRATION-1.51.md +1 -1
  30. package/docs/REFERENCE.md +26 -28
  31. package/docs/api/README.md +2 -2
  32. package/docs/api/classes/IdentityError.md +1 -1
  33. package/docs/api/classes/OwnerClientError.md +1 -1
  34. package/docs/api/classes/VaultCore.md +34 -94
  35. package/docs/api/classes/VaultCoreError.md +1 -1
  36. package/docs/api/enumerations/IdentityErrorCode.md +1 -1
  37. package/docs/api/enumerations/OwnerClientErrorCode.md +1 -1
  38. package/docs/api/functions/createAgentClient.md +1 -1
  39. package/docs/api/functions/createIdentity.md +1 -1
  40. package/docs/api/functions/createOwnerHttpFlowBoundary.md +1 -1
  41. package/docs/api/functions/createOwnerSession.md +1 -1
  42. package/docs/api/functions/createPersistentVaultCoreDependencies.md +1 -1
  43. package/docs/api/functions/createStandardAcquireBoundary.md +1 -1
  44. package/docs/api/functions/createStandardDispatchBoundary.md +1 -1
  45. package/docs/api/functions/createVault.md +1 -1
  46. package/docs/api/functions/createVaultClient.md +1 -1
  47. package/docs/api/functions/createVaultCore.md +1 -1
  48. package/docs/api/functions/createVaultCoreDependencies.md +1 -1
  49. package/docs/api/functions/createVaultService.md +1 -1
  50. package/docs/api/functions/createWorkspaceStorage.md +1 -1
  51. package/docs/api/functions/deriveIdentityId.md +1 -1
  52. package/docs/api/functions/deriveVaultWorkingKeyFromPassword.md +1 -1
  53. package/docs/api/functions/getDefaultWorkspaceDir.md +1 -1
  54. package/docs/api/functions/handleVaultAgentControlHttp.md +1 -1
  55. package/docs/api/functions/handleVaultHttpDispatch.md +1 -1
  56. package/docs/api/functions/initializeVaultCustody.md +1 -1
  57. package/docs/api/functions/listVaults.md +1 -1
  58. package/docs/api/functions/readVaultProfile.md +1 -1
  59. package/docs/api/functions/recoverVault.md +1 -1
  60. package/docs/api/functions/recoverVaultWorkingKey.md +1 -1
  61. package/docs/api/functions/restoreIdentity.md +1 -1
  62. package/docs/api/functions/updateVaultMetadata.md +1 -1
  63. package/docs/api/functions/wrapVaultCoreAsVaultService.md +1 -1
  64. package/docs/api/functions/writeVaultProfile.md +1 -1
  65. package/docs/api/interfaces/AgentClient.md +5 -5
  66. package/docs/api/interfaces/AgentDispatchIntent.md +1 -1
  67. package/docs/api/interfaces/AgentDispatchTransport.md +5 -5
  68. package/docs/api/interfaces/AgentIdentity.md +1 -1
  69. package/docs/api/interfaces/AgentSigner.md +1 -1
  70. package/docs/api/interfaces/AgentSubmitCapabilityRequestInput.md +1 -1
  71. package/docs/api/interfaces/CbioRuntime.md +1 -1
  72. package/docs/api/interfaces/CreateAgentClientOptions.md +1 -1
  73. package/docs/api/interfaces/CreateIdentityOptions.md +1 -1
  74. package/docs/api/interfaces/CreateOwnerSessionOptions.md +1 -1
  75. package/docs/api/interfaces/CreatePersistentVaultCoreDependenciesOptions.md +1 -1
  76. package/docs/api/interfaces/CreateVaultClientOptions.md +1 -1
  77. package/docs/api/interfaces/CreateVaultOptions.md +1 -1
  78. package/docs/api/interfaces/CreatedVault.md +1 -1
  79. package/docs/api/interfaces/DefaultPolicyEngineOptions.md +1 -1
  80. package/docs/api/interfaces/IStorageProvider.md +1 -1
  81. package/docs/api/interfaces/InitializeVaultCustodyOptions.md +1 -1
  82. package/docs/api/interfaces/InitializedVaultCustody.md +1 -1
  83. package/docs/api/interfaces/OwnerAgentProvisionResult.md +1 -1
  84. package/docs/api/interfaces/OwnerDefineSecretTargetsInput.md +1 -1
  85. package/docs/api/interfaces/OwnerSecretTargetBinding.md +1 -1
  86. package/docs/api/interfaces/OwnerSensitiveActionConfirmation.md +1 -1
  87. package/docs/api/interfaces/OwnerSensitiveActionContext.md +1 -1
  88. package/docs/api/interfaces/OwnerSession.md +1 -1
  89. package/docs/api/interfaces/OwnerStoreSecretInput.md +1 -1
  90. package/docs/api/interfaces/OwnerWriteSecretInput.md +1 -1
  91. package/docs/api/interfaces/RecoverVaultOptions.md +1 -1
  92. package/docs/api/interfaces/RecoveredVault.md +1 -1
  93. package/docs/api/interfaces/RestoreIdentityOptions.md +1 -1
  94. package/docs/api/interfaces/Signer.md +1 -1
  95. package/docs/api/interfaces/VaultApproveCapabilityRequestInput.md +1 -1
  96. package/docs/api/interfaces/VaultApproveDispatchInput.md +1 -1
  97. package/docs/api/interfaces/VaultAuditQueryInput.md +1 -1
  98. package/docs/api/interfaces/VaultClient.md +40 -76
  99. package/docs/api/interfaces/VaultCoreDependenciesOptions.md +1 -1
  100. package/docs/api/interfaces/VaultCreateAgentInput.md +1 -1
  101. package/docs/api/interfaces/VaultDeleteSecretInput.md +1 -1
  102. package/docs/api/interfaces/VaultExportSecretInput.md +1 -1
  103. package/docs/api/interfaces/VaultGrantCapabilityInput.md +1 -1
  104. package/docs/api/interfaces/VaultGrantCapabilityRequest.md +1 -1
  105. package/docs/api/interfaces/VaultIdentity.md +1 -1
  106. package/docs/api/interfaces/VaultImportAgentInput.md +1 -1
  107. package/docs/api/interfaces/VaultIssueSessionTokenInput.md +1 -1
  108. package/docs/api/interfaces/VaultListAgentsInput.md +1 -1
  109. package/docs/api/interfaces/VaultListCapabilitiesInput.md +1 -1
  110. package/docs/api/interfaces/VaultListSecretsInput.md +1 -1
  111. package/docs/api/interfaces/VaultMetadata.md +1 -1
  112. package/docs/api/interfaces/VaultObject.md +1 -1
  113. package/docs/api/interfaces/VaultProfile.md +1 -1
  114. package/docs/api/interfaces/VaultReadAgentPrivateKeyInput.md +1 -1
  115. package/docs/api/interfaces/VaultReadSecretPlaintextInput.md +1 -1
  116. package/docs/api/interfaces/VaultRegisterFlowInput.md +1 -1
  117. package/docs/api/interfaces/VaultRevokeCapabilityInput.md +1 -1
  118. package/docs/api/interfaces/VaultRevokeSessionTokenInput.md +1 -1
  119. package/docs/api/interfaces/VaultSigner.md +1 -1
  120. package/docs/api/interfaces/VaultSubmitCapabilityRequestInput.md +1 -1
  121. package/docs/api/interfaces/VaultUpdateAgentInput.md +1 -1
  122. package/docs/api/type-aliases/AgentCapabilityEnvelope.md +1 -1
  123. package/docs/api/type-aliases/AgentVisibleSecretRecord.md +1 -1
  124. package/docs/api/type-aliases/CbioRuntimeModule.md +1 -1
  125. package/docs/api/type-aliases/OwnerGrantCapabilityInput.md +1 -1
  126. package/docs/api/variables/DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY.md +1 -1
  127. package/docs/zh/README.md +19 -7
  128. package/package.json +1 -1
@@ -83,8 +83,7 @@ function createAgentControlBinding(requestId, requestedAt, agentId, action, payl
83
83
  */
84
84
  export class VaultCore {
85
85
  _deps;
86
- _pendingObservers = new Set();
87
- _pendingCapabilityObservers = new Set();
86
+ _capabilityStateObservers = new Set();
88
87
  constructor(_deps) {
89
88
  this._deps = _deps;
90
89
  }
@@ -93,6 +92,128 @@ export class VaultCore {
93
92
  throw new VaultCoreError("owner access denied", code);
94
93
  }
95
94
  }
95
+ _stateToGrantedCapability(state) {
96
+ return {
97
+ vaultId: state.vaultId,
98
+ capabilityId: state.capabilityId ?? "",
99
+ agentId: state.agentId,
100
+ secretIds: state.secretIds ? [...state.secretIds] : undefined,
101
+ secretAliases: state.secretAliases ? [...state.secretAliases] : undefined,
102
+ operation: state.operation,
103
+ customFlowId: state.customFlowId,
104
+ scope: state.scope,
105
+ methods: [...state.methods],
106
+ issuedAt: state.issuedAt ?? state.requestedAt,
107
+ expiresAt: state.expiresAt,
108
+ rateLimit: state.rateLimit,
109
+ skipAudit: state.skipAudit,
110
+ };
111
+ }
112
+ async _buildAgentCapabilityStates(agentId) {
113
+ return (await this._deps.capabilityStates.list(this._deps.vaultId, agentId)).map((state) => ({
114
+ status: state.status,
115
+ source: state.source,
116
+ agentId: state.agentId,
117
+ requestId: state.requestId,
118
+ capabilityId: state.capabilityId,
119
+ operation: state.operation,
120
+ secretIds: state.secretIds ? [...state.secretIds] : undefined,
121
+ secretAliases: state.secretAliases ? [...state.secretAliases] : undefined,
122
+ customFlowId: state.customFlowId,
123
+ scope: state.scope,
124
+ methods: [...state.methods],
125
+ issuedAt: state.issuedAt,
126
+ requestedAt: state.requestedAt,
127
+ expiresAt: state.expiresAt,
128
+ rateLimit: state.rateLimit,
129
+ skipAudit: state.skipAudit,
130
+ justification: state.justification,
131
+ secretAlias: state.secretAlias,
132
+ targetUrl: state.targetUrl,
133
+ }));
134
+ }
135
+ _isExecutablePendingState(state) {
136
+ return !!(state.requestId && state.targetUrl && state.secretAlias && state.proof);
137
+ }
138
+ async _executePendingCapabilityState(command, mode) {
139
+ if (command.vaultId.value !== this._deps.vaultId.value) {
140
+ throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
141
+ }
142
+ const pending = await this._deps.capabilityStates.getByRequestId(command.vaultId, command.requestId);
143
+ if (!pending || pending.status !== "PENDING") {
144
+ throw new VaultCoreError("pending capability state not found", "VAULT_REQUEST_NOT_FOUND");
145
+ }
146
+ const issuedAt = this._deps.clock.nowIso();
147
+ const capability = {
148
+ vaultId: this._deps.vaultId,
149
+ agentId: pending.agentId,
150
+ capabilityId: pending.capabilityId ?? this._deps.ids.newCapabilityId(),
151
+ secretIds: pending.secretIds ? [...pending.secretIds] : undefined,
152
+ secretAliases: pending.secretAliases ? [...pending.secretAliases] : (pending.secretAlias ? [pending.secretAlias] : []),
153
+ operation: pending.operation,
154
+ customFlowId: pending.customFlowId,
155
+ scope: pending.targetUrl ?? pending.scope,
156
+ methods: [...pending.methods],
157
+ issuedAt,
158
+ expiresAt: pending.expiresAt,
159
+ rateLimit: pending.rateLimit,
160
+ skipAudit: pending.skipAudit,
161
+ };
162
+ let result;
163
+ if (this._isExecutablePendingState(pending)) {
164
+ result = await this.agentDispatchSecret({
165
+ vaultId: this._deps.vaultId,
166
+ agent: { kind: "agent", id: pending.agentId },
167
+ capability,
168
+ secretAlias: pending.secretAlias === "unknown" ? undefined : pending.secretAlias,
169
+ targetUrl: pending.targetUrl,
170
+ method: pending.methods[0] ?? "POST",
171
+ headers: pending.headers,
172
+ body: pending.body,
173
+ proof: pending.proof,
174
+ requestId: pending.requestId,
175
+ requestedAt: pending.requestedAt,
176
+ });
177
+ }
178
+ else if (mode === "grant") {
179
+ result = {
180
+ vaultId: this._deps.vaultId,
181
+ requestId: pending.requestId ?? command.requestId,
182
+ status: DispatchStatus.SUCCEEDED,
183
+ targetUrl: pending.scope,
184
+ method: pending.methods[0] ?? "POST",
185
+ };
186
+ }
187
+ else {
188
+ throw new VaultCoreError("pending capability state is not executable", "VAULT_WRITE_DENIED");
189
+ }
190
+ if (mode === "grant") {
191
+ await this._deps.capabilityStates.upsert({
192
+ ...pending,
193
+ capabilityId: capability.capabilityId,
194
+ status: "GRANTED",
195
+ source: "owner_grant",
196
+ issuedAt,
197
+ decidedAt: issuedAt,
198
+ });
199
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `executed and granted capability state ${command.requestId}`, {
200
+ requestId: command.requestId,
201
+ agentId: pending.agentId,
202
+ capabilityId: capability.capabilityId,
203
+ operation: capability.operation,
204
+ }));
205
+ }
206
+ else {
207
+ await this._deps.capabilityStates.deleteByRequestId(command.vaultId, command.requestId);
208
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `executed once and deleted capability state ${command.requestId}`, {
209
+ requestId: command.requestId,
210
+ agentId: pending.agentId,
211
+ capabilityId: capability.capabilityId,
212
+ operation: capability.operation,
213
+ }));
214
+ }
215
+ return result;
216
+ }
96
217
  get vaultId() {
97
218
  return this._deps.vaultId;
98
219
  }
@@ -142,7 +263,9 @@ export class VaultCore {
142
263
  }
143
264
  }
144
265
  async _listVisibleSecretsForAgent(agentId) {
145
- const capabilities = await this._deps.capabilities.list(this._deps.vaultId, agentId);
266
+ const capabilities = (await this._deps.capabilityStates.list(this._deps.vaultId, agentId))
267
+ .filter((state) => state.status === "GRANTED")
268
+ .map((state) => this._stateToGrantedCapability(state));
146
269
  const capabilityMap = new Map();
147
270
  for (const capability of capabilities) {
148
271
  for (const alias of capability.secretAliases ?? []) {
@@ -171,16 +294,10 @@ export class VaultCore {
171
294
  };
172
295
  });
173
296
  }
174
- ownerOnPendingDispatch(callback) {
175
- this._pendingObservers.add(callback);
176
- return () => {
177
- this._pendingObservers.delete(callback);
178
- };
179
- }
180
- ownerOnPendingCapabilityRequest(callback) {
181
- this._pendingCapabilityObservers.add(callback);
297
+ ownerOnCapabilityState(callback) {
298
+ this._capabilityStateObservers.add(callback);
182
299
  return () => {
183
- this._pendingCapabilityObservers.delete(callback);
300
+ this._capabilityStateObservers.delete(callback);
184
301
  };
185
302
  }
186
303
  async ownerRegisterAgentIdentity(command) {
@@ -245,7 +362,13 @@ export class VaultCore {
245
362
  throw new VaultCoreError("capability id required", "VAULT_IDENTITY_DENIED");
246
363
  }
247
364
  try {
248
- await this._deps.capabilities.register(command.capability);
365
+ await this._deps.capabilityStates.upsert({
366
+ ...command.capability,
367
+ status: "GRANTED",
368
+ source: "owner_grant",
369
+ requestId: undefined,
370
+ requestedAt: command.capability.issuedAt,
371
+ });
249
372
  await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CAPABILITY, AuditOutcome.SUCCEEDED, `capability registered: ${command.capability.capabilityId}`, {
250
373
  capabilityId: command.capability.capabilityId,
251
374
  operation: command.capability.operation,
@@ -275,28 +398,27 @@ export class VaultCore {
275
398
  }
276
399
  const pendingRecord = {
277
400
  vaultId: this._deps.vaultId,
401
+ status: "PENDING",
402
+ source: "explicit_request",
278
403
  requestId: command.requestId,
279
- requester: command.requester,
280
404
  agentId: command.agentId,
281
- scope: {
282
- operation: command.scope.operation,
283
- secretAliases: command.scope.secretAliases ? [...command.scope.secretAliases] : [],
284
- scope: command.scope.scope,
285
- methods: [...command.scope.methods],
286
- rateLimit: command.scope.rateLimit,
287
- skipAudit: command.scope.skipAudit,
288
- expiresAt: command.scope.expiresAt,
289
- },
405
+ operation: command.scope.operation,
406
+ secretAliases: command.scope.secretAliases ? [...command.scope.secretAliases] : [],
407
+ scope: command.scope.scope,
408
+ methods: [...command.scope.methods],
409
+ rateLimit: command.scope.rateLimit,
410
+ skipAudit: command.scope.skipAudit,
411
+ expiresAt: command.scope.expiresAt,
290
412
  justification: command.justification,
291
413
  requestedAt: command.requestedAt,
292
414
  };
293
- await this._deps.pendingCapabilityRequests.save(pendingRecord);
294
- for (const observer of this._pendingCapabilityObservers) {
415
+ await this._deps.capabilityStates.upsert(pendingRecord);
416
+ for (const observer of this._capabilityStateObservers) {
295
417
  try {
296
418
  observer(pendingRecord);
297
419
  }
298
420
  catch (error) {
299
- console.error("VaultCore: error in pending capability observer:", error);
421
+ console.error("VaultCore: error in capability state observer:", error);
300
422
  }
301
423
  }
302
424
  await this._appendAudit(toAuditEntry(this._deps, command.requester, AuditAction.SUBMIT_CAPABILITY_REQUEST, AuditOutcome.PENDING, `capability request submitted for agent: ${command.agentId}`, {
@@ -310,7 +432,8 @@ export class VaultCore {
310
432
  if (vaultId.value !== this._deps.vaultId.value) {
311
433
  throw new VaultCoreError("capability lookup vault mismatch", "VAULT_IDENTITY_DENIED");
312
434
  }
313
- return this._deps.capabilities.get(vaultId, agentId, capabilityId);
435
+ const state = await this._deps.capabilityStates.getByCapabilityId(vaultId, agentId, capabilityId);
436
+ return state && state.status === "GRANTED" ? this._stateToGrantedCapability(state) : null;
314
437
  }
315
438
  async ownerRegisterCustomFlow(command) {
316
439
  if (command.vaultId.value !== this._deps.vaultId.value) {
@@ -513,7 +636,9 @@ export class VaultCore {
513
636
  if (!agentRecord) {
514
637
  return { vaultId: this._deps.vaultId, decision: "deny", reason: "agent not found", secretId: null, executorTarget: null };
515
638
  }
516
- const capabilities = await this._deps.capabilities.list(this._deps.vaultId, request.agent.id);
639
+ const capabilities = (await this._deps.capabilityStates.list(this._deps.vaultId, request.agent.id))
640
+ .filter((state) => state.status === "GRANTED")
641
+ .map((state) => this._stateToGrantedCapability(state));
517
642
  const requestedCapabilityId = request.capability?.capabilityId;
518
643
  const candidateCapabilities = requestedCapabilityId
519
644
  ? capabilities.filter((cap) => cap.capabilityId === requestedCapabilityId)
@@ -527,25 +652,31 @@ export class VaultCore {
527
652
  if (!capability) {
528
653
  // It's a discovery case if the agent and secret exist but no capability matches
529
654
  const pendingRecord = {
655
+ vaultId: this._deps.vaultId,
656
+ status: "PENDING",
657
+ source: "dispatch_discovery",
530
658
  requestId: request.requestId,
531
659
  agentId: request.agent.id,
532
660
  capabilityId: undefined,
661
+ operation: "dispatch_http",
662
+ secretAliases: request.secretAlias ? [request.secretAlias] : [],
663
+ scope: request.targetUrl,
664
+ methods: [request.method],
665
+ requestedAt: request.requestedAt,
533
666
  secretAlias: request.secretAlias ?? "unknown",
534
667
  targetUrl: request.targetUrl,
535
- method: request.method,
536
668
  headers: request.headers,
537
669
  body: request.body,
538
- requestedAt: request.requestedAt,
539
670
  proof: request.proof,
540
671
  };
541
- await this._deps.pendingRequests.save(pendingRecord);
672
+ await this._deps.capabilityStates.upsert(pendingRecord);
542
673
  // Notify observers
543
- for (const observer of this._pendingObservers) {
674
+ for (const observer of this._capabilityStateObservers) {
544
675
  try {
545
676
  observer(pendingRecord);
546
677
  }
547
678
  catch (error) {
548
- console.error("VaultCore: error in pending observer:", error);
679
+ console.error("VaultCore: error in capability state observer:", error);
549
680
  }
550
681
  }
551
682
  await this._appendDecisionAudit(request, AuditOutcome.PENDING, "dispatch stalled for manual discovery approval", {
@@ -705,7 +836,9 @@ export class VaultCore {
705
836
  return identities;
706
837
  }
707
838
  async ownerListCapabilities(actor, agentId, request) {
708
- const capabilities = await this._deps.capabilities.list(this._deps.vaultId, agentId);
839
+ const capabilities = (await this._deps.capabilityStates.list(this._deps.vaultId, agentId))
840
+ .filter((state) => state.status === "GRANTED")
841
+ .map((state) => this._stateToGrantedCapability(state));
709
842
  await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_CAPABILITIES, AuditOutcome.ALLOWED, "capabilities listed", {
710
843
  requestId: request?.requestId,
711
844
  agentId,
@@ -732,7 +865,7 @@ export class VaultCore {
732
865
  throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
733
866
  }
734
867
  await this._verifyAgentControlProof(request, "list_capabilities");
735
- return this._deps.capabilities.list(this._deps.vaultId, request.agent.id);
868
+ return this._buildAgentCapabilityStates(request.agent.id);
736
869
  }
737
870
  async agentListSecrets(request) {
738
871
  if (request.vaultId.value !== this._deps.vaultId.value) {
@@ -745,13 +878,25 @@ export class VaultCore {
745
878
  if (command.vaultId.value !== this._deps.vaultId.value) {
746
879
  throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
747
880
  }
748
- const capabilities = await this._deps.capabilities.list(this._deps.vaultId, command.agent.id);
881
+ await this._verifyAgentControlProof(command, "get_manifest");
882
+ const agentRecord = await this._deps.agentIdentities.get(this._deps.vaultId, command.agent.id);
883
+ if (!agentRecord) {
884
+ throw new VaultCoreError("agent identity not registered", "VAULT_DISPATCH_DENIED");
885
+ }
886
+ const capabilities = await this._buildAgentCapabilityStates(command.agent.id);
749
887
  const vaultNickname = "CBIO Vault"; // TODO: Pull from profile if available
750
888
  return {
751
889
  agentId: command.agent.id,
752
890
  vaultId: this._deps.vaultId.value,
753
891
  vaultNickname,
754
892
  issuedAt: this._deps.clock.nowIso(),
893
+ agent: {
894
+ agentId: agentRecord.agentId,
895
+ identityId: agentRecord.identityId,
896
+ publicKey: agentRecord.publicKey,
897
+ nickname: agentRecord.nickname,
898
+ metadata: agentRecord.metadata,
899
+ },
755
900
  capabilities,
756
901
  tools: getAgentToolbox(),
757
902
  };
@@ -778,7 +923,15 @@ export class VaultCore {
778
923
  });
779
924
  }
780
925
  async ownerRevokeCapability(command) {
781
- await this._deps.policy.revokeCapability(command.vaultId, command.agentId, command.capabilityId);
926
+ const existing = await this._deps.capabilityStates.getByCapabilityId(command.vaultId, command.agentId, command.capabilityId);
927
+ if (!existing) {
928
+ throw new VaultCoreError("capability not found", "VAULT_CAPABILITY_NOT_FOUND");
929
+ }
930
+ await this._deps.capabilityStates.upsert({
931
+ ...existing,
932
+ status: "REJECTED",
933
+ decidedAt: this._deps.clock.nowIso(),
934
+ });
782
935
  await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REVOKE_CAPABILITY, AuditOutcome.SUCCEEDED, "capability revoked", {
783
936
  requestId: command.requestId,
784
937
  agentId: command.agentId,
@@ -824,135 +977,39 @@ export class VaultCore {
824
977
  await this._deps.sessionTokens.revoke(request.token);
825
978
  await this._appendAudit(toAuditEntry(this._deps, request.actor, AuditAction.REVOKE_SESSION_TOKEN, AuditOutcome.SUCCEEDED, "session token revoked"));
826
979
  }
827
- async ownerListPendingDispatches(command) {
980
+ async ownerListCapabilityStates(command) {
828
981
  if (command.vaultId.value !== this._deps.vaultId.value) {
829
982
  throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
830
983
  }
831
- return this._deps.pendingRequests.list(command.vaultId);
984
+ return (await this._deps.capabilityStates.list(command.vaultId, command.agentId))
985
+ .filter((state) => !command.status || state.status === command.status);
832
986
  }
833
- async ownerListPendingCapabilityRequests(command) {
834
- if (command.vaultId.value !== this._deps.vaultId.value) {
835
- throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
836
- }
837
- return this._deps.pendingCapabilityRequests.list(command.vaultId);
987
+ async ownerExecuteCapabilityStateOnce(command) {
988
+ return this._executePendingCapabilityState(command, "once");
838
989
  }
839
- async ownerApproveCapabilityRequest(command) {
840
- if (command.vaultId.value !== this._deps.vaultId.value) {
841
- throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
842
- }
843
- const pending = await this._deps.pendingCapabilityRequests.get(command.requestId);
844
- if (!pending) {
845
- throw new VaultCoreError("pending capability request not found", "VAULT_REQUEST_NOT_FOUND");
846
- }
847
- const capability = {
848
- vaultId: this._deps.vaultId,
849
- agentId: pending.agentId,
850
- capabilityId: command.capabilityId ?? this._deps.ids.newCapabilityId(),
851
- operation: pending.scope.operation,
852
- secretAliases: pending.scope.secretAliases ? [...pending.scope.secretAliases] : [],
853
- scope: pending.scope.scope,
854
- methods: [...pending.scope.methods],
855
- rateLimit: pending.scope.rateLimit,
856
- skipAudit: pending.scope.skipAudit,
857
- expiresAt: pending.scope.expiresAt,
858
- issuedAt: this._deps.clock.nowIso(),
859
- };
860
- await this._deps.capabilities.register(capability);
861
- await this._deps.pendingCapabilityRequests.delete(command.requestId);
862
- await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `approved capability request ${command.requestId}`, {
863
- requestId: command.requestId,
864
- agentId: pending.agentId,
865
- capabilityId: capability.capabilityId,
866
- operation: capability.operation,
867
- }));
868
- return capability;
990
+ async ownerExecuteCapabilityStateAndGrant(command) {
991
+ return this._executePendingCapabilityState(command, "grant");
869
992
  }
870
- async ownerRejectCapabilityRequest(command) {
993
+ async ownerRejectCapabilityState(command) {
871
994
  if (command.vaultId.value !== this._deps.vaultId.value) {
872
995
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
873
996
  }
874
- const pending = await this._deps.pendingCapabilityRequests.get(command.requestId);
875
- if (!pending) {
876
- throw new VaultCoreError("pending capability request not found", "VAULT_REQUEST_NOT_FOUND");
997
+ const pending = await this._deps.capabilityStates.getByRequestId(command.vaultId, command.requestId);
998
+ if (!pending || pending.status !== "PENDING") {
999
+ throw new VaultCoreError("pending capability state not found", "VAULT_REQUEST_NOT_FOUND");
877
1000
  }
878
- await this._deps.pendingCapabilityRequests.delete(command.requestId);
1001
+ const rejectedState = {
1002
+ ...pending,
1003
+ status: "REJECTED",
1004
+ decidedAt: this._deps.clock.nowIso(),
1005
+ };
1006
+ await this._deps.capabilityStates.upsert(rejectedState);
879
1007
  await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REJECT_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `rejected capability request ${command.requestId}`, {
880
1008
  requestId: command.requestId,
881
1009
  agentId: pending.agentId,
882
- operation: pending.scope.operation,
883
- }));
884
- }
885
- async ownerApproveDispatch(command) {
886
- if (command.vaultId.value !== this._deps.vaultId.value) {
887
- throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
888
- }
889
- const pending = await this._deps.pendingRequests.get(command.requestId);
890
- if (!pending) {
891
- throw new VaultCoreError("pending request not found", "VAULT_REQUEST_NOT_FOUND");
892
- }
893
- const agentRecord = await this._deps.agentIdentities.get(this._deps.vaultId, pending.agentId);
894
- if (!agentRecord) {
895
- throw new VaultCoreError("agent identity not found", "VAULT_AGENT_NOT_FOUND");
896
- }
897
- let capability;
898
- if (pending.capabilityId) {
899
- const existing = await this._deps.capabilities.get(this._deps.vaultId, pending.agentId, pending.capabilityId);
900
- if (!existing) {
901
- throw new VaultCoreError("capability not found", "VAULT_CAPABILITY_NOT_FOUND");
902
- }
903
- capability = existing;
904
- }
905
- else {
906
- // Discovery case: derive from request
907
- const capabilityId = this._deps.ids.newCapabilityId();
908
- capability = {
909
- vaultId: this._deps.vaultId,
910
- agentId: pending.agentId,
911
- capabilityId,
912
- secretAliases: [pending.secretAlias],
913
- methods: [pending.method],
914
- scope: pending.targetUrl,
915
- operation: "dispatch_http",
916
- issuedAt: this._deps.clock.nowIso(),
917
- skipAudit: command.skipAudit ?? false,
918
- };
919
- if (command.permanent) {
920
- await this._deps.capabilities.register(capability);
921
- }
922
- }
923
- const result = await this.agentDispatchSecret({
924
- vaultId: this._deps.vaultId,
925
- agent: { kind: "agent", id: pending.agentId },
926
- capability: capability,
927
- secretAlias: pending.secretAlias === "unknown" ? undefined : pending.secretAlias,
928
- targetUrl: pending.targetUrl,
929
- method: pending.method,
930
- headers: pending.headers,
931
- body: pending.body,
932
- proof: pending.proof,
933
- requestId: pending.requestId,
934
- requestedAt: pending.requestedAt,
935
- });
936
- await this._deps.pendingRequests.delete(command.requestId);
937
- await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_DISPATCH, AuditOutcome.SUCCEEDED, `approved dispatch ${command.requestId}${command.permanent ? " and granted permanent capability" : ""}`, {
938
- requestId: command.requestId,
939
- agentId: pending.agentId,
940
- capabilityId: capability.capabilityId,
941
- }));
942
- return result;
943
- }
944
- async ownerRejectDispatch(command) {
945
- if (command.vaultId.value !== this._deps.vaultId.value) {
946
- throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
947
- }
948
- const pending = await this._deps.pendingRequests.get(command.requestId);
949
- if (!pending) {
950
- throw new VaultCoreError("pending request not found", "VAULT_REQUEST_NOT_FOUND");
951
- }
952
- await this._deps.pendingRequests.delete(command.requestId);
953
- await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REJECT_DISPATCH, AuditOutcome.SUCCEEDED, `rejected dispatch ${command.requestId}`, {
954
- requestId: command.requestId,
1010
+ operation: pending.operation,
955
1011
  }));
1012
+ return rejectedState;
956
1013
  }
957
1014
  }
958
1015
  export function createVaultCore(deps) {