@ouro.bot/friends 0.1.0-alpha.5 → 0.1.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -16
- package/changelog.json +12 -0
- package/dist/a2a-client/index.d.ts +1 -0
- package/dist/a2a-client/index.js +5 -1
- package/dist/a2a-client/roster-verify.d.ts +15 -0
- package/dist/a2a-client/roster-verify.js +61 -0
- package/dist/account-roster.d.ts +52 -0
- package/dist/account-roster.js +108 -0
- package/dist/agent-peer.js +5 -1
- package/dist/audit.d.ts +42 -0
- package/dist/audit.js +86 -0
- package/dist/connect-authority.d.ts +43 -0
- package/dist/connect-authority.js +84 -0
- package/dist/connect.d.ts +55 -0
- package/dist/connect.js +160 -0
- package/dist/coordination.d.ts +17 -1
- package/dist/coordination.js +80 -6
- package/dist/file-bundle.d.ts +5 -0
- package/dist/file-bundle.js +4 -0
- package/dist/friend-lookup.d.ts +9 -0
- package/dist/friend-lookup.js +69 -0
- package/dist/identity.d.ts +17 -0
- package/dist/identity.js +68 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +51 -2
- package/dist/mailbox/index.d.ts +13 -10
- package/dist/mailbox/index.js +1 -1
- package/dist/mcp/dispatch.d.ts +27 -1
- package/dist/mcp/dispatch.js +110 -3
- package/dist/mcp/run-main.js +8 -5
- package/dist/mcp/schemas.js +51 -4
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.js +2 -2
- package/dist/mission-result.d.ts +82 -0
- package/dist/mission-result.js +200 -0
- package/dist/mission-store-file.js +8 -0
- package/dist/resolver.d.ts +32 -1
- package/dist/resolver.js +50 -3
- package/dist/roster-store-file.d.ts +16 -0
- package/dist/roster-store-file.js +125 -0
- package/dist/roster-store-memory.d.ts +9 -0
- package/dist/roster-store-memory.js +20 -0
- package/dist/roster-store.d.ts +29 -0
- package/dist/roster-store.js +9 -0
- package/dist/roster-verifier.d.ts +23 -0
- package/dist/roster-verifier.js +47 -0
- package/dist/trust-explanation.d.ts +7 -1
- package/dist/trust-explanation.js +52 -34
- package/dist/trust-mutation.d.ts +13 -1
- package/dist/trust-mutation.js +31 -2
- package/dist/types.d.ts +64 -0
- package/package.json +2 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AccountRoster } from "./roster-store";
|
|
2
|
+
export interface RosterVerifier {
|
|
3
|
+
/** Whether `roster` is authentic under the pinned `rosterKey`. The identity-only
|
|
4
|
+
* default returns true for any well-formed roster (ignores the sig); an Ed25519
|
|
5
|
+
* impl verifies the detached sig over the canonical roster bytes. */
|
|
6
|
+
verify(roster: AccountRoster, rosterKey: string): boolean;
|
|
7
|
+
/** SECURITY (finding 1, HIGH): whether this verifier is strong enough to back a
|
|
8
|
+
* FAMILY grant. The identity-only default ignores the sig, so it MUST NOT grant
|
|
9
|
+
* family — only a real cryptographic verifier (the a2a-client `ed25519RosterVerifier`)
|
|
10
|
+
* sets this true. `evaluateAccountMembership` fails closed (→ `unverified`, never
|
|
11
|
+
* `family_same_account`) when the active verifier is not family-granting. Optional
|
|
12
|
+
* + defaulting-to-false so a custom verifier is non-granting unless it opts in. */
|
|
13
|
+
grantsFamily?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Identity-only roster verifier: accept any well-formed roster, ignore the sig.
|
|
16
|
+
* The day-one default for NON-GRANT identity checks; it deliberately omits
|
|
17
|
+
* `grantsFamily` (defaults to false) so the family-granting path
|
|
18
|
+
* (`evaluateAccountMembership`) fails closed under it — a garbage-signed roster can
|
|
19
|
+
* never yield a family grant without a real cryptographic verifier injected. Mirrors
|
|
20
|
+
* `tofuVerifier`. */
|
|
21
|
+
export declare const identityRosterVerifier: RosterVerifier;
|
|
22
|
+
/** The default verifier used when no crypto verifier is injected. */
|
|
23
|
+
export declare const DEFAULT_ROSTER_VERIFIER: RosterVerifier;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_ROSTER_VERIFIER = exports.identityRosterVerifier = void 0;
|
|
4
|
+
// RosterVerifier — the pluggable account-roster authentication seam (Q1; mirrors
|
|
5
|
+
// AgentVerifier exactly). The core declares the INTERFACE + an identity-only
|
|
6
|
+
// default that does NO crypto; the a2a-client side provides the real Ed25519
|
|
7
|
+
// implementation (`ed25519RosterVerifier`), which the host injects — the same split
|
|
8
|
+
// that keeps `DidVerifier` out of the core. THIS MODULE MUST NOT import
|
|
9
|
+
// src/a2a-client/ or libsodium (the no-restricted-imports lint enforces it).
|
|
10
|
+
//
|
|
11
|
+
// The canonical-bytes contract both sides agree on: the roster `sig` is an Ed25519
|
|
12
|
+
// detached signature over `jcsBytes({ accountId, members, epoch })` — the roster
|
|
13
|
+
// MINUS its `sig` field — exactly how `verifyEnvelopeSignature` signs the
|
|
14
|
+
// proof-stripped envelope. The identity default ignores the sig (TOFU-equivalent);
|
|
15
|
+
// the crypto impl checks it.
|
|
16
|
+
const observability_1 = require("./observability");
|
|
17
|
+
/** A roster is well-formed when it has the structural shape the membership check
|
|
18
|
+
* relies on: a string accountId, an array of `{handle, did}` members, a numeric
|
|
19
|
+
* epoch, and a string sig. (The identity verifier accepts any well-formed roster
|
|
20
|
+
* without checking the sig — TOFU-equivalent, mirroring `tofuVerifier`.) */
|
|
21
|
+
function isWellFormedRoster(roster) {
|
|
22
|
+
return (typeof roster.accountId === "string" &&
|
|
23
|
+
Array.isArray(roster.members) &&
|
|
24
|
+
roster.members.every((m) => typeof m.handle === "string" && typeof m.did === "string") &&
|
|
25
|
+
typeof roster.epoch === "number" &&
|
|
26
|
+
typeof roster.sig === "string");
|
|
27
|
+
}
|
|
28
|
+
/** Identity-only roster verifier: accept any well-formed roster, ignore the sig.
|
|
29
|
+
* The day-one default for NON-GRANT identity checks; it deliberately omits
|
|
30
|
+
* `grantsFamily` (defaults to false) so the family-granting path
|
|
31
|
+
* (`evaluateAccountMembership`) fails closed under it — a garbage-signed roster can
|
|
32
|
+
* never yield a family grant without a real cryptographic verifier injected. Mirrors
|
|
33
|
+
* `tofuVerifier`. */
|
|
34
|
+
exports.identityRosterVerifier = {
|
|
35
|
+
verify(roster) {
|
|
36
|
+
const ok = isWellFormedRoster(roster);
|
|
37
|
+
(0, observability_1.emitNervesEvent)({
|
|
38
|
+
component: "friends",
|
|
39
|
+
event: "friends.roster_verified",
|
|
40
|
+
message: "verified account roster (tofu)",
|
|
41
|
+
meta: { accountId: roster.accountId, epoch: roster.epoch, ok },
|
|
42
|
+
});
|
|
43
|
+
return ok;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
/** The default verifier used when no crypto verifier is injected. */
|
|
47
|
+
exports.DEFAULT_ROSTER_VERIFIER = exports.identityRosterVerifier;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Channel, FriendRecord, TrustLevel } from "./types";
|
|
2
|
-
export type TrustBasis = "direct" | "shared_group" | "unknown";
|
|
2
|
+
export type TrustBasis = "direct" | "shared_group" | "unknown" | "same_account";
|
|
3
3
|
export interface TrustExplanation {
|
|
4
4
|
level: TrustLevel;
|
|
5
5
|
basis: TrustBasis;
|
|
@@ -13,4 +13,10 @@ export declare function describeTrustContext(input: {
|
|
|
13
13
|
friend: FriendRecord;
|
|
14
14
|
channel: Channel;
|
|
15
15
|
isGroupChat?: boolean;
|
|
16
|
+
/** When the relationship is `family` AND this hint is `"same_account"`, the
|
|
17
|
+
* explanation attributes the family trust to the signed account roster
|
|
18
|
+
* (`basis: "same_account"`) instead of the generic `direct`. Ignored for any
|
|
19
|
+
* non-family level. Absent ⇒ existing behavior byte-for-byte. (Unit 3a stub:
|
|
20
|
+
* accepted but not yet honored — implemented GREEN in Unit 3b.) */
|
|
21
|
+
basisHint?: TrustBasis;
|
|
16
22
|
}): TrustExplanation;
|
|
@@ -11,14 +11,17 @@ function resolveLevel(friend) {
|
|
|
11
11
|
function describeTrustContext(input) {
|
|
12
12
|
const level = resolveLevel(input.friend);
|
|
13
13
|
const relatedGroupId = findRelatedGroupId(input.friend);
|
|
14
|
-
|
|
14
|
+
// The same-account variant only applies where the relationship is actually
|
|
15
|
+
// account-derived family: level === "family" AND the caller hints same_account
|
|
16
|
+
// (the roster path seats it). It keeps the family tier's permits/constraints but
|
|
17
|
+
// attributes the trust to the signed account roster, not generic direct trust.
|
|
18
|
+
const isSameAccountFamily = level === "family" && input.basisHint === "same_account";
|
|
19
|
+
const explanation = isSameAccountFamily
|
|
15
20
|
? {
|
|
16
21
|
level,
|
|
17
|
-
basis: "
|
|
18
|
-
summary:
|
|
19
|
-
|
|
20
|
-
: "direct trusted relationship",
|
|
21
|
-
why: "this relationship is directly trusted rather than inferred through a shared group or cold first contact.",
|
|
22
|
+
basis: "same_account",
|
|
23
|
+
summary: "same-account family (signed account roster)",
|
|
24
|
+
why: "this agent is recognized as the same owner's agent via the signed account roster, not through a shared group or cold first contact.",
|
|
22
25
|
permits: [
|
|
23
26
|
"local operations when appropriate",
|
|
24
27
|
"proactive follow-through",
|
|
@@ -26,39 +29,54 @@ function describeTrustContext(input) {
|
|
|
26
29
|
],
|
|
27
30
|
constraints: [],
|
|
28
31
|
}
|
|
29
|
-
: level === "
|
|
32
|
+
: level === "family" || level === "friend"
|
|
30
33
|
? {
|
|
31
34
|
level,
|
|
32
|
-
basis: "
|
|
33
|
-
summary:
|
|
34
|
-
? "
|
|
35
|
-
: "
|
|
36
|
-
why:
|
|
37
|
-
? `this trust comes from the shared group context ${relatedGroupId}, not from direct endorsement.`
|
|
38
|
-
: "this trust comes from shared group context rather than direct endorsement.",
|
|
35
|
+
basis: "direct",
|
|
36
|
+
summary: level === "family"
|
|
37
|
+
? "direct family trust"
|
|
38
|
+
: "direct trusted relationship",
|
|
39
|
+
why: "this relationship is directly trusted rather than inferred through a shared group or cold first contact.",
|
|
39
40
|
permits: [
|
|
40
|
-
"
|
|
41
|
-
"
|
|
41
|
+
"local operations when appropriate",
|
|
42
|
+
"proactive follow-through",
|
|
43
|
+
"full collaborative problem solving",
|
|
42
44
|
],
|
|
43
|
-
constraints: [
|
|
44
|
-
"guarded local actions",
|
|
45
|
-
"do not assume broad private authority",
|
|
46
|
-
],
|
|
47
|
-
relatedGroupId,
|
|
45
|
+
constraints: [],
|
|
48
46
|
}
|
|
49
|
-
:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
: level === "acquaintance"
|
|
48
|
+
? {
|
|
49
|
+
level,
|
|
50
|
+
basis: "shared_group",
|
|
51
|
+
summary: relatedGroupId
|
|
52
|
+
? "known through the shared project group"
|
|
53
|
+
: "known through a shared group context",
|
|
54
|
+
why: relatedGroupId
|
|
55
|
+
? `this trust comes from the shared group context ${relatedGroupId}, not from direct endorsement.`
|
|
56
|
+
: "this trust comes from shared group context rather than direct endorsement.",
|
|
57
|
+
permits: [
|
|
58
|
+
"group-safe coordination",
|
|
59
|
+
"normal conversation inside the shared context",
|
|
60
|
+
],
|
|
61
|
+
constraints: [
|
|
62
|
+
"guarded local actions",
|
|
63
|
+
"do not assume broad private authority",
|
|
64
|
+
],
|
|
65
|
+
relatedGroupId,
|
|
66
|
+
}
|
|
67
|
+
: {
|
|
68
|
+
level,
|
|
69
|
+
basis: "unknown",
|
|
70
|
+
summary: "truly unknown first-contact context",
|
|
71
|
+
why: "this person is not known through direct trust or a shared group context.",
|
|
72
|
+
permits: [
|
|
73
|
+
"safe first-contact orientation only",
|
|
74
|
+
],
|
|
75
|
+
constraints: [
|
|
76
|
+
"first contact does not reach the full model on open channels",
|
|
77
|
+
"no local or privileged actions",
|
|
78
|
+
],
|
|
79
|
+
};
|
|
62
80
|
(0, observability_1.emitNervesEvent)({
|
|
63
81
|
component: "friends",
|
|
64
82
|
event: "friends.trust_explained",
|
package/dist/trust-mutation.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import type { FriendStore } from "./store";
|
|
2
2
|
import type { TrustLevel } from "./types";
|
|
3
3
|
import type { FriendOpResult } from "./results";
|
|
4
|
-
|
|
4
|
+
import type { AuditSink } from "./audit";
|
|
5
|
+
import type { TrustBasis } from "./trust-explanation";
|
|
6
|
+
/** Optional control-plane context for a trust mutation (Bug B). When a `sink` is
|
|
7
|
+
* supplied, a successful mutation appends one append-only control-plane audit
|
|
8
|
+
* record carrying WHO (`actor`), the `basis` and `originSense`, and WHEN. All
|
|
9
|
+
* fields are optional so the existing 3-arg callers are unaffected. */
|
|
10
|
+
export interface SetFriendTrustContext {
|
|
11
|
+
actor?: string;
|
|
12
|
+
originSense?: string;
|
|
13
|
+
basis?: TrustBasis;
|
|
14
|
+
sink?: AuditSink;
|
|
15
|
+
}
|
|
16
|
+
export declare function setFriendTrust(store: FriendStore, friendId: string, level: TrustLevel, ctx?: SetFriendTrustContext): Promise<FriendOpResult>;
|
package/dist/trust-mutation.js
CHANGED
|
@@ -7,7 +7,8 @@ exports.setFriendTrust = setFriendTrust;
|
|
|
7
7
|
// `trustLevel` and `role` to the same level (so the record's coarse role tracks
|
|
8
8
|
// its trust). A missing friend is a normal `not_found` result, never a throw.
|
|
9
9
|
const observability_1 = require("./observability");
|
|
10
|
-
|
|
10
|
+
const identity_1 = require("./identity");
|
|
11
|
+
async function setFriendTrust(store, friendId, level, ctx) {
|
|
11
12
|
(0, observability_1.emitNervesEvent)({
|
|
12
13
|
component: "friends",
|
|
13
14
|
event: "friends.trust_set",
|
|
@@ -16,14 +17,42 @@ async function setFriendTrust(store, friendId, level) {
|
|
|
16
17
|
});
|
|
17
18
|
const current = await store.get(friendId);
|
|
18
19
|
if (!current) {
|
|
20
|
+
// not_found is an early return BEFORE any mutation — and so writes NO audit
|
|
21
|
+
// record. The control-plane log captures actual standing changes only.
|
|
19
22
|
return { ok: false, status: "not_found", message: "friend record not found" };
|
|
20
23
|
}
|
|
24
|
+
const updatedAt = new Date().toISOString();
|
|
21
25
|
const updated = {
|
|
22
26
|
...current,
|
|
23
27
|
trustLevel: level,
|
|
24
28
|
role: level,
|
|
25
|
-
updatedAt
|
|
29
|
+
updatedAt,
|
|
26
30
|
};
|
|
27
31
|
await store.put(friendId, updated);
|
|
32
|
+
// Bug B — append one control-plane audit record on the successful mutation. The
|
|
33
|
+
// `targetDid` is the record's durable identity DID (identity.did, falling back to
|
|
34
|
+
// the migrated a2a.did via resolveAgentIdentity). `actor` defaults to the literal
|
|
35
|
+
// "unknown" when the caller threads no context. No sink ⇒ a clean no-op.
|
|
36
|
+
//
|
|
37
|
+
// NOTE (finding 6-B): the append runs AFTER store.put, so it is best-effort with
|
|
38
|
+
// respect to the mutation — if the sink append throws/crashes, the trust change is
|
|
39
|
+
// already persisted but the audit line may be missing. We keep this ordering on
|
|
40
|
+
// purpose (the mutation is the source of truth; the audit is an observability log,
|
|
41
|
+
// not a 2-phase-commit participant). A throwing sink rejects this call so the caller
|
|
42
|
+
// still sees the failure; it does not roll back the already-applied mutation.
|
|
43
|
+
if (ctx?.sink) {
|
|
44
|
+
const targetDid = (0, identity_1.resolveAgentIdentity)(current.agentMeta).did;
|
|
45
|
+
const record = {
|
|
46
|
+
action: "set_trust",
|
|
47
|
+
targetId: friendId,
|
|
48
|
+
...(targetDid !== undefined ? { targetDid } : {}),
|
|
49
|
+
level,
|
|
50
|
+
...(ctx.basis !== undefined ? { basis: ctx.basis } : {}),
|
|
51
|
+
actor: ctx.actor ?? "unknown",
|
|
52
|
+
...(ctx.originSense !== undefined ? { originSense: ctx.originSense } : {}),
|
|
53
|
+
ts: updatedAt,
|
|
54
|
+
};
|
|
55
|
+
await ctx.sink.append(record);
|
|
56
|
+
}
|
|
28
57
|
return { ok: true, status: "updated", record: updated };
|
|
29
58
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -75,6 +75,48 @@ export interface ImportedLearning {
|
|
|
75
75
|
assertedBy?: AgentAttribution;
|
|
76
76
|
originallyAssertedBy?: AgentAttribution;
|
|
77
77
|
}
|
|
78
|
+
export interface MissionTaskSpec {
|
|
79
|
+
/** Correlation key the result-return matches (PINNED). Minted by the producer. */
|
|
80
|
+
requestId: string;
|
|
81
|
+
/** What B is being asked to do (the headline ask). */
|
|
82
|
+
summary: string;
|
|
83
|
+
/** Optional longer brief. */
|
|
84
|
+
details?: string;
|
|
85
|
+
/** Optional structured inputs. */
|
|
86
|
+
inputs?: Record<string, string>;
|
|
87
|
+
}
|
|
88
|
+
export interface MissionResult {
|
|
89
|
+
/** Correlates to the gap-1 task-spec's requestId (PINNED) — A only accepts a result
|
|
90
|
+
* for a requestId it actually delegated. */
|
|
91
|
+
requestId: string;
|
|
92
|
+
/** The headline deliverable — what B produced. */
|
|
93
|
+
summary: string;
|
|
94
|
+
/** Optional larger produced artifact body. */
|
|
95
|
+
artifact?: string;
|
|
96
|
+
/** Optional structured outputs. */
|
|
97
|
+
outputs?: Record<string, string>;
|
|
98
|
+
/** first_party on B's side; imported (attributed to B) on A's. */
|
|
99
|
+
provenance?: NoteProvenance;
|
|
100
|
+
}
|
|
101
|
+
export interface MissionResultEnvelope {
|
|
102
|
+
/** The mission, named by its join key — `missionKey` + a human title. */
|
|
103
|
+
subject: {
|
|
104
|
+
missionKey: string;
|
|
105
|
+
title: string;
|
|
106
|
+
};
|
|
107
|
+
/** The agent that produced this result (B's join-key agentId) — the attribution.
|
|
108
|
+
* NOTE (security review inc-2 finding 5, by-design): this is SELF-ASSERTED and is
|
|
109
|
+
* vestigial on import — importMissionResult attributes + enforces against the
|
|
110
|
+
* TRANSPORT-supplied `ImportMissionResultInput.fromAgentId` (the authenticated channel
|
|
111
|
+
* identity), never this envelope field, so a forged value here changes nothing. */
|
|
112
|
+
fromAgentId: string;
|
|
113
|
+
/** The delegation correlation key (matches the gap-1 task-spec's requestId). */
|
|
114
|
+
requestId: string;
|
|
115
|
+
result: MissionResult;
|
|
116
|
+
/** Opaque, verifier-specific proof slot. The TOFU verifier ignores it. */
|
|
117
|
+
proof?: string;
|
|
118
|
+
issuedAt: string;
|
|
119
|
+
}
|
|
78
120
|
export type CoordinationIntent = "request" | "offer" | "accept" | "decline" | "handoff";
|
|
79
121
|
export declare function isCoordinationIntent(value: unknown): value is CoordinationIntent;
|
|
80
122
|
export interface CoordinationLogEntry {
|
|
@@ -99,6 +141,17 @@ export interface MissionRecord {
|
|
|
99
141
|
learnings: Record<string, MissionLearning>;
|
|
100
142
|
importedLearnings?: Record<string, Record<string, ImportedLearning>>;
|
|
101
143
|
coordination?: MissionCoordination;
|
|
144
|
+
delegations?: Record<string, {
|
|
145
|
+
task: MissionTaskSpec;
|
|
146
|
+
assignee?: AgentAttribution;
|
|
147
|
+
provenance: NoteProvenance;
|
|
148
|
+
}>;
|
|
149
|
+
importedDelegations?: Record<string, Record<string, {
|
|
150
|
+
task: MissionTaskSpec;
|
|
151
|
+
provenance: NoteProvenance;
|
|
152
|
+
}>>;
|
|
153
|
+
results?: Record<string, MissionResult>;
|
|
154
|
+
importedResults?: Record<string, Record<string, MissionResult>>;
|
|
102
155
|
createdAt: string;
|
|
103
156
|
updatedAt: string;
|
|
104
157
|
schemaVersion: number;
|
|
@@ -108,6 +161,17 @@ export interface AgentMeta {
|
|
|
108
161
|
familiarity: number;
|
|
109
162
|
sharedMissions: string[];
|
|
110
163
|
outcomes: RelationshipOutcome[];
|
|
164
|
+
/** The durable identity home (p11 Item 2 — the DID re-key). `did` is the
|
|
165
|
+
* cross-agent primary key; `pinnedKey` is its TOFU-pinned Ed25519 public key.
|
|
166
|
+
* Additive + optional: legacy records carry only `a2a.did` (or nothing) and
|
|
167
|
+
* migrate-on-read into this shape via `resolveAgentIdentity`. schemaVersion
|
|
168
|
+
* stays 1. */
|
|
169
|
+
identity?: {
|
|
170
|
+
did: string;
|
|
171
|
+
pinnedKey?: string;
|
|
172
|
+
handle?: string;
|
|
173
|
+
pinnedAt?: string;
|
|
174
|
+
};
|
|
111
175
|
a2a?: {
|
|
112
176
|
cardUrl?: string;
|
|
113
177
|
endpointUrl?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/friends",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "The who's-who / identity / relationship substrate for agents — trust ladder (family/friend/acquaintance/stranger), multi-party and multi-agent, consumed via the FriendStore interface + FriendResolver.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"example:cross-agent-mission-memory": "npm run build && tsx examples/cross-agent-mission-memory.ts",
|
|
47
47
|
"example:cross-agent-standing": "npm run build && tsx examples/cross-agent-standing.ts",
|
|
48
48
|
"example:cross-agent-coordination": "npm run build && tsx examples/cross-agent-coordination.ts",
|
|
49
|
+
"example:cross-agent-delegation": "npm run build && tsx examples/cross-agent-delegation.ts",
|
|
49
50
|
"example:cross-agent-a2a-relay": "npm run build && tsx examples/cross-agent-a2a-relay.ts",
|
|
50
51
|
"release:bump": "node scripts/release-bump.cjs",
|
|
51
52
|
"release:preflight": "node scripts/release-preflight.cjs",
|