brainclaw 0.19.2

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/LICENSE +74 -0
  2. package/README.md +226 -0
  3. package/dist/cli.js +1037 -0
  4. package/dist/commands/accept.js +149 -0
  5. package/dist/commands/adapter-openclaw-import.js +75 -0
  6. package/dist/commands/add-step.js +35 -0
  7. package/dist/commands/agent-board.js +106 -0
  8. package/dist/commands/audit.js +35 -0
  9. package/dist/commands/bootstrap.js +34 -0
  10. package/dist/commands/capability.js +104 -0
  11. package/dist/commands/changes.js +112 -0
  12. package/dist/commands/check-constraints.js +63 -0
  13. package/dist/commands/claim-resource.js +54 -0
  14. package/dist/commands/claim.js +92 -0
  15. package/dist/commands/complete-step.js +34 -0
  16. package/dist/commands/constraint.js +44 -0
  17. package/dist/commands/context-diff.js +32 -0
  18. package/dist/commands/context.js +63 -0
  19. package/dist/commands/decision.js +45 -0
  20. package/dist/commands/delete-plan.js +20 -0
  21. package/dist/commands/diff.js +99 -0
  22. package/dist/commands/doctor.js +1275 -0
  23. package/dist/commands/enable-agent.js +63 -0
  24. package/dist/commands/env.js +46 -0
  25. package/dist/commands/estimation-report.js +167 -0
  26. package/dist/commands/explore.js +47 -0
  27. package/dist/commands/export.js +381 -0
  28. package/dist/commands/handoff.js +63 -0
  29. package/dist/commands/history.js +22 -0
  30. package/dist/commands/hooks.js +123 -0
  31. package/dist/commands/init.js +356 -0
  32. package/dist/commands/install-hooks.js +115 -0
  33. package/dist/commands/instruction.js +56 -0
  34. package/dist/commands/list-agents.js +44 -0
  35. package/dist/commands/list-claims.js +45 -0
  36. package/dist/commands/list-instructions.js +50 -0
  37. package/dist/commands/list-plans.js +48 -0
  38. package/dist/commands/mcp-worker.js +12 -0
  39. package/dist/commands/mcp.js +2272 -0
  40. package/dist/commands/memory.js +283 -0
  41. package/dist/commands/metrics.js +175 -0
  42. package/dist/commands/plan-resource.js +62 -0
  43. package/dist/commands/plan.js +76 -0
  44. package/dist/commands/prune-candidates.js +36 -0
  45. package/dist/commands/prune.js +48 -0
  46. package/dist/commands/pull.js +25 -0
  47. package/dist/commands/push.js +28 -0
  48. package/dist/commands/rebuild.js +14 -0
  49. package/dist/commands/reflect-runtime-note.js +74 -0
  50. package/dist/commands/reflect.js +286 -0
  51. package/dist/commands/register-agent.js +29 -0
  52. package/dist/commands/reject.js +52 -0
  53. package/dist/commands/release-claim.js +41 -0
  54. package/dist/commands/release-claims.js +67 -0
  55. package/dist/commands/review.js +242 -0
  56. package/dist/commands/rollback.js +156 -0
  57. package/dist/commands/runtime-note.js +144 -0
  58. package/dist/commands/runtime-status.js +49 -0
  59. package/dist/commands/search.js +36 -0
  60. package/dist/commands/session-end.js +187 -0
  61. package/dist/commands/session-start.js +147 -0
  62. package/dist/commands/set-trust.js +92 -0
  63. package/dist/commands/setup.js +446 -0
  64. package/dist/commands/show-candidate.js +31 -0
  65. package/dist/commands/star-candidate.js +28 -0
  66. package/dist/commands/status.js +133 -0
  67. package/dist/commands/sync.js +159 -0
  68. package/dist/commands/tool.js +126 -0
  69. package/dist/commands/trap.js +74 -0
  70. package/dist/commands/update-handoff.js +23 -0
  71. package/dist/commands/update-plan.js +37 -0
  72. package/dist/commands/upgrade.js +382 -0
  73. package/dist/commands/use-candidate.js +35 -0
  74. package/dist/commands/version.js +96 -0
  75. package/dist/commands/watch.js +215 -0
  76. package/dist/commands/whoami.js +104 -0
  77. package/dist/core/agent-context.js +340 -0
  78. package/dist/core/agent-files.js +874 -0
  79. package/dist/core/agent-integrations.js +135 -0
  80. package/dist/core/agent-inventory.js +401 -0
  81. package/dist/core/agent-registry.js +420 -0
  82. package/dist/core/ai-agent-detection.js +140 -0
  83. package/dist/core/audit.js +85 -0
  84. package/dist/core/bootstrap.js +658 -0
  85. package/dist/core/brainclaw-version.js +433 -0
  86. package/dist/core/candidates.js +137 -0
  87. package/dist/core/circuit-breaker.js +118 -0
  88. package/dist/core/claims.js +72 -0
  89. package/dist/core/config.js +86 -0
  90. package/dist/core/context-diff.js +122 -0
  91. package/dist/core/context.js +1212 -0
  92. package/dist/core/contradictions.js +270 -0
  93. package/dist/core/coordination.js +86 -0
  94. package/dist/core/cross-project.js +99 -0
  95. package/dist/core/duplicates.js +72 -0
  96. package/dist/core/event-log.js +152 -0
  97. package/dist/core/events.js +56 -0
  98. package/dist/core/execution-context.js +204 -0
  99. package/dist/core/freshness.js +87 -0
  100. package/dist/core/global-registry.js +182 -0
  101. package/dist/core/host.js +10 -0
  102. package/dist/core/identity.js +151 -0
  103. package/dist/core/ids.js +56 -0
  104. package/dist/core/input-validation.js +81 -0
  105. package/dist/core/instructions.js +117 -0
  106. package/dist/core/io.js +191 -0
  107. package/dist/core/json-store.js +63 -0
  108. package/dist/core/lifecycle.js +45 -0
  109. package/dist/core/lock.js +129 -0
  110. package/dist/core/logger.js +49 -0
  111. package/dist/core/machine-profile.js +332 -0
  112. package/dist/core/markdown.js +120 -0
  113. package/dist/core/memory-git.js +133 -0
  114. package/dist/core/migration.js +247 -0
  115. package/dist/core/project-registry.js +64 -0
  116. package/dist/core/reflection-safety.js +21 -0
  117. package/dist/core/repo-analysis.js +133 -0
  118. package/dist/core/reputation.js +409 -0
  119. package/dist/core/runtime.js +134 -0
  120. package/dist/core/schema.js +580 -0
  121. package/dist/core/search.js +115 -0
  122. package/dist/core/security.js +66 -0
  123. package/dist/core/setup-state.js +50 -0
  124. package/dist/core/state.js +83 -0
  125. package/dist/core/store-resolution.js +119 -0
  126. package/dist/core/sync-remote.js +83 -0
  127. package/dist/core/traps.js +86 -0
  128. package/package.json +60 -0
