@ouro.bot/cli 0.1.0-alpha.670 → 0.1.0-alpha.671
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.json +6 -0
- package/dist/a2a/onboarding.js +13 -41
- package/dist/heart/daemon/cli-exec.js +15 -56
- package/dist/repertoire/tools-notes.js +29 -38
- package/package.json +2 -2
package/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.671",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Consolidate friend-domain record logic into @ouro.bot/friends: re-pin the git dependency and route save_friend_note, the friend update/link/unlink CLI commands, and A2A peer onboarding through the package's applyFriendNote/setFriendTrust/linkExternalId/unlinkExternalId/upsertAgentPeer helpers, removing the duplicated in-harness record-mutation logic while keeping the MCP tool wrappers, CLI framing, and A2A HTTP card-fetch glue."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.670",
|
|
6
12
|
"changes": [
|
package/dist/a2a/onboarding.js
CHANGED
|
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.onboardA2APeer = onboardA2APeer;
|
|
37
|
-
const node_crypto_1 = require("node:crypto");
|
|
38
37
|
const path = __importStar(require("node:path"));
|
|
39
38
|
const identity_1 = require("../heart/identity");
|
|
40
39
|
const runtime_1 = require("../nerves/runtime");
|
|
@@ -52,60 +51,33 @@ function agentIdFor(_card, cardUrl) {
|
|
|
52
51
|
return parsed.toString();
|
|
53
52
|
}
|
|
54
53
|
async function onboardA2APeer(options) {
|
|
54
|
+
// HTTP/URL glue stays harness-side: fetch the agent card, resolve its JSON-RPC
|
|
55
|
+
// endpoint, and derive the stable agentId. The record-shaping (mint/update the
|
|
56
|
+
// agent-peer friend) is delegated to @ouro.bot/friends' upsertAgentPeer.
|
|
55
57
|
const card = await (0, client_1.fetchA2AAgentCard)(options.cardUrl, options.fetchImpl);
|
|
56
58
|
const store = storeFor(options);
|
|
57
|
-
const now = new Date().toISOString();
|
|
58
59
|
const externalId = agentIdFor(card, options.cardUrl);
|
|
59
60
|
/* v8 ignore next -- fetchA2AAgentCard validates a usable endpoint or legacy url before returning a card @preserve */
|
|
60
61
|
const endpointUrl = (0, client_1.endpointForCard)(card) ?? options.cardUrl;
|
|
61
62
|
const protocolVersion = card.supportedInterfaces?.find((entry) => entry.url === endpointUrl)?.protocolVersion
|
|
62
63
|
?? card.protocolVersion;
|
|
63
|
-
const existing = await store.findByExternalId("a2a-agent", externalId);
|
|
64
64
|
const name = options.name ?? card.name;
|
|
65
|
-
const
|
|
66
|
-
const baseMeta = existing?.agentMeta ?? {
|
|
67
|
-
bundleName: name,
|
|
68
|
-
familiarity: 0,
|
|
69
|
-
sharedMissions: [],
|
|
70
|
-
outcomes: [],
|
|
71
|
-
};
|
|
72
|
-
const record = {
|
|
73
|
-
...(existing ?? {
|
|
74
|
-
id: (0, node_crypto_1.randomUUID)(),
|
|
75
|
-
createdAt: now,
|
|
76
|
-
externalIds: [],
|
|
77
|
-
tenantMemberships: [],
|
|
78
|
-
toolPreferences: {},
|
|
79
|
-
notes: {},
|
|
80
|
-
totalTokens: 0,
|
|
81
|
-
schemaVersion: 1,
|
|
82
|
-
}),
|
|
65
|
+
const record = await (0, friends_1.upsertAgentPeer)(store, {
|
|
83
66
|
name,
|
|
84
|
-
|
|
85
|
-
trustLevel,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
cardUrl: options.cardUrl,
|
|
92
|
-
endpointUrl,
|
|
93
|
-
agentId: externalId,
|
|
94
|
-
protocolVersion,
|
|
95
|
-
},
|
|
67
|
+
agentId: externalId,
|
|
68
|
+
...(options.trustLevel ? { trustLevel: options.trustLevel } : {}),
|
|
69
|
+
a2a: {
|
|
70
|
+
cardUrl: options.cardUrl,
|
|
71
|
+
endpointUrl,
|
|
72
|
+
agentId: externalId,
|
|
73
|
+
protocolVersion,
|
|
96
74
|
},
|
|
97
|
-
|
|
98
|
-
...(existing?.externalIds.filter((id) => !(id.provider === "a2a-agent" && id.externalId === externalId)) ?? []),
|
|
99
|
-
{ provider: "a2a-agent", externalId, linkedAt: now },
|
|
100
|
-
],
|
|
101
|
-
updatedAt: now,
|
|
102
|
-
};
|
|
103
|
-
await store.put(record.id, record);
|
|
75
|
+
});
|
|
104
76
|
(0, runtime_1.emitNervesEvent)({
|
|
105
77
|
component: "friends",
|
|
106
78
|
event: "friends.a2a_peer_onboarded",
|
|
107
79
|
message: "onboarded A2A peer into friend model",
|
|
108
|
-
meta: { agentName: options.agentName, friendId: record.id, peerName: record.name, trustLevel },
|
|
80
|
+
meta: { agentName: options.agentName, friendId: record.id, peerName: record.name, trustLevel: record.trustLevel },
|
|
109
81
|
});
|
|
110
82
|
return record;
|
|
111
83
|
}
|
|
@@ -5419,14 +5419,6 @@ async function performSystemSetup(deps) {
|
|
|
5419
5419
|
await registerOuroBundleTypeNonBlocking(deps);
|
|
5420
5420
|
}
|
|
5421
5421
|
// ── Friend command execution ──
|
|
5422
|
-
const TRUST_RANK = { family: 4, friend: 3, acquaintance: 2, stranger: 1 };
|
|
5423
|
-
/* v8 ignore start -- defensive: ?? fallbacks are unreachable when inputs are valid TrustLevel values @preserve */
|
|
5424
|
-
function higherTrust(a, b) {
|
|
5425
|
-
const rankA = TRUST_RANK[a ?? "stranger"] ?? 1;
|
|
5426
|
-
const rankB = TRUST_RANK[b ?? "stranger"] ?? 1;
|
|
5427
|
-
return rankA >= rankB ? (a ?? "stranger") : (b ?? "stranger");
|
|
5428
|
-
}
|
|
5429
|
-
/* v8 ignore stop */
|
|
5430
5422
|
async function executeFriendCommand(command, store) {
|
|
5431
5423
|
if (command.kind === "friend.list") {
|
|
5432
5424
|
const listAll = store.listAll;
|
|
@@ -5467,65 +5459,32 @@ async function executeFriendCommand(command, store) {
|
|
|
5467
5459
|
return `created: ${id} (${command.name}, ${trustLevel})`;
|
|
5468
5460
|
}
|
|
5469
5461
|
if (command.kind === "friend.update") {
|
|
5470
|
-
const
|
|
5471
|
-
if (
|
|
5462
|
+
const result = await (0, friends_1.setFriendTrust)(store, command.friendId, command.trustLevel);
|
|
5463
|
+
if (result.status === "not_found")
|
|
5472
5464
|
return `friend not found: ${command.friendId}`;
|
|
5473
|
-
const now = new Date().toISOString();
|
|
5474
|
-
await store.put(command.friendId, {
|
|
5475
|
-
...current,
|
|
5476
|
-
trustLevel: command.trustLevel,
|
|
5477
|
-
role: command.trustLevel,
|
|
5478
|
-
updatedAt: now,
|
|
5479
|
-
});
|
|
5480
5465
|
return `updated: ${command.friendId} → trust=${command.trustLevel}`;
|
|
5481
5466
|
}
|
|
5482
5467
|
if (command.kind === "friend.link") {
|
|
5483
|
-
const
|
|
5484
|
-
|
|
5468
|
+
const result = await (0, friends_1.linkExternalId)(store, command.friendId, {
|
|
5469
|
+
provider: command.provider,
|
|
5470
|
+
externalId: command.externalId,
|
|
5471
|
+
});
|
|
5472
|
+
if (result.status === "not_found")
|
|
5485
5473
|
return `friend not found: ${command.friendId}`;
|
|
5486
|
-
|
|
5487
|
-
if (alreadyLinked)
|
|
5474
|
+
if (result.status === "noop")
|
|
5488
5475
|
return `identity already linked: ${command.provider}:${command.externalId}`;
|
|
5489
|
-
const
|
|
5490
|
-
const newExternalIds = [
|
|
5491
|
-
...current.externalIds,
|
|
5492
|
-
{ provider: command.provider, externalId: command.externalId, linkedAt: now },
|
|
5493
|
-
];
|
|
5494
|
-
// Orphan cleanup: check if another friend has this externalId
|
|
5495
|
-
const orphan = await store.findByExternalId(command.provider, command.externalId);
|
|
5496
|
-
let mergeMessage = "";
|
|
5497
|
-
let mergedNotes = { ...current.notes };
|
|
5498
|
-
let mergedTrust = current.trustLevel;
|
|
5499
|
-
let orphanExternalIds = [];
|
|
5500
|
-
if (orphan && orphan.id !== command.friendId) {
|
|
5501
|
-
// Merge orphan's notes (target's notes take priority)
|
|
5502
|
-
mergedNotes = { ...orphan.notes, ...current.notes };
|
|
5503
|
-
// Keep higher trust level
|
|
5504
|
-
mergedTrust = higherTrust(current.trustLevel, orphan.trustLevel);
|
|
5505
|
-
// Collect orphan's other externalIds (excluding the one being linked)
|
|
5506
|
-
orphanExternalIds = orphan.externalIds.filter((ext) => !(ext.provider === command.provider && ext.externalId === command.externalId));
|
|
5507
|
-
await store.delete(orphan.id);
|
|
5508
|
-
mergeMessage = ` (merged orphan ${orphan.id})`;
|
|
5509
|
-
}
|
|
5510
|
-
await store.put(command.friendId, {
|
|
5511
|
-
...current,
|
|
5512
|
-
externalIds: [...newExternalIds, ...orphanExternalIds],
|
|
5513
|
-
notes: mergedNotes,
|
|
5514
|
-
trustLevel: mergedTrust,
|
|
5515
|
-
updatedAt: now,
|
|
5516
|
-
});
|
|
5476
|
+
const mergeMessage = result.status === "merged" ? " (merged orphan)" : "";
|
|
5517
5477
|
return `linked ${command.provider}:${command.externalId} to ${command.friendId}${mergeMessage}`;
|
|
5518
5478
|
}
|
|
5519
5479
|
// command.kind === "friend.unlink"
|
|
5520
|
-
const
|
|
5521
|
-
|
|
5480
|
+
const result = await (0, friends_1.unlinkExternalId)(store, command.friendId, {
|
|
5481
|
+
provider: command.provider,
|
|
5482
|
+
externalId: command.externalId,
|
|
5483
|
+
});
|
|
5484
|
+
if (result.status === "not_found")
|
|
5522
5485
|
return `friend not found: ${command.friendId}`;
|
|
5523
|
-
|
|
5524
|
-
if (idx === -1)
|
|
5486
|
+
if (result.status === "noop")
|
|
5525
5487
|
return `identity not linked: ${command.provider}:${command.externalId}`;
|
|
5526
|
-
const now = new Date().toISOString();
|
|
5527
|
-
const filtered = current.externalIds.filter((_, i) => i !== idx);
|
|
5528
|
-
await store.put(command.friendId, { ...current, externalIds: filtered, updatedAt: now });
|
|
5529
5488
|
return `unlinked ${command.provider}:${command.externalId} from ${command.friendId}`;
|
|
5530
5489
|
}
|
|
5531
5490
|
async function executeA2ACommand(command, deps) {
|
|
@@ -40,6 +40,7 @@ const skills_1 = require("./skills");
|
|
|
40
40
|
const config_1 = require("../heart/config");
|
|
41
41
|
const runtime_1 = require("../nerves/runtime");
|
|
42
42
|
const identity_1 = require("../heart/identity");
|
|
43
|
+
const friends_1 = require("@ouro.bot/friends");
|
|
43
44
|
const diary_1 = require("../mind/diary");
|
|
44
45
|
const record_paths_1 = require("../mind/record-paths");
|
|
45
46
|
const provenance_trust_1 = require("../mind/provenance-trust");
|
|
@@ -414,7 +415,8 @@ exports.notesToolDefinitions = [
|
|
|
414
415
|
const friendId = ctx.context.friend?.id;
|
|
415
416
|
if (!friendId)
|
|
416
417
|
return "i can't save notes -- no friend identity available";
|
|
417
|
-
// Validate parameters
|
|
418
|
+
// Validate parameters (input-shape guards stay harness-side so we keep the
|
|
419
|
+
// first-person tool wording; applyFriendNote does the record mutation).
|
|
418
420
|
if (!a.content)
|
|
419
421
|
return "i need a content value to save";
|
|
420
422
|
const validTypes = ["name", "tool_preference", "note"];
|
|
@@ -422,44 +424,33 @@ exports.notesToolDefinitions = [
|
|
|
422
424
|
return `i don't recognize type '${a.type}' -- use name, tool_preference, or note`;
|
|
423
425
|
if ((a.type === "tool_preference" || a.type === "note") && !a.key)
|
|
424
426
|
return "i need a key for tool_preference or note type";
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const updated = { ...record, toolPreferences: { ...record.toolPreferences, [a.key]: a.content }, updatedAt: new Date().toISOString() };
|
|
442
|
-
await ctx.friendStore.put(friendId, updated);
|
|
443
|
-
return `saved: toolPreference ${a.key} = ${a.content}`;
|
|
444
|
-
}
|
|
445
|
-
// type === "note"
|
|
446
|
-
// Redirect "name" key to name field
|
|
447
|
-
if (a.key === "name") {
|
|
448
|
-
const updated = { ...record, name: a.content, updatedAt: new Date().toISOString() };
|
|
449
|
-
await ctx.friendStore.put(friendId, updated);
|
|
427
|
+
// Record-domain logic lives in @ouro.bot/friends; this wrapper maps the
|
|
428
|
+
// structured FriendOpResult back to the tool's first-person strings.
|
|
429
|
+
const result = await (0, friends_1.applyFriendNote)(ctx.friendStore, friendId, {
|
|
430
|
+
type: a.type,
|
|
431
|
+
...(a.key !== undefined ? { key: a.key } : {}),
|
|
432
|
+
content: a.content,
|
|
433
|
+
override: a.override === "true",
|
|
434
|
+
});
|
|
435
|
+
switch (result.status) {
|
|
436
|
+
case "saved":
|
|
437
|
+
if (a.type === "name")
|
|
438
|
+
return `saved: name = ${a.content}`;
|
|
439
|
+
if (a.type === "tool_preference")
|
|
440
|
+
return `saved: toolPreference ${a.key} = ${a.content}`;
|
|
441
|
+
return `saved: note ${a.key} = ${a.content}`;
|
|
442
|
+
case "redirected_to_name":
|
|
450
443
|
return `updated friend's name to '${a.content}' (stored as name, not a note)`;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
/* v8 ignore next -- defensive: non-Error branch for String(err) @preserve */
|
|
462
|
-
return `error saving note: ${err instanceof Error ? err.message : String(err)}`;
|
|
444
|
+
case "override_required":
|
|
445
|
+
// result.message embeds the existing value; append the harness merge instruction.
|
|
446
|
+
return `${result.message}. if you want to replace it, call again with override: true. or merge both values into content and override.`;
|
|
447
|
+
case "not_found":
|
|
448
|
+
return "i can't find the friend record on disk";
|
|
449
|
+
/* v8 ignore next 2 -- invalid is pre-empted by the harness validation above; kept for exhaustiveness @preserve */
|
|
450
|
+
case "invalid":
|
|
451
|
+
return result.message ?? "i can't save that note";
|
|
452
|
+
default:
|
|
453
|
+
return `error saving note: ${result.message}`;
|
|
463
454
|
}
|
|
464
455
|
},
|
|
465
456
|
summaryKeys: ["type", "key", "content"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.671",
|
|
4
4
|
"main": "dist/heart/daemon/ouro-entry.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cli": "dist/heart/daemon/ouro-bot-entry.js",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
53
|
-
"@ouro.bot/friends": "git+https://github.com/ourostack/friends.git#
|
|
53
|
+
"@ouro.bot/friends": "git+https://github.com/ourostack/friends.git#250d1a4bbbad5cd50687975afc463e60e3ff8366",
|
|
54
54
|
"@azure/identity": "^4.13.0",
|
|
55
55
|
"@azure/storage-blob": "^12.31.0",
|
|
56
56
|
"@microsoft/teams.api": "2.0.11",
|