@ouro.bot/cli 0.1.0-alpha.186 → 0.1.0-alpha.187

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 CHANGED
@@ -2,8 +2,9 @@
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
4
  {
5
- "version": "0.1.0-alpha.186",
5
+ "version": "0.1.0-alpha.187",
6
6
  "changes": [
7
+ "refactor: collapse AgentRelationship into FriendRecord — one identity system for humans and agents",
7
8
  "refactor: rename AdoptionSpecialist to SerpentGuide",
8
9
  "feat(hatch): detect API keys from environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, AZURE_OPENAI_API_KEY, MINIMAX_API_KEY, GITHUB_TOKEN)",
9
10
  "fix(cli): React unmount warning suppression covers SerpentGuide exit path"
@@ -39,7 +39,6 @@ exports.readPresence = readPresence;
39
39
  exports.readPeerPresence = readPeerPresence;
40
40
  const fs = __importStar(require("fs"));
41
41
  const path = __importStar(require("path"));
42
- const os = __importStar(require("os"));
43
42
  const runtime_1 = require("../nerves/runtime");
44
43
  function presenceDir(agentRoot) {
45
44
  return path.join(agentRoot, "state", "presence");
@@ -145,40 +144,41 @@ function readPresence(agentRoot, _agentName) {
145
144
  }
146
145
  }
147
146
  function readPeerPresence(agentRoot) {
148
- const relDir = path.join(agentRoot, "state", "relationships");
149
- if (!fs.existsSync(relDir)) {
147
+ const friendsDir = path.join(agentRoot, "friends");
148
+ if (!fs.existsSync(friendsDir)) {
150
149
  (0, runtime_1.emitNervesEvent)({
151
150
  component: "heart",
152
151
  event: "heart.peer_presence_read",
153
- message: "no relationships directory, no peers",
152
+ message: "no friends directory, no peers",
154
153
  meta: { peerCount: 0 },
155
154
  });
156
155
  return [];
157
156
  }
158
- const files = fs.readdirSync(relDir).filter((f) => f.endsWith(".json"));
157
+ const files = fs.readdirSync(friendsDir).filter((f) => f.endsWith(".json"));
159
158
  const peers = [];
160
159
  for (const file of files) {
161
160
  try {
162
- const raw = fs.readFileSync(path.join(relDir, file), "utf-8");
163
- const rel = JSON.parse(raw);
164
- const peerName = rel.agentName;
165
- // Read peer's presence from their bundle
166
- const peerRoot = path.join(os.homedir(), "AgentBundles", `${peerName}.ouro`);
167
- const peerPresencePath = path.join(peerRoot, "state", "presence", "self.json");
168
- if (fs.existsSync(peerPresencePath)) {
169
- const presenceRaw = fs.readFileSync(peerPresencePath, "utf-8");
170
- const presence = JSON.parse(presenceRaw);
171
- peers.push(presence);
172
- }
161
+ const raw = fs.readFileSync(path.join(friendsDir, file), "utf-8");
162
+ const friend = JSON.parse(raw);
163
+ if (friend.kind !== "agent")
164
+ continue;
165
+ peers.push({
166
+ agentName: friend.name ?? path.basename(file, ".json"),
167
+ availability: "idle",
168
+ lane: "idle",
169
+ mission: "",
170
+ tempo: "brief",
171
+ updatedAt: friend.updatedAt ?? new Date().toISOString(),
172
+ });
173
173
  }
174
174
  catch {
175
- // Skip peers with unreadable data
175
+ // Skip malformed or unreadable files
176
176
  }
177
177
  }
178
178
  (0, runtime_1.emitNervesEvent)({
179
179
  component: "heart",
180
180
  event: "heart.peer_presence_read",
181
- message: `read ${peers.length} peer presence records`,
181
+ message: `read ${peers.length} agent peer records from friends`,
182
182
  meta: { peerCount: peers.length },
183
183
  });
184
184
  return peers;
@@ -127,6 +127,8 @@ class FileFriendStore {
127
127
  trustLevel === "stranger"
128
128
  ? trustLevel
129
129
  : DEFAULT_TRUST_LEVEL;
130
+ const kind = raw.kind === "human" || raw.kind === "agent" ? raw.kind : "human";
131
+ const agentMeta = kind === "agent" ? this.normalizeAgentMeta(raw.agentMeta) : undefined;
130
132
  return {
131
133
  id: raw.id,
132
134
  name: raw.name,
@@ -153,6 +155,21 @@ class FileFriendStore {
153
155
  createdAt: typeof raw.createdAt === "string" ? raw.createdAt : new Date().toISOString(),
154
156
  updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : new Date().toISOString(),
155
157
  schemaVersion: typeof raw.schemaVersion === "number" ? raw.schemaVersion : 1,
158
+ kind,
159
+ agentMeta,
160
+ };
161
+ }
162
+ normalizeAgentMeta(raw) {
163
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
164
+ return undefined;
165
+ const meta = raw;
166
+ if (typeof meta.bundleName !== "string")
167
+ return undefined;
168
+ return {
169
+ bundleName: meta.bundleName,
170
+ familiarity: typeof meta.familiarity === "number" ? meta.familiarity : 0,
171
+ sharedMissions: Array.isArray(meta.sharedMissions) ? meta.sharedMissions : [],
172
+ outcomes: Array.isArray(meta.outcomes) ? meta.outcomes : [],
156
173
  };
157
174
  }
158
175
  async readJson(filePath) {
@@ -64,7 +64,6 @@ const cross_chat_delivery_1 = require("../heart/cross-chat-delivery");
64
64
  const obligations_2 = require("../heart/obligations");
65
65
  const episodes_1 = require("../mind/episodes");
66
66
  const cares_1 = require("../heart/cares");
67
- const agent_relationships_1 = require("../heart/agent-relationships");
68
67
  const presence_1 = require("../heart/presence");
69
68
  const intentions_1 = require("../heart/intentions");
70
69
  // Tracks which file paths have been read via read_file in this session.
@@ -1675,13 +1674,15 @@ exports.baseToolDefinitions = [
1675
1674
  },
1676
1675
  },
1677
1676
  },
1678
- handler: (a) => {
1679
- const agentRoot = (0, identity_1.getAgentRoot)();
1680
- const result = a.agentName
1681
- ? (0, agent_relationships_1.readRelationship)(agentRoot, a.agentName)
1682
- : (0, agent_relationships_1.readRelationships)(agentRoot);
1677
+ handler: async (a, ctx) => {
1678
+ const allFriends = ctx?.friendStore?.listAll ? await ctx.friendStore.listAll() : [];
1679
+ let agents = allFriends.filter((f) => f.kind === "agent");
1680
+ if (a.agentName) {
1681
+ const needle = a.agentName.toLowerCase();
1682
+ agents = agents.filter((f) => f.name?.toLowerCase() === needle);
1683
+ }
1683
1684
  (0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_relationships", message: `queried relationships`, meta: { agentName: a.agentName ?? "all" } });
1684
- return JSON.stringify(result, null, 2);
1685
+ return JSON.stringify(agents, null, 2);
1685
1686
  },
1686
1687
  },
1687
1688
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.186",
3
+ "version": "0.1.0-alpha.187",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",
@@ -1,161 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.recordInteraction = recordInteraction;
37
- exports.readRelationships = readRelationships;
38
- exports.readRelationship = readRelationship;
39
- exports.recordOutcome = recordOutcome;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
42
- const runtime_1 = require("../nerves/runtime");
43
- function relationshipsDir(agentRoot) {
44
- return path.join(agentRoot, "state", "relationships");
45
- }
46
- function relationshipFilePath(agentRoot, agentName) {
47
- return path.join(relationshipsDir(agentRoot), `${agentName.toLowerCase()}.json`);
48
- }
49
- function readRelationshipFile(agentRoot, agentName) {
50
- const filePath = relationshipFilePath(agentRoot, agentName);
51
- if (!fs.existsSync(filePath)) {
52
- return null;
53
- }
54
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
55
- }
56
- function writeRelationshipFile(agentRoot, rel) {
57
- const dir = relationshipsDir(agentRoot);
58
- fs.mkdirSync(dir, { recursive: true });
59
- fs.writeFileSync(path.join(dir, `${rel.agentName}.json`), JSON.stringify(rel, null, 2), "utf-8");
60
- }
61
- function recordInteraction(agentRoot, agentName, context) {
62
- const normalizedName = agentName.toLowerCase();
63
- const now = new Date().toISOString();
64
- const existing = readRelationshipFile(agentRoot, normalizedName);
65
- if (existing) {
66
- existing.familiarity += 1;
67
- existing.lastInteraction = now;
68
- if (context.displayName) {
69
- existing.displayName = context.displayName;
70
- }
71
- if (context.missionId && !existing.sharedMissions.includes(context.missionId)) {
72
- existing.sharedMissions.push(context.missionId);
73
- }
74
- if (context.note) {
75
- existing.notes.push(context.note);
76
- }
77
- writeRelationshipFile(agentRoot, existing);
78
- (0, runtime_1.emitNervesEvent)({
79
- component: "heart",
80
- event: "heart.relationship_updated",
81
- message: `relationship updated: ${normalizedName}`,
82
- meta: { agentName: normalizedName, familiarity: existing.familiarity },
83
- });
84
- return existing;
85
- }
86
- const rel = {
87
- agentName: normalizedName,
88
- displayName: context.displayName ?? normalizedName,
89
- familiarity: 1,
90
- trust: "neutral",
91
- sharedMissions: context.missionId ? [context.missionId] : [],
92
- lastInteraction: now,
93
- outcomes: [],
94
- notes: context.note ? [context.note] : [],
95
- };
96
- writeRelationshipFile(agentRoot, rel);
97
- (0, runtime_1.emitNervesEvent)({
98
- component: "heart",
99
- event: "heart.relationship_created",
100
- message: `relationship created: ${normalizedName}`,
101
- meta: { agentName: normalizedName },
102
- });
103
- return rel;
104
- }
105
- function readRelationships(agentRoot) {
106
- const dir = relationshipsDir(agentRoot);
107
- if (!fs.existsSync(dir)) {
108
- (0, runtime_1.emitNervesEvent)({
109
- component: "heart",
110
- event: "heart.relationships_read",
111
- message: "read relationships: directory missing, returning empty",
112
- meta: { count: 0 },
113
- });
114
- return [];
115
- }
116
- const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
117
- const relationships = [];
118
- for (const file of files) {
119
- try {
120
- const content = fs.readFileSync(path.join(dir, file), "utf-8");
121
- const rel = JSON.parse(content);
122
- relationships.push(rel);
123
- }
124
- catch {
125
- // Skip malformed JSON files
126
- }
127
- }
128
- (0, runtime_1.emitNervesEvent)({
129
- component: "heart",
130
- event: "heart.relationships_read",
131
- message: `read ${relationships.length} relationships`,
132
- meta: { count: relationships.length },
133
- });
134
- return relationships;
135
- }
136
- function readRelationship(agentRoot, agentName) {
137
- const rel = readRelationshipFile(agentRoot, agentName);
138
- (0, runtime_1.emitNervesEvent)({
139
- component: "heart",
140
- event: "heart.relationship_read",
141
- message: rel ? `read relationship: ${agentName.toLowerCase()}` : `relationship not found: ${agentName.toLowerCase()}`,
142
- meta: { agentName: agentName.toLowerCase(), found: !!rel },
143
- });
144
- return rel;
145
- }
146
- function recordOutcome(agentRoot, agentName, outcome) {
147
- const normalizedName = agentName.toLowerCase();
148
- const existing = readRelationshipFile(agentRoot, normalizedName);
149
- if (!existing) {
150
- throw new Error(`Agent relationship not found: ${normalizedName}`);
151
- }
152
- existing.outcomes.push(outcome);
153
- writeRelationshipFile(agentRoot, existing);
154
- (0, runtime_1.emitNervesEvent)({
155
- component: "heart",
156
- event: "heart.outcome_recorded",
157
- message: `outcome recorded for ${normalizedName}: ${outcome.result}`,
158
- meta: { agentName: normalizedName, missionId: outcome.missionId, result: outcome.result },
159
- });
160
- return existing;
161
- }