@@ -0,0 +1,409 @@
1
+ import { listAgentIdentities, resolveCurrentAgentIdentity } from './agent-registry.js';
2
+ import { listArchivedCandidates, listCandidates } from './candidates.js';
3
+ import { listClaims } from './claims.js';
4
+ import { loadConfig } from './config.js';
5
+ import { nowISO } from './ids.js';
6
+ import { listRuntimeNotes } from './runtime.js';
7
+ function clampScore(value) {
8
+ if (!Number.isFinite(value)) {
9
+ return 0;
10
+ }
11
+ return Math.max(0, Math.min(100, Math.round(value)));
12
+ }
13
+ function createAccumulator(identity) {
14
+ return {
15
+ identity,
16
+ signals: {
17
+ candidates_authored: 0,
18
+ pending_candidates: 0,
19
+ accepted_candidates: 0,
20
+ rejected_candidates_authored: 0,
21
+ promoted_runtime_candidates: 0,
22
+ promoted_runtime_accepted: 0,
23
+ stars_received: 0,
24
+ uses_received: 0,
25
+ accepted_reviews: 0,
26
+ rejected_reviews: 0,
27
+ reasoned_rejections: 0,
28
+ runtime_notes_created: 0,
29
+ plan_linked_activity: 0,
30
+ claims_created: 0,
31
+ released_claims: 0,
32
+ orphan_runtime_noise: 0,
33
+ },
34
+ };
35
+ }
36
+ function buildIdentityResolvers(registered) {
37
+ const byId = new Map();
38
+ const byName = new Map();
39
+ for (const agent of registered) {
40
+ byId.set(agent.agent_id, agent);
41
+ byName.set(agent.agent_name.trim().toLowerCase(), agent);
42
+ }
43
+ return {
44
+ resolve(value) {
45
+ const trimmed = value?.trim();
46
+ if (!trimmed) {
47
+ return undefined;
48
+ }
49
+ const byAgentId = byId.get(trimmed);
50
+ if (byAgentId) {
51
+ return {
52
+ key: byAgentId.agent_id,
53
+ agent_id: byAgentId.agent_id,
54
+ agent_name: byAgentId.agent_name,
55
+ kind: 'registered-agent',
56
+ };
57
+ }
58
+ const byAgentName = byName.get(trimmed.toLowerCase());
59
+ if (byAgentName) {
60
+ return {
61
+ key: byAgentName.agent_id,
62
+ agent_id: byAgentName.agent_id,
63
+ agent_name: byAgentName.agent_name,
64
+ kind: 'registered-agent',
65
+ };
66
+ }
67
+ return {
68
+ key: `actor:${trimmed.toLowerCase()}`,
69
+ agent_name: trimmed,
70
+ kind: 'actor',
71
+ };
72
+ },
73
+ };
74
+ }
75
+ function withinWindow(timestamp, sinceMs) {
76
+ if (!timestamp) {
77
+ return false;
78
+ }
79
+ const parsed = Date.parse(timestamp);
80
+ if (Number.isNaN(parsed)) {
81
+ return false;
82
+ }
83
+ return parsed >= sinceMs;
84
+ }
85
+ function getAccumulator(store, identity) {
86
+ const existing = store.get(identity.key);
87
+ if (existing) {
88
+ return existing;
89
+ }
90
+ const created = createAccumulator(identity);
91
+ store.set(identity.key, created);
92
+ return created;
93
+ }
94
+ function trackCandidateSignals(candidate, bucket, store, sinceMs, config, resolveIdentity) {
95
+ if (!withinWindow(candidate.created_at, sinceMs) && !withinWindow(candidate.resolved_at, sinceMs)) {
96
+ return;
97
+ }
98
+ const author = resolveIdentity(candidate.author_id ?? candidate.author);
99
+ if (author) {
100
+ const stats = getAccumulator(store, author);
101
+ stats.signals.candidates_authored += 1;
102
+ stats.signals.stars_received += candidate.star_count ?? 0;
103
+ stats.signals.uses_received += candidate.usage_count ?? 0;
104
+ if (bucket === 'pending') {
105
+ stats.signals.pending_candidates += 1;
106
+ }
107
+ if (bucket === 'accepted') {
108
+ stats.signals.accepted_candidates += 1;
109
+ }
110
+ if (bucket === 'rejected') {
111
+ stats.signals.rejected_candidates_authored += 1;
112
+ }
113
+ if (candidate.source?.startsWith('runtime-note:')) {
114
+ stats.signals.promoted_runtime_candidates += 1;
115
+ if (bucket === 'accepted') {
116
+ stats.signals.promoted_runtime_accepted += 1;
117
+ }
118
+ }
119
+ }
120
+ const reviewer = resolveIdentity(candidate.resolved_by);
121
+ if (reviewer && bucket !== 'pending' && withinWindow(candidate.resolved_at, sinceMs)) {
122
+ const stats = getAccumulator(store, reviewer);
123
+ if (bucket === 'accepted') {
124
+ stats.signals.accepted_reviews += 1;
125
+ }
126
+ if (bucket === 'rejected') {
127
+ stats.signals.rejected_reviews += 1;
128
+ if (candidate.resolution_reason?.trim()) {
129
+ stats.signals.reasoned_rejections += 1;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ function trackRuntimeSignals(note, store, sinceMs, resolveIdentity) {
135
+ if (!withinWindow(note.created_at, sinceMs)) {
136
+ return;
137
+ }
138
+ const identity = resolveIdentity(note.agent_id ?? note.agent);
139
+ if (!identity) {
140
+ return;
141
+ }
142
+ const stats = getAccumulator(store, identity);
143
+ stats.signals.runtime_notes_created += 1;
144
+ if (note.plan_id) {
145
+ stats.signals.plan_linked_activity += 1;
146
+ }
147
+ }
148
+ function trackClaimSignals(claim, store, sinceMs, resolveIdentity) {
149
+ if (!withinWindow(claim.created_at, sinceMs) && !withinWindow(claim.released_at, sinceMs)) {
150
+ return;
151
+ }
152
+ const identity = resolveIdentity(claim.agent_id ?? claim.agent);
153
+ if (!identity) {
154
+ return;
155
+ }
156
+ const stats = getAccumulator(store, identity);
157
+ stats.signals.claims_created += 1;
158
+ if (claim.plan_id) {
159
+ stats.signals.plan_linked_activity += 1;
160
+ }
161
+ if (claim.status === 'released' && withinWindow(claim.released_at, sinceMs)) {
162
+ stats.signals.released_claims += 1;
163
+ }
164
+ }
165
+ function finalizeSnapshot(accumulator) {
166
+ const orphanRuntimeNoise = Math.max(0, accumulator.signals.runtime_notes_created - accumulator.signals.promoted_runtime_candidates - accumulator.signals.plan_linked_activity);
167
+ accumulator.signals.orphan_runtime_noise = orphanRuntimeNoise;
168
+ const boundedStars = Math.min(accumulator.signals.stars_received, 5);
169
+ const boundedUses = Math.min(accumulator.signals.uses_received, 4);
170
+ const boundedRuntimeNotes = Math.min(accumulator.signals.runtime_notes_created, 4);
171
+ const boundedPromotions = Math.min(accumulator.signals.promoted_runtime_candidates, 4);
172
+ const boundedPlanActivity = Math.min(accumulator.signals.plan_linked_activity, 4);
173
+ const boundedNoise = Math.min(accumulator.signals.orphan_runtime_noise, 4);
174
+ const contributionQuality = clampScore(35 * accumulator.signals.accepted_candidates
175
+ + 20 * accumulator.signals.promoted_runtime_accepted
176
+ + 10 * boundedUses
177
+ + 4 * boundedStars
178
+ - 12 * accumulator.signals.rejected_candidates_authored);
179
+ const reviewReliability = clampScore(30 * accumulator.signals.accepted_reviews
180
+ + 18 * accumulator.signals.rejected_reviews
181
+ + 4 * accumulator.signals.reasoned_rejections);
182
+ const continuityHygiene = clampScore(12 * boundedRuntimeNotes
183
+ + 12 * boundedPromotions
184
+ + 8 * boundedPlanActivity
185
+ + 4 * Math.min(accumulator.signals.released_claims, 4)
186
+ - 6 * boundedNoise);
187
+ const internalTrust = clampScore(contributionQuality * 0.5 + reviewReliability * 0.3 + continuityHygiene * 0.2);
188
+ return {
189
+ key: accumulator.identity.key,
190
+ agent_id: accumulator.identity.agent_id,
191
+ agent_name: accumulator.identity.agent_name,
192
+ kind: accumulator.identity.kind,
193
+ signals: accumulator.signals,
194
+ scores: {
195
+ contribution_quality: contributionQuality,
196
+ review_reliability: reviewReliability,
197
+ continuity_hygiene: continuityHygiene,
198
+ internal_trust: internalTrust,
199
+ },
200
+ };
201
+ }
202
+ export function buildReputationSnapshot(cwd) {
203
+ const config = loadConfig(cwd);
204
+ const reputationConfig = config.reputation ?? {
205
+ enabled: false,
206
+ visibility: 'internal-only',
207
+ decay_days: 30,
208
+ ranking_weight: 0.15,
209
+ resume_weight: 0.35,
210
+ mcp_exposure: false,
211
+ };
212
+ const registered = listAgentIdentities(cwd);
213
+ const currentAgent = resolveCurrentAgentIdentity(cwd);
214
+ const resolvers = buildIdentityResolvers(registered);
215
+ const store = new Map();
216
+ const sinceMs = Date.now() - reputationConfig.decay_days * 24 * 60 * 60 * 1000;
217
+ for (const agent of registered) {
218
+ getAccumulator(store, {
219
+ key: agent.agent_id,
220
+ agent_id: agent.agent_id,
221
+ agent_name: agent.agent_name,
222
+ kind: 'registered-agent',
223
+ });
224
+ }
225
+ for (const candidate of listCandidates('pending', cwd)) {
226
+ trackCandidateSignals(candidate, 'pending', store, sinceMs, config, resolvers.resolve);
227
+ }
228
+ for (const candidate of listArchivedCandidates('accepted', cwd)) {
229
+ trackCandidateSignals(candidate, 'accepted', store, sinceMs, config, resolvers.resolve);
230
+ }
231
+ for (const candidate of listArchivedCandidates('rejected', cwd)) {
232
+ trackCandidateSignals(candidate, 'rejected', store, sinceMs, config, resolvers.resolve);
233
+ }
234
+ for (const note of listRuntimeNotes({ visibility: 'all', includeAllHosts: true }, cwd)) {
235
+ trackRuntimeSignals(note, store, sinceMs, resolvers.resolve);
236
+ }
237
+ for (const claim of listClaims(cwd)) {
238
+ trackClaimSignals(claim, store, sinceMs, resolvers.resolve);
239
+ }
240
+ const agents = [...store.values()]
241
+ .map((entry) => finalizeSnapshot(entry))
242
+ .sort((a, b) => {
243
+ const trustDelta = b.scores.internal_trust - a.scores.internal_trust;
244
+ if (trustDelta !== 0) {
245
+ return trustDelta;
246
+ }
247
+ return a.agent_name.localeCompare(b.agent_name);
248
+ });
249
+ const currentAgentSnapshot = currentAgent
250
+ ? agents.find((agent) => agent.agent_id === currentAgent.agent_id)
251
+ : undefined;
252
+ return {
253
+ enabled: reputationConfig.enabled,
254
+ visibility: reputationConfig.visibility,
255
+ window_days: reputationConfig.decay_days,
256
+ generated_at: nowISO(),
257
+ project_id: config.project_id,
258
+ current_agent_id: currentAgent?.agent_id,
259
+ current_agent: currentAgentSnapshot,
260
+ agents: reputationConfig.enabled ? agents : [],
261
+ };
262
+ }
263
+ export function buildCurrentAgentResumeSummary(cwd) {
264
+ const snapshot = buildReputationSnapshot(cwd);
265
+ const current = snapshot.current_agent;
266
+ if (!snapshot.enabled || !current) {
267
+ return undefined;
268
+ }
269
+ const strengths = [];
270
+ const cautions = [];
271
+ const suggestedFocus = [];
272
+ if (current.signals.accepted_candidates > 0) {
273
+ strengths.push(`${current.signals.accepted_candidates} accepted candidate(s) landed in canonical memory recently.`);
274
+ }
275
+ if (current.signals.promoted_runtime_accepted > 0) {
276
+ strengths.push(`${current.signals.promoted_runtime_accepted} runtime note(s) were promoted and then accepted.`);
277
+ }
278
+ if ((current.signals.accepted_reviews + current.signals.rejected_reviews) > 0) {
279
+ strengths.push(`${current.signals.accepted_reviews + current.signals.rejected_reviews} review resolution(s) were recorded for this agent.`);
280
+ }
281
+ if (current.signals.plan_linked_activity > 0) {
282
+ strengths.push(`${current.signals.plan_linked_activity} plan-linked activity signal(s) were captured.`);
283
+ }
284
+ if (current.signals.pending_candidates > 0) {
285
+ cautions.push(`${current.signals.pending_candidates} pending candidate(s) still need review.`);
286
+ suggestedFocus.push('Review pending candidates before starting new exploration.');
287
+ }
288
+ if (current.signals.orphan_runtime_noise > 0) {
289
+ cautions.push(`${current.signals.orphan_runtime_noise} runtime note(s) are not yet linked to a plan or durable promotion.`);
290
+ suggestedFocus.push('Promote or prune runtime notes that still carry useful signal.');
291
+ }
292
+ if (current.signals.claims_created > current.signals.released_claims) {
293
+ cautions.push(`${current.signals.claims_created - current.signals.released_claims} claim(s) may still need release or refresh.`);
294
+ suggestedFocus.push('Release or refresh stale claims before deep work resumes.');
295
+ }
296
+ if (current.signals.runtime_notes_created > 0 && current.signals.plan_linked_activity === 0) {
297
+ suggestedFocus.push('Link future runtime notes to plans when possible to improve session continuity.');
298
+ }
299
+ if (strengths.length === 0) {
300
+ strengths.push('No strong durability signal yet; this agent is still building a project-specific track record.');
301
+ }
302
+ if (cautions.length === 0) {
303
+ cautions.push('No immediate continuity warning detected in the recent reputation window.');
304
+ }
305
+ if (suggestedFocus.length === 0) {
306
+ suggestedFocus.push('Keep recording concise runtime notes and promote only the ones worth preserving.');
307
+ }
308
+ return {
309
+ agent_name: current.agent_name,
310
+ agent_id: current.agent_id,
311
+ internal_trust: current.scores.internal_trust,
312
+ contribution_quality: current.scores.contribution_quality,
313
+ review_reliability: current.scores.review_reliability,
314
+ continuity_hygiene: current.scores.continuity_hygiene,
315
+ strengths: strengths.slice(0, 3),
316
+ cautions: cautions.slice(0, 3),
317
+ suggested_focus: suggestedFocus.slice(0, 3),
318
+ };
319
+ }
320
+ export function buildReputationRankingLookup(cwd) {
321
+ const config = loadConfig(cwd);
322
+ const rankingWeight = config.reputation?.ranking_weight ?? 0.15;
323
+ const snapshot = buildReputationSnapshot(cwd);
324
+ const byId = new Map();
325
+ const byName = new Map();
326
+ const byKey = new Map();
327
+ for (const agent of snapshot.agents) {
328
+ byKey.set(agent.key, agent.scores.internal_trust);
329
+ if (agent.agent_id) {
330
+ byId.set(agent.agent_id, agent.scores.internal_trust);
331
+ }
332
+ byName.set(agent.agent_name.trim().toLowerCase(), agent.scores.internal_trust);
333
+ }
334
+ const getInternalTrust = (actorId, actorName) => {
335
+ const byAgentId = actorId?.trim() ? byId.get(actorId.trim()) : undefined;
336
+ if (typeof byAgentId === 'number') {
337
+ return byAgentId;
338
+ }
339
+ const normalizedName = actorName?.trim().toLowerCase();
340
+ if (normalizedName) {
341
+ const direct = byName.get(normalizedName);
342
+ if (typeof direct === 'number') {
343
+ return direct;
344
+ }
345
+ const actorKey = byKey.get(`actor:${normalizedName}`);
346
+ if (typeof actorKey === 'number') {
347
+ return actorKey;
348
+ }
349
+ }
350
+ return 0;
351
+ };
352
+ const getRankingBonus = (actorId, actorName) => {
353
+ if (!snapshot.enabled || rankingWeight <= 0) {
354
+ return 0;
355
+ }
356
+ const trust = getInternalTrust(actorId, actorName);
357
+ const bonus = (trust / 100) * (rankingWeight * 10);
358
+ return Math.max(0, Math.min(1.5, Number(bonus.toFixed(2))));
359
+ };
360
+ return {
361
+ enabled: snapshot.enabled,
362
+ ranking_weight: rankingWeight,
363
+ getInternalTrust,
364
+ getRankingBonus,
365
+ };
366
+ }
367
+ export function toPublicReputationSummary(agent) {
368
+ return {
369
+ agent_name: agent.agent_name,
370
+ agent_id: agent.agent_id,
371
+ internal_trust: agent.scores.internal_trust,
372
+ contribution_quality: agent.scores.contribution_quality,
373
+ review_reliability: agent.scores.review_reliability,
374
+ continuity_hygiene: agent.scores.continuity_hygiene,
375
+ pending_candidates: agent.signals.pending_candidates,
376
+ accepted_candidates: agent.signals.accepted_candidates,
377
+ accepted_reviews: agent.signals.accepted_reviews,
378
+ rejected_reviews: agent.signals.rejected_reviews,
379
+ };
380
+ }
381
+ export function buildReputationSummary(cwd) {
382
+ const snapshot = buildReputationSnapshot(cwd);
383
+ const trackedAgents = snapshot.agents.length;
384
+ const avgInternalTrust = trackedAgents > 0
385
+ ? Number((snapshot.agents.reduce((sum, agent) => sum + agent.scores.internal_trust, 0) / trackedAgents).toFixed(1))
386
+ : 0;
387
+ const currentTrust = snapshot.current_agent?.scores.internal_trust;
388
+ return {
389
+ enabled: snapshot.enabled,
390
+ visibility: snapshot.visibility,
391
+ tracked_agents: trackedAgents,
392
+ avg_internal_trust: avgInternalTrust,
393
+ current_agent_id: snapshot.current_agent_id,
394
+ current_agent_trust: currentTrust,
395
+ total_pending_candidates: snapshot.agents.reduce((sum, agent) => sum + agent.signals.pending_candidates, 0),
396
+ total_review_resolutions: snapshot.agents.reduce((sum, agent) => sum + agent.signals.accepted_reviews + agent.signals.rejected_reviews, 0),
397
+ total_runtime_notes: snapshot.agents.reduce((sum, agent) => sum + agent.signals.runtime_notes_created, 0),
398
+ };
399
+ }
400
+ export function findAgentReputationSummary(agentNameOrId, cwd) {
401
+ const value = agentNameOrId?.trim();
402
+ if (!value) {
403
+ return undefined;
404
+ }
405
+ const snapshot = buildReputationSnapshot(cwd);
406
+ const found = snapshot.agents.find((agent) => agent.agent_id === value || agent.agent_name.toLowerCase() === value.toLowerCase());
407
+ return found ? toPublicReputationSummary(found) : undefined;
408
+ }
409
+ //# sourceMappingURL=reputation.js.map
@@ -0,0 +1,134 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { resolveCurrentHostId, sanitizeHostId } from './host.js';
5
+ import { resolveEntityDir } from './io.js';
6
+ import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
7
+ import { RuntimeNoteSchema } from './schema.js';
8
+ import { commitMemoryChange } from './memory-git.js';
9
+ import { appendEvent } from './event-log.js';
10
+ function sharedRuntimeDir(cwd, mode = 'read') {
11
+ return resolveEntityDir('runtime', cwd ?? process.cwd(), mode);
12
+ }
13
+ function machineRuntimeDir(cwd, mode = 'read') {
14
+ return resolveEntityDir('runtime-hosts', cwd ?? process.cwd(), mode);
15
+ }
16
+ function privateRuntimeDir(cwd, mode = 'read') {
17
+ return resolveEntityDir('runtime-private', cwd ?? process.cwd(), mode);
18
+ }
19
+ function sharedAgentDir(agent, cwd, mode = 'read') {
20
+ return path.join(sharedRuntimeDir(cwd, mode), agent);
21
+ }
22
+ function hostRootDir(visibility, hostId, cwd, mode = 'read') {
23
+ const baseDir = visibility === 'machine' ? machineRuntimeDir(cwd, mode) : privateRuntimeDir(cwd, mode);
24
+ return path.join(baseDir, sanitizeHostId(hostId));
25
+ }
26
+ function hostAgentDir(visibility, hostId, agent, cwd, mode = 'read') {
27
+ return path.join(hostRootDir(visibility, hostId, cwd, mode), agent);
28
+ }
29
+ export function ensureRuntimeDir(agent, cwd, visibility = 'shared', hostId) {
30
+ const dir = visibility === 'shared'
31
+ ? sharedAgentDir(agent, cwd, 'write')
32
+ : hostAgentDir(visibility, hostId ?? resolveCurrentHostId(), agent, cwd, 'write');
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ }
37
+ export function saveRuntimeNote(note, cwd) {
38
+ const visibility = note.visibility ?? 'shared';
39
+ const hostId = sanitizeHostId(note.host_id ?? resolveCurrentHostId());
40
+ const persistedNote = visibility === 'shared'
41
+ ? { ...note, visibility, host_id: hostId }
42
+ : { ...note, visibility, host_id: hostId };
43
+ ensureRuntimeDir(note.agent, cwd, visibility, hostId);
44
+ const filepath = visibility === 'shared'
45
+ ? path.join(sharedAgentDir(note.agent, cwd, 'write'), `${note.id}.json`)
46
+ : path.join(hostAgentDir(visibility, hostId, note.agent, cwd, 'write'), `${note.id}.json`);
47
+ saveVersionedJsonFile('runtime_note', filepath, RuntimeNoteSchema.parse(persistedNote));
48
+ appendEvent({ action: 'create', item_type: 'runtime_note', item_id: note.id, agent: note.agent, agent_id: note.agent_id }, cwd);
49
+ commitMemoryChange(`runtime note: ${note.note_type ?? 'note'} (${note.agent})`, cwd);
50
+ }
51
+ export function runtimeNotePath(note, cwd) {
52
+ const visibility = note.visibility ?? 'shared';
53
+ const hostId = sanitizeHostId(note.host_id ?? resolveCurrentHostId());
54
+ return visibility === 'shared'
55
+ ? path.join(sharedAgentDir(note.agent, cwd), `${note.id}.json`)
56
+ : path.join(hostAgentDir(visibility, hostId, note.agent, cwd), `${note.id}.json`);
57
+ }
58
+ export function deleteRuntimeNote(note, cwd) {
59
+ const filepath = runtimeNotePath(note, cwd);
60
+ if (!fs.existsSync(filepath)) {
61
+ return false;
62
+ }
63
+ fs.unlinkSync(filepath);
64
+ return true;
65
+ }
66
+ function readAgentNotes(dir, agent) {
67
+ if (!fs.existsSync(dir))
68
+ return [];
69
+ const agents = agent
70
+ ? [agent]
71
+ : fs.readdirSync(dir).filter((entry) => fs.statSync(path.join(dir, entry)).isDirectory());
72
+ const notes = [];
73
+ for (const a of agents) {
74
+ const agentDirectory = path.join(dir, a);
75
+ if (!fs.existsSync(agentDirectory))
76
+ continue;
77
+ const files = fs.readdirSync(agentDirectory).filter((file) => file.endsWith('.json'));
78
+ for (const file of files) {
79
+ try {
80
+ notes.push(loadVersionedJsonFile('runtime_note', path.join(agentDirectory, file)).document);
81
+ }
82
+ catch { /* skip */ }
83
+ }
84
+ }
85
+ return notes;
86
+ }
87
+ function resolveHostIds(rootDir, options) {
88
+ if (!fs.existsSync(rootDir))
89
+ return [];
90
+ if (options.includeAllHosts) {
91
+ return fs.readdirSync(rootDir)
92
+ .filter((entry) => fs.statSync(path.join(rootDir, entry)).isDirectory())
93
+ .map((entry) => sanitizeHostId(entry));
94
+ }
95
+ return [sanitizeHostId(options.hostId ?? resolveCurrentHostId())];
96
+ }
97
+ function readHostScopedNotes(visibility, options, cwd) {
98
+ const rootDir = visibility === 'machine' ? machineRuntimeDir(cwd) : privateRuntimeDir(cwd);
99
+ const hostIds = resolveHostIds(rootDir, options);
100
+ const notes = [];
101
+ for (const hostId of hostIds) {
102
+ notes.push(...readAgentNotes(hostRootDir(visibility, hostId, cwd), options.agent));
103
+ }
104
+ return notes;
105
+ }
106
+ function normalizeRuntimeListOptions(agentOrOptions) {
107
+ if (typeof agentOrOptions === 'string') {
108
+ return { agent: agentOrOptions };
109
+ }
110
+ return agentOrOptions ?? {};
111
+ }
112
+ export function listRuntimeNotes(agentOrOptions, cwd) {
113
+ const options = normalizeRuntimeListOptions(agentOrOptions);
114
+ const visibility = options.visibility;
115
+ const notes = [];
116
+ if (!visibility || visibility === 'shared' || visibility === 'all') {
117
+ notes.push(...readAgentNotes(sharedRuntimeDir(cwd), options.agent));
118
+ }
119
+ if (!visibility || visibility === 'machine' || visibility === 'all') {
120
+ notes.push(...readHostScopedNotes('machine', options, cwd));
121
+ }
122
+ if (visibility === 'private' || visibility === 'all') {
123
+ notes.push(...readHostScopedNotes('private', options, cwd));
124
+ }
125
+ return notes.sort((a, b) => a.created_at.localeCompare(b.created_at));
126
+ }
127
+ export function findRuntimeNoteById(id, options = {}, cwd) {
128
+ return listRuntimeNotes({ ...options, visibility: options.visibility ?? 'all' }, cwd).find((note) => note.id === id);
129
+ }
130
+ export function generateRuntimeNoteId() {
131
+ const rand = crypto.randomBytes(4).toString('hex');
132
+ return `rtn_${rand}`;
133
+ }
134
+ //# sourceMappingURL=runtime.js.map