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,1212 @@
1
+ import { loadConfig } from './config.js';
2
+ import { resolveCrossProjectLinks, loadCrossProjectState } from './cross-project.js';
3
+ import { buildContextDiff } from './context-diff.js';
4
+ import { resolveStoreChain } from './store-resolution.js';
5
+ import { findAgentIdentityByName, resolveCurrentAgentIdentity } from './agent-registry.js';
6
+ import { hasReusableBootstrapProfile, runBootstrapProfile, selectDerivedSignals } from './bootstrap.js';
7
+ import { buildAgentToolingContext } from './agent-context.js';
8
+ import { buildExecutionContext, compactExecutionContext } from './execution-context.js';
9
+ import { getVisibleMemoryVersion } from './freshness.js';
10
+ import { resolveCurrentHostId } from './host.js';
11
+ import { inferProjectFromTarget, loadInstructions, resolveInstructions } from './instructions.js';
12
+ import { buildCurrentAgentResumeSummary, buildReputationRankingLookup } from './reputation.js';
13
+ import { loadState } from './state.js';
14
+ import { listCandidates } from './candidates.js';
15
+ import { listClaims } from './claims.js';
16
+ import { listRuntimeNotes } from './runtime.js';
17
+ import { isTrapActive, listOperationalTraps } from './traps.js';
18
+ import { buildEstimationReport } from '../commands/estimation-report.js';
19
+ export const CONTEXT_SCHEMA_VERSION = '1.2';
20
+ export function buildContext(options = {}) {
21
+ const state = loadState(options.cwd);
22
+ const config = loadConfig(options.cwd);
23
+ // Resolve parent stores for multi-store merge (walk-up from cwd)
24
+ const storeChain = resolveStoreChain(options.cwd ?? process.cwd());
25
+ const profile = options.profile ?? config.profile ?? 'dev';
26
+ const projectMode = config.project_mode ?? 'auto';
27
+ const projectStrategy = config.projects?.strategy ?? 'manual';
28
+ const currentHost = resolveCurrentHostId();
29
+ const memoryVersion = getVisibleMemoryVersion({ cwd: options.cwd, hostId: options.host, allHosts: options.allHosts });
30
+ const target = options.target?.trim() ?? '';
31
+ const project = options.project?.trim() || inferProjectFromTarget(target, config);
32
+ const agent = options.agent?.trim() || config.current_agent?.trim();
33
+ const currentAgentIdentity = agent
34
+ ? (options.agent?.trim() ? findAgentIdentityByName(agent, options.cwd) : resolveCurrentAgentIdentity(options.cwd))
35
+ : undefined;
36
+ const profileMaxItems = { compact: 6, copilot: 5, quick: 3 };
37
+ const maxItems = options.maxItems ?? profileMaxItems[profile] ?? 8;
38
+ const maxChars = options.maxChars && options.maxChars > 0 ? options.maxChars : undefined;
39
+ // Instructions will be resolved after parent-store merge below (line ~460)
40
+ const rankingLookup = buildReputationRankingLookup(options.cwd);
41
+ const profileSections = {
42
+ compact: ['plan', 'constraint'],
43
+ copilot: ['constraint', 'trap'],
44
+ quick: ['constraint', 'plan'],
45
+ };
46
+ const allowedSections = profileSections[profile];
47
+ const items = [];
48
+ for (const plan of state.plan_items.filter((item) => item.status !== 'done' && item.status !== 'dropped')) {
49
+ const meta = [plan.status, plan.priority];
50
+ if (plan.assignee)
51
+ meta.push(`assignee:${plan.assignee}`);
52
+ if (plan.project)
53
+ meta.push(`project:${plan.project}`);
54
+ if (plan.steps && plan.steps.length > 0) {
55
+ const done = plan.steps.filter((s) => s.status === 'done').length;
56
+ meta.push(`${done}/${plan.steps.length}`);
57
+ }
58
+ items.push({
59
+ id: plan.id,
60
+ section: 'plan',
61
+ text: plan.text,
62
+ tags: plan.tags,
63
+ related_paths: plan.related_paths,
64
+ score: 0,
65
+ reasons: [],
66
+ extra: meta.join(', '),
67
+ });
68
+ }
69
+ for (const c of state.active_constraints) {
70
+ items.push({
71
+ id: c.id,
72
+ section: 'constraint',
73
+ text: c.text,
74
+ tags: c.tags,
75
+ related_paths: c.related_paths,
76
+ score: 0,
77
+ reasons: [],
78
+ extra: c.status,
79
+ provenance: {
80
+ actor: c.author,
81
+ actor_id: c.author_id,
82
+ project_id: c.project_id,
83
+ host_id: c.host_id,
84
+ session_id: c.session_id,
85
+ },
86
+ });
87
+ }
88
+ for (const d of state.recent_decisions) {
89
+ items.push({
90
+ id: d.id,
91
+ section: 'decision',
92
+ text: d.text,
93
+ tags: d.tags,
94
+ related_paths: d.related_paths,
95
+ score: 0,
96
+ reasons: [],
97
+ extra: d.related_paths?.join(', '),
98
+ provenance: {
99
+ actor: d.author,
100
+ actor_id: d.author_id,
101
+ project_id: d.project_id,
102
+ host_id: d.host_id,
103
+ session_id: d.session_id,
104
+ },
105
+ });
106
+ }
107
+ for (const t of state.known_traps.filter((trap) => isTrapActive(trap))) {
108
+ items.push({
109
+ id: t.id,
110
+ section: 'trap',
111
+ text: t.text,
112
+ tags: t.tags,
113
+ related_paths: t.related_paths,
114
+ score: 0,
115
+ reasons: [],
116
+ extra: `${t.severity}, visibility:${t.visibility ?? 'shared'}`,
117
+ provenance: {
118
+ actor: t.author,
119
+ actor_id: t.author_id,
120
+ project_id: t.project_id,
121
+ host_id: t.host_id,
122
+ session_id: t.session_id,
123
+ },
124
+ });
125
+ }
126
+ for (const trap of listOperationalTraps({ hostId: options.host, includeAllHosts: options.allHosts }, options.cwd).filter((entry) => isTrapActive(entry))) {
127
+ items.push({
128
+ id: trap.id,
129
+ section: 'trap',
130
+ text: trap.text,
131
+ tags: trap.tags,
132
+ related_paths: trap.related_paths,
133
+ score: 0,
134
+ reasons: [],
135
+ extra: `${trap.severity}, visibility:${trap.visibility ?? 'machine'}${trap.host_id ? `, host:${trap.host_id}` : ''}`,
136
+ });
137
+ }
138
+ for (const h of state.open_handoffs.filter((x) => x.status === 'open')) {
139
+ items.push({
140
+ id: h.id,
141
+ section: 'handoff',
142
+ text: h.text,
143
+ tags: h.tags,
144
+ related_paths: h.related_paths,
145
+ score: 0,
146
+ reasons: [],
147
+ extra: `${h.from} -> ${h.to}`,
148
+ provenance: {
149
+ actor: h.author,
150
+ actor_id: h.author_id,
151
+ project_id: h.project_id,
152
+ host_id: h.host_id,
153
+ session_id: h.session_id,
154
+ },
155
+ });
156
+ }
157
+ const runtimeNotes = listRuntimeNotes({
158
+ hostId: options.host,
159
+ includeAllHosts: options.allHosts,
160
+ }, options.cwd);
161
+ for (const note of runtimeNotes) {
162
+ if (project && note.project && note.project !== project) {
163
+ continue;
164
+ }
165
+ const meta = [`agent:${note.agent}`, `visibility:${note.visibility}`];
166
+ if (note.host_id)
167
+ meta.push(`host:${note.host_id}`);
168
+ if (note.agent_id)
169
+ meta.push(`agent_id:${note.agent_id}`);
170
+ if (note.session_id)
171
+ meta.push(`session:${note.session_id}`);
172
+ if (note.plan_id)
173
+ meta.push(`plan:${note.plan_id}`);
174
+ if (note.project)
175
+ meta.push(`project:${note.project}`);
176
+ items.push({
177
+ id: note.id,
178
+ section: 'runtime',
179
+ text: note.text,
180
+ tags: note.tags,
181
+ score: 0,
182
+ reasons: [],
183
+ extra: meta.join(', '),
184
+ provenance: {
185
+ actor: note.agent,
186
+ actor_id: note.agent_id,
187
+ project_id: note.project_id,
188
+ host_id: note.host_id,
189
+ session_id: note.session_id,
190
+ },
191
+ });
192
+ }
193
+ if (options.includePending) {
194
+ for (const p of listCandidates('pending', options.cwd)) {
195
+ const meta = [`${p.type}`, `stars:${p.star_count ?? 0}`, `uses:${p.usage_count ?? 0}`];
196
+ if (p.author_id)
197
+ meta.push(`author_id:${p.author_id}`);
198
+ if (p.session_id)
199
+ meta.push(`session:${p.session_id}`);
200
+ items.push({
201
+ id: p.id,
202
+ section: 'candidate',
203
+ text: p.text,
204
+ tags: p.tags,
205
+ related_paths: p.related_paths,
206
+ score: 0,
207
+ reasons: [],
208
+ extra: meta.join(', '),
209
+ provenance: {
210
+ actor: p.author,
211
+ actor_id: p.author_id,
212
+ project_id: p.project_id,
213
+ host_id: p.host_id,
214
+ session_id: p.session_id,
215
+ },
216
+ });
217
+ }
218
+ }
219
+ // Merge items from parent stores (multi-store hierarchy)
220
+ // Primary store is storeChain[0]; parents are storeChain[1+]
221
+ const seenIds = new Set(items.map((i) => i.id));
222
+ for (const parentStore of storeChain.slice(1)) {
223
+ try {
224
+ const parentState = loadState(parentStore.cwd);
225
+ const storeLabel = parentStore.role !== 'unknown' ? parentStore.role : `depth:${parentStore.depth}`;
226
+ for (const c of parentState.active_constraints) {
227
+ if (seenIds.has(c.id))
228
+ continue;
229
+ seenIds.add(c.id);
230
+ items.push({
231
+ id: c.id, section: 'constraint', text: c.text, tags: c.tags,
232
+ related_paths: c.related_paths, score: 0, reasons: [],
233
+ extra: `${c.status} [from:${storeLabel}]`,
234
+ provenance: { actor: c.author, actor_id: c.author_id, project_id: c.project_id },
235
+ });
236
+ }
237
+ for (const d of parentState.recent_decisions) {
238
+ if (seenIds.has(d.id))
239
+ continue;
240
+ seenIds.add(d.id);
241
+ items.push({
242
+ id: d.id, section: 'decision', text: d.text, tags: d.tags,
243
+ related_paths: d.related_paths, score: 0, reasons: [],
244
+ extra: `[from:${storeLabel}]`,
245
+ provenance: { actor: d.author, actor_id: d.author_id, project_id: d.project_id },
246
+ });
247
+ }
248
+ for (const t of parentState.known_traps.filter((trap) => isTrapActive(trap))) {
249
+ if (seenIds.has(t.id))
250
+ continue;
251
+ seenIds.add(t.id);
252
+ items.push({
253
+ id: t.id, section: 'trap', text: t.text, tags: t.tags,
254
+ related_paths: t.related_paths, score: 0, reasons: [],
255
+ extra: `${t.severity} [from:${storeLabel}]`,
256
+ provenance: { actor: t.author, actor_id: t.author_id, project_id: t.project_id },
257
+ });
258
+ }
259
+ for (const plan of parentState.plan_items.filter((p) => p.status !== 'done' && p.status !== 'dropped')) {
260
+ if (seenIds.has(plan.id))
261
+ continue;
262
+ seenIds.add(plan.id);
263
+ const meta = [plan.status, plan.priority, `from:${storeLabel}`];
264
+ if (plan.assignee)
265
+ meta.push(`assignee:${plan.assignee}`);
266
+ items.push({
267
+ id: plan.id, section: 'plan', text: plan.text, tags: plan.tags,
268
+ related_paths: plan.related_paths, score: 0, reasons: [],
269
+ extra: meta.join(', '),
270
+ });
271
+ }
272
+ for (const h of parentState.open_handoffs.filter((x) => x.status === 'open')) {
273
+ if (seenIds.has(h.id))
274
+ continue;
275
+ seenIds.add(h.id);
276
+ items.push({
277
+ id: h.id, section: 'handoff', text: h.text, tags: h.tags,
278
+ related_paths: h.related_paths, score: 0, reasons: [],
279
+ extra: `${h.from} -> ${h.to} [from:${storeLabel}]`,
280
+ provenance: { actor: h.author, actor_id: h.author_id, project_id: h.project_id },
281
+ });
282
+ }
283
+ }
284
+ catch {
285
+ // Non-fatal: skip unreadable parent store
286
+ }
287
+ }
288
+ // Merge active claims from all parent stores for open_work visibility
289
+ const parentStoreClaims = [];
290
+ for (const parentStore of storeChain.slice(1)) {
291
+ try {
292
+ parentStoreClaims.push(...listClaims(parentStore.cwd));
293
+ }
294
+ catch { /* non-fatal */ }
295
+ }
296
+ // Merge instructions from all stores in the chain
297
+ const allInstructions = [...loadInstructions(options.cwd)];
298
+ for (const parentStore of storeChain.slice(1)) {
299
+ try {
300
+ const parentInstrs = loadInstructions(parentStore.cwd);
301
+ for (const instr of parentInstrs) {
302
+ if (!allInstructions.some((existing) => existing.id === instr.id)) {
303
+ allInstructions.push(instr);
304
+ }
305
+ }
306
+ }
307
+ catch { /* non-fatal */ }
308
+ }
309
+ const resolvedInstructions = resolveInstructions(allInstructions, { project, agent });
310
+ // Apply profile section filter before scoring
311
+ if (allowedSections) {
312
+ const allowed = allowedSections;
313
+ items.splice(0, items.length, ...items.filter((i) => allowed.includes(i.section)));
314
+ }
315
+ const queryTerms = tokenise(target);
316
+ for (const item of items) {
317
+ const relevance = computeRelevance(item, queryTerms, profile, target);
318
+ item.score = relevance.score;
319
+ item.reasons = relevance.reasons;
320
+ if (item.score >= 0 && item.provenance) {
321
+ const trustBonus = rankingLookup.getRankingBonus(item.provenance.actor_id, item.provenance.actor);
322
+ if (trustBonus > 0) {
323
+ item.score += trustBonus;
324
+ item.reasons = uniqueReasons([...item.reasons, `reputation signal:+${trustBonus.toFixed(2)}`]);
325
+ }
326
+ }
327
+ }
328
+ const ranked = items
329
+ .filter(item => item.score >= 0)
330
+ .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id))
331
+ .slice(0, maxItems);
332
+ const selected = maxChars ? applyCharBudget(ranked, maxChars) : ranked;
333
+ const resumeSummary = buildCurrentAgentResumeSummary(options.cwd);
334
+ const scopedActivity = buildScopedActivity({
335
+ target,
336
+ project,
337
+ state,
338
+ runtimeNotes,
339
+ pendingCandidates: listCandidates('pending', options.cwd),
340
+ });
341
+ const memoryDensity = classifyMemoryDensity(selected.length);
342
+ const bootstrapEnabled = options.bootstrap !== false;
343
+ let bootstrapAvailable = hasReusableBootstrapProfile(target, options.cwd);
344
+ let derivedSignals;
345
+ if (bootstrapEnabled && (options.refreshBootstrap || memoryDensity === 'low')) {
346
+ const bootstrap = runBootstrapProfile({
347
+ target,
348
+ refresh: options.refreshBootstrap,
349
+ cwd: options.cwd,
350
+ });
351
+ bootstrapAvailable = bootstrap.profile.seed_count > 0;
352
+ if (memoryDensity === 'low') {
353
+ const signals = selectDerivedSignals(target, 5, options.cwd);
354
+ if (signals.length > 0) {
355
+ derivedSignals = signals;
356
+ }
357
+ }
358
+ }
359
+ else if (bootstrapEnabled && bootstrapAvailable && memoryDensity === 'low') {
360
+ const signals = selectDerivedSignals(target, 5, options.cwd);
361
+ if (signals.length > 0) {
362
+ derivedSignals = signals;
363
+ }
364
+ }
365
+ const executionSensitive = isExecutionSensitiveTarget(target);
366
+ const derivedUsesExecution = derivedSignals?.some((signal) => signal.source_kind === 'machine') ?? false;
367
+ const derivedUsesTooling = derivedSignals?.some((signal) => signal.source_kind === 'skill' || signal.source_kind === 'mcp') ?? false;
368
+ const rawAgentTooling = buildAgentToolingContext({ cwd: options.cwd });
369
+ const actionableAgentRules = rawAgentTooling.agents_rules.length > 0;
370
+ const blockingTooling = rawAgentTooling.mcp_servers.some((server) => server.availability === 'missing_command');
371
+ const shouldExposeExecution = memoryDensity === 'low' || executionSensitive || derivedUsesExecution;
372
+ const shouldExposeAgentTooling = memoryDensity === 'low'
373
+ || executionSensitive
374
+ || derivedUsesTooling
375
+ || actionableAgentRules
376
+ || blockingTooling;
377
+ const executionContext = shouldExposeExecution
378
+ ? compactExecutionContext(buildExecutionContext({ cwd: options.cwd }))
379
+ : undefined;
380
+ const agentTooling = shouldExposeAgentTooling
381
+ ? summariseAgentTooling(rawAgentTooling)
382
+ : undefined;
383
+ // Build open_work: active claims and in_progress plans owned by the current agent
384
+ let openWork;
385
+ if (currentAgentIdentity || agent) {
386
+ const agentName = agent;
387
+ const agentId = currentAgentIdentity?.agent_id;
388
+ const allClaims = [...listClaims(options.cwd), ...parentStoreClaims];
389
+ const activeClaims = allClaims.filter((c) => c.status === 'active' && (agentId ? c.agent_id === agentId : c.agent === agentName));
390
+ const claimPlanIds = new Set(activeClaims.map((c) => c.plan_id).filter(Boolean));
391
+ const inProgressPlans = state.plan_items.filter((p) => p.status === 'in_progress' &&
392
+ (p.assignee === agentName || claimPlanIds.has(p.id)));
393
+ if (activeClaims.length > 0 || inProgressPlans.length > 0) {
394
+ openWork = {
395
+ active_claims: activeClaims.map(({ id, scope, description, created_at, plan_id, expires_at }) => ({ id, scope, description, created_at, plan_id, expires_at })),
396
+ in_progress_plans: inProgressPlans.map(({ id, text, assignee }) => ({ id, text, assignee })),
397
+ };
398
+ }
399
+ }
400
+ // Cross-project items (subscriber links — read-only, always injected, bypass scoring)
401
+ const crossProjectItems = [];
402
+ for (const link of resolveCrossProjectLinks(options.cwd)) {
403
+ if (!link.available)
404
+ continue;
405
+ try {
406
+ const linkedState = loadCrossProjectState(link.absolutePath);
407
+ for (const d of linkedState.recent_decisions) {
408
+ crossProjectItems.push({
409
+ id: d.id, section: 'cross_project', text: d.text,
410
+ tags: d.tags, score: 0, reasons: [], from_project: link.projectName,
411
+ });
412
+ }
413
+ for (const c of linkedState.active_constraints) {
414
+ crossProjectItems.push({
415
+ id: c.id, section: 'cross_project', text: c.text,
416
+ tags: c.tags, score: 0, reasons: [], from_project: link.projectName,
417
+ });
418
+ }
419
+ for (const t of linkedState.known_traps.filter((trap) => isTrapActive(trap))) {
420
+ crossProjectItems.push({
421
+ id: t.id, section: 'cross_project', text: t.text,
422
+ tags: t.tags, score: 0, reasons: [], from_project: link.projectName,
423
+ });
424
+ }
425
+ }
426
+ catch { /* skip unavailable linked project */ }
427
+ }
428
+ const result = {
429
+ context_schema: CONTEXT_SCHEMA_VERSION,
430
+ profile,
431
+ project_id: config.project_id,
432
+ agent_id: currentAgentIdentity?.agent_id,
433
+ project_mode: projectMode,
434
+ project_strategy: projectStrategy,
435
+ current_host: currentHost,
436
+ host_filter: options.host,
437
+ all_hosts: options.allHosts ?? false,
438
+ memory_version: memoryVersion,
439
+ target,
440
+ project,
441
+ agent,
442
+ memory_density: memoryDensity,
443
+ bootstrap_available: bootstrapAvailable,
444
+ derived_signals: derivedSignals,
445
+ execution_context: executionContext,
446
+ agent_tooling: agentTooling,
447
+ scoped_activity: scopedActivity,
448
+ context_diff: options.sinceSession
449
+ ? buildContextDiff({
450
+ session: options.sinceSession,
451
+ cwd: options.cwd,
452
+ includeItems: true,
453
+ })
454
+ : undefined,
455
+ resolved_instructions: resolvedInstructions,
456
+ resume_summary: resumeSummary,
457
+ open_work: openWork,
458
+ stores: storeChain.length > 1
459
+ ? storeChain.map(({ cwd, depth, role }) => ({ cwd, depth, role }))
460
+ : undefined,
461
+ estimation_calibration: (() => {
462
+ try {
463
+ const report = buildEstimationReport({ agent, cwd: options.cwd });
464
+ return report.summary.with_both >= 3 ? report.summary.calibration_hint : undefined;
465
+ }
466
+ catch {
467
+ return undefined;
468
+ }
469
+ })(),
470
+ cross_project_items: crossProjectItems.length > 0 ? crossProjectItems : undefined,
471
+ selected,
472
+ };
473
+ if (options.digest) {
474
+ result.digest = buildContextDigest(result);
475
+ }
476
+ return result;
477
+ }
478
+ export function renderContextMarkdown(result, explain = false) {
479
+ const lines = [];
480
+ lines.push(`# Agent Context (${result.profile})`);
481
+ lines.push('');
482
+ if (result.open_work && (result.open_work.active_claims.length > 0 || result.open_work.in_progress_plans.length > 0)) {
483
+ lines.push('## ⚠ Your open work');
484
+ lines.push('');
485
+ if (result.open_work.active_claims.length > 0) {
486
+ lines.push('Active claims (release when done):');
487
+ const now = new Date().toISOString();
488
+ for (const claim of result.open_work.active_claims) {
489
+ const planRef = claim.plan_id ? ` [plan: ${claim.plan_id}]` : '';
490
+ const expired = claim.expires_at && claim.expires_at < now ? ' ⚠ EXPIRED — run brainclaw prune' : '';
491
+ const ttlInfo = claim.expires_at && !expired ? ` (expires ${claim.expires_at.slice(0, 16).replace('T', ' ')})` : '';
492
+ lines.push(`- [${claim.id}] ${claim.description}${planRef}${ttlInfo}${expired}`);
493
+ lines.push(` scope: ${claim.scope}`);
494
+ }
495
+ }
496
+ if (result.open_work.in_progress_plans.length > 0) {
497
+ lines.push('In-progress plan items (update status when done):');
498
+ for (const plan of result.open_work.in_progress_plans) {
499
+ lines.push(`- [${plan.id}] ${plan.text}`);
500
+ }
501
+ }
502
+ lines.push('');
503
+ }
504
+ if (result.estimation_calibration) {
505
+ lines.push(`Estimation calibration: ${result.estimation_calibration}`);
506
+ lines.push('');
507
+ }
508
+ lines.push(`Context schema: ${result.context_schema}`);
509
+ if (result.project_id) {
510
+ lines.push(`Project ID: ${result.project_id}`);
511
+ }
512
+ if (result.agent_id && result.agent) {
513
+ lines.push(`Agent ID: ${result.agent_id}`);
514
+ }
515
+ lines.push(`Project mode: ${result.project_mode} (${result.project_strategy})`);
516
+ lines.push(`Current host: ${result.current_host}`);
517
+ lines.push(`Memory version: ${result.memory_version}`);
518
+ lines.push(`Memory density: ${result.memory_density}`);
519
+ lines.push(`Bootstrap available: ${result.bootstrap_available ? 'yes' : 'no'}`);
520
+ if (result.stores && result.stores.length > 1) {
521
+ lines.push(`Store chain: ${result.stores.map((s) => `${s.role}(d=${s.depth})`).join(' → ')}`);
522
+ }
523
+ if (result.all_hosts) {
524
+ lines.push('Runtime host filter: all-hosts');
525
+ }
526
+ else if (result.host_filter) {
527
+ lines.push(`Runtime host filter: ${result.host_filter}`);
528
+ }
529
+ if (result.project) {
530
+ lines.push(`Resolved project: ${result.project}`);
531
+ }
532
+ if (result.agent) {
533
+ const suffix = result.agent_id ? ` (${result.agent_id})` : '';
534
+ lines.push(`Resolved agent: ${result.agent}${suffix}`);
535
+ }
536
+ if (result.execution_context) {
537
+ lines.push('');
538
+ lines.push('Execution context:');
539
+ if (result.execution_context.branch) {
540
+ lines.push(`- Branch: ${result.execution_context.branch}`);
541
+ }
542
+ lines.push(`- Git status: ${result.execution_context.git_status}`);
543
+ lines.push(`- Workspace: ${result.execution_context.workspace_root}`);
544
+ const toolchains = result.execution_context.toolchains.map((tool) => `${tool.name}${tool.version ? ` ${tool.version}` : ''}`);
545
+ if (toolchains.length > 0) {
546
+ lines.push(`- Toolchains: ${toolchains.join(', ')}`);
547
+ }
548
+ }
549
+ if (result.agent_tooling) {
550
+ lines.push('');
551
+ lines.push('Agent tooling:');
552
+ lines.push(`- AGENTS.md: ${result.agent_tooling.agents_md_present ? 'present' : 'absent'}`);
553
+ if (result.agent_tooling.agents_md_title) {
554
+ lines.push(`- AGENTS title: ${result.agent_tooling.agents_md_title}`);
555
+ }
556
+ for (const rule of result.agent_tooling.agents_rules) {
557
+ lines.push(`- Rule: ${rule}`);
558
+ }
559
+ if (result.agent_tooling.skills.length > 0) {
560
+ lines.push(`- Skills: ${result.agent_tooling.skills.map((skill) => formatSkillSummary(skill)).join(', ')}`);
561
+ }
562
+ if (result.agent_tooling.mcp_servers.length > 0) {
563
+ lines.push(`- MCP servers: ${result.agent_tooling.mcp_servers.map((server) => formatMcpServerSummary(server)).join(', ')}`);
564
+ }
565
+ }
566
+ if (result.context_diff) {
567
+ lines.push('');
568
+ lines.push('New since session started:');
569
+ lines.push(`- ${result.context_diff.summary}`);
570
+ }
571
+ if (result.digest) {
572
+ lines.push('');
573
+ lines.push('Digest:');
574
+ for (const line of result.digest.split('\n')) {
575
+ lines.push(`- ${line}`);
576
+ }
577
+ }
578
+ if (result.resume_summary) {
579
+ lines.push('');
580
+ lines.push(`Resume summary for ${result.resume_summary.agent_name}:`);
581
+ lines.push(`- Internal trust: ${result.resume_summary.internal_trust}`);
582
+ lines.push(`- Contribution quality: ${result.resume_summary.contribution_quality}`);
583
+ lines.push(`- Review reliability: ${result.resume_summary.review_reliability}`);
584
+ lines.push(`- Continuity hygiene: ${result.resume_summary.continuity_hygiene}`);
585
+ for (const item of result.resume_summary.strengths) {
586
+ lines.push(`- Strength: ${item}`);
587
+ }
588
+ for (const item of result.resume_summary.cautions) {
589
+ lines.push(`- Caution: ${item}`);
590
+ }
591
+ for (const item of result.resume_summary.suggested_focus) {
592
+ lines.push(`- Focus: ${item}`);
593
+ }
594
+ }
595
+ lines.push('');
596
+ if (result.target) {
597
+ lines.push(`Target: ${result.target}`);
598
+ lines.push('');
599
+ }
600
+ lines.push('Instructions:');
601
+ if (result.resolved_instructions.length === 0) {
602
+ lines.push('- None resolved.');
603
+ }
604
+ else {
605
+ for (const instruction of result.resolved_instructions) {
606
+ const scope = instruction.scope ? `:${instruction.scope}` : '';
607
+ const tags = instruction.tags.length ? ` [${instruction.tags.join(', ')}]` : '';
608
+ lines.push(`- [${instruction.id}] <${instruction.layer}${scope}> ${instruction.text}${tags}`);
609
+ }
610
+ }
611
+ lines.push('');
612
+ if (result.selected.length === 0) {
613
+ lines.push('- No relevant canonical memory found.');
614
+ if (result.derived_signals && result.derived_signals.length > 0) {
615
+ lines.push('');
616
+ lines.push('Derived signals:');
617
+ for (const signal of result.derived_signals) {
618
+ lines.push(`- [${signal.seed_kind}/${signal.confidence}] ${signal.text} <${signal.source_kind}:${signal.source_ref}>`);
619
+ }
620
+ }
621
+ return lines.join('\n');
622
+ }
623
+ lines.push('Canonical memory:');
624
+ for (const item of result.selected) {
625
+ const tags = item.tags.length ? ` [${item.tags.join(', ')}]` : '';
626
+ const extra = item.extra ? ` (${item.extra})` : '';
627
+ const why = explain && item.reasons.length ? ` {why: ${item.reasons.join(', ')}}` : '';
628
+ lines.push(`- [${item.id}] <${item.section}> ${item.text}${extra}${tags}${why}`);
629
+ }
630
+ if (result.derived_signals && result.derived_signals.length > 0) {
631
+ lines.push('');
632
+ lines.push('Derived signals:');
633
+ for (const signal of result.derived_signals) {
634
+ lines.push(`- [${signal.seed_kind}/${signal.confidence}] ${signal.text} <${signal.source_kind}:${signal.source_ref}>`);
635
+ }
636
+ }
637
+ return lines.join('\n');
638
+ }
639
+ export function renderContextPromptTemplate(result, compact = false) {
640
+ const lines = [];
641
+ if (!compact) {
642
+ lines.push('Use the following project memory context before planning or making changes:');
643
+ lines.push('');
644
+ }
645
+ lines.push('```memory-context');
646
+ if (compact) {
647
+ lines.push(`cs=${result.context_schema}`);
648
+ if (result.digest) {
649
+ lines.push('dg:');
650
+ for (const line of result.digest.split('\n')) {
651
+ lines.push(` - ${line}`);
652
+ }
653
+ }
654
+ lines.push(`p=${result.profile}`);
655
+ if (result.project_id) {
656
+ lines.push(`pid=${result.project_id}`);
657
+ }
658
+ if (result.agent_id) {
659
+ lines.push(`aid=${result.agent_id}`);
660
+ }
661
+ lines.push(`pm=${result.project_mode}`);
662
+ lines.push(`ps=${result.project_strategy}`);
663
+ lines.push(`ch=${result.current_host}`);
664
+ lines.push(`mv=${result.memory_version}`);
665
+ lines.push(`md=${result.memory_density}`);
666
+ lines.push(`ba=${result.bootstrap_available ? 'y' : 'n'}`);
667
+ if (result.all_hosts) {
668
+ lines.push('hf=all-hosts');
669
+ }
670
+ else if (result.host_filter) {
671
+ lines.push(`hf=${result.host_filter}`);
672
+ }
673
+ if (result.project) {
674
+ lines.push(`pr=${result.project}`);
675
+ }
676
+ if (result.agent) {
677
+ lines.push(`ag=${result.agent}`);
678
+ }
679
+ if (result.execution_context) {
680
+ if (result.execution_context.branch) {
681
+ lines.push(`br=${result.execution_context.branch}`);
682
+ }
683
+ lines.push(`gs=${result.execution_context.git_status}`);
684
+ lines.push(`wr=${result.execution_context.workspace_root}`);
685
+ }
686
+ if (result.agent_tooling) {
687
+ lines.push(`am=${result.agent_tooling.agents_md_present ? 'y' : 'n'}`);
688
+ lines.push(`ar=${result.agent_tooling.agents_rules.length}`);
689
+ lines.push(`sk=${result.agent_tooling.skills.length}`);
690
+ lines.push(`ms=${result.agent_tooling.mcp_servers.length}`);
691
+ }
692
+ if (result.context_diff) {
693
+ lines.push(`sd=${result.context_diff.since_session ?? ''}`);
694
+ lines.push(`dc=${result.context_diff.counts.total}`);
695
+ }
696
+ if (result.resume_summary) {
697
+ lines.push(`rt=${result.resume_summary.internal_trust}`);
698
+ lines.push('rs:');
699
+ for (const item of result.resume_summary.suggested_focus) {
700
+ lines.push(` - ${item}`);
701
+ }
702
+ }
703
+ if (result.target) {
704
+ lines.push(`t=${result.target}`);
705
+ }
706
+ }
707
+ else {
708
+ lines.push(`context_schema: ${result.context_schema}`);
709
+ if (result.digest) {
710
+ lines.push('digest:');
711
+ for (const line of result.digest.split('\n')) {
712
+ lines.push(` - ${line}`);
713
+ }
714
+ }
715
+ lines.push(`profile: ${result.profile}`);
716
+ if (result.project_id) {
717
+ lines.push(`project_id: ${result.project_id}`);
718
+ }
719
+ if (result.agent_id) {
720
+ lines.push(`agent_id: ${result.agent_id}`);
721
+ }
722
+ lines.push(`project_mode: ${result.project_mode}`);
723
+ lines.push(`project_strategy: ${result.project_strategy}`);
724
+ lines.push(`current_host: ${result.current_host}`);
725
+ lines.push(`memory_version: ${result.memory_version}`);
726
+ lines.push(`memory_density: ${result.memory_density}`);
727
+ lines.push(`bootstrap_available: ${result.bootstrap_available}`);
728
+ if (result.all_hosts) {
729
+ lines.push('host_filter: all-hosts');
730
+ }
731
+ else if (result.host_filter) {
732
+ lines.push(`host_filter: ${result.host_filter}`);
733
+ }
734
+ if (result.project) {
735
+ lines.push(`project: ${result.project}`);
736
+ }
737
+ if (result.agent) {
738
+ lines.push(`agent: ${result.agent}`);
739
+ }
740
+ if (result.execution_context) {
741
+ lines.push('execution_context:');
742
+ lines.push(` platform: ${result.execution_context.platform}`);
743
+ if (result.execution_context.branch) {
744
+ lines.push(` branch: ${result.execution_context.branch}`);
745
+ }
746
+ lines.push(` git_status: ${result.execution_context.git_status}`);
747
+ lines.push(` workspace_root: ${result.execution_context.workspace_root}`);
748
+ lines.push(' toolchains:');
749
+ for (const tool of result.execution_context.toolchains) {
750
+ lines.push(` - ${tool.name}${tool.version ? ` ${tool.version}` : ''}`);
751
+ }
752
+ }
753
+ if (result.agent_tooling) {
754
+ lines.push('agent_tooling:');
755
+ lines.push(` agents_md_present: ${result.agent_tooling.agents_md_present}`);
756
+ if (result.agent_tooling.agents_md_title) {
757
+ lines.push(` agents_md_title: ${result.agent_tooling.agents_md_title}`);
758
+ }
759
+ lines.push(' agents_rules:');
760
+ for (const rule of result.agent_tooling.agents_rules) {
761
+ lines.push(` - ${rule}`);
762
+ }
763
+ lines.push(' skills:');
764
+ for (const skill of result.agent_tooling.skills) {
765
+ lines.push(` - ${formatSkillSummary(skill)}`);
766
+ }
767
+ lines.push(' mcp_servers:');
768
+ for (const server of result.agent_tooling.mcp_servers) {
769
+ lines.push(` - ${formatMcpServerSummary(server)}`);
770
+ }
771
+ }
772
+ if (result.context_diff) {
773
+ lines.push('context_diff:');
774
+ if (result.context_diff.since_session) {
775
+ lines.push(` since_session: ${result.context_diff.since_session}`);
776
+ }
777
+ if (result.context_diff.since) {
778
+ lines.push(` since: ${result.context_diff.since}`);
779
+ }
780
+ lines.push(` summary: ${result.context_diff.summary}`);
781
+ lines.push(' counts:');
782
+ lines.push(` constraints: ${result.context_diff.counts.constraints}`);
783
+ lines.push(` decisions: ${result.context_diff.counts.decisions}`);
784
+ lines.push(` traps: ${result.context_diff.counts.traps}`);
785
+ lines.push(` handoffs: ${result.context_diff.counts.handoffs}`);
786
+ lines.push(` pending_candidates: ${result.context_diff.counts.pending_candidates}`);
787
+ lines.push(` total: ${result.context_diff.counts.total}`);
788
+ }
789
+ if (result.resume_summary) {
790
+ lines.push('resume_summary:');
791
+ lines.push(` agent_name: ${result.resume_summary.agent_name}`);
792
+ if (result.resume_summary.agent_id) {
793
+ lines.push(` agent_id: ${result.resume_summary.agent_id}`);
794
+ }
795
+ lines.push(` internal_trust: ${result.resume_summary.internal_trust}`);
796
+ lines.push(` contribution_quality: ${result.resume_summary.contribution_quality}`);
797
+ lines.push(` review_reliability: ${result.resume_summary.review_reliability}`);
798
+ lines.push(` continuity_hygiene: ${result.resume_summary.continuity_hygiene}`);
799
+ lines.push(' suggested_focus:');
800
+ for (const item of result.resume_summary.suggested_focus) {
801
+ lines.push(` - ${item}`);
802
+ }
803
+ }
804
+ if (result.target) {
805
+ lines.push(`target: ${result.target}`);
806
+ }
807
+ }
808
+ if (result.open_work && (result.open_work.active_claims.length > 0 || result.open_work.in_progress_plans.length > 0)) {
809
+ lines.push(compact ? 'ow:' : 'open_work:');
810
+ if (result.open_work.active_claims.length > 0) {
811
+ lines.push(compact ? ' claims:' : ' active_claims:');
812
+ for (const claim of result.open_work.active_claims) {
813
+ if (compact) {
814
+ const planRef = claim.plan_id ? ` pl=${claim.plan_id}` : '';
815
+ lines.push(` - id=${claim.id}${planRef} sc="${claim.scope}" tx="${claim.description}"`);
816
+ }
817
+ else {
818
+ const planRef = claim.plan_id ? ` plan_id=${claim.plan_id}` : '';
819
+ lines.push(` - id=${claim.id}${planRef} scope="${claim.scope}" description="${claim.description}"`);
820
+ }
821
+ }
822
+ }
823
+ if (result.open_work.in_progress_plans.length > 0) {
824
+ lines.push(compact ? ' plans:' : ' in_progress_plans:');
825
+ for (const plan of result.open_work.in_progress_plans) {
826
+ if (compact) {
827
+ lines.push(` - id=${plan.id} tx="${plan.text}"`);
828
+ }
829
+ else {
830
+ lines.push(` - id=${plan.id} text="${plan.text}"`);
831
+ }
832
+ }
833
+ }
834
+ }
835
+ lines.push(compact ? 'ins:' : 'instructions:');
836
+ if (result.resolved_instructions.length === 0) {
837
+ lines.push(compact ? ' - n' : ' - none');
838
+ }
839
+ else {
840
+ for (const instruction of result.resolved_instructions) {
841
+ if (compact) {
842
+ const scope = instruction.scope ? ` sc=${instruction.scope}` : '';
843
+ const tags = instruction.tags.length ? ` tg=[${instruction.tags.join(',')}]` : '';
844
+ lines.push(` - id=${instruction.id} ly=${instruction.layer}${scope}${tags} tx="${instruction.text}"`);
845
+ }
846
+ else {
847
+ const scope = instruction.scope ? ` scope=${instruction.scope}` : '';
848
+ const tags = instruction.tags.length ? ` tags=[${instruction.tags.join(',')}]` : '';
849
+ lines.push(` - id=${instruction.id} layer=${instruction.layer}${scope}${tags} text="${instruction.text}"`);
850
+ }
851
+ }
852
+ }
853
+ lines.push(compact ? 'i:' : 'items:');
854
+ if (result.selected.length === 0) {
855
+ lines.push(compact ? ' - n' : ' - none');
856
+ }
857
+ else {
858
+ for (const item of result.selected) {
859
+ if (compact) {
860
+ const tags = item.tags.length ? ` tg=[${item.tags.join(',')}]` : '';
861
+ const extra = item.extra ? ` ex="${item.extra}"` : '';
862
+ const why = item.reasons.length ? ` why=[${item.reasons.join('|')}]` : '';
863
+ lines.push(` - id=${item.id} tp=${item.section}${tags}${extra}${why} tx="${item.text}"`);
864
+ }
865
+ else {
866
+ const tags = item.tags.length ? ` tags=[${item.tags.join(',')}]` : '';
867
+ const extra = item.extra ? ` extra="${item.extra}"` : '';
868
+ const why = item.reasons.length ? ` why=[${item.reasons.join(', ')}]` : '';
869
+ lines.push(` - id=${item.id} type=${item.section}${tags}${extra}${why} text="${item.text}"`);
870
+ }
871
+ }
872
+ }
873
+ if (result.derived_signals && result.derived_signals.length > 0) {
874
+ lines.push(compact ? 'ds:' : 'derived_signals:');
875
+ for (const signal of result.derived_signals) {
876
+ if (compact) {
877
+ const paths = signal.related_paths?.length ? ` rp=[${signal.related_paths.join(',')}]` : '';
878
+ lines.push(` - id=${signal.id} sk=${signal.seed_kind} cf=${signal.confidence} src=${signal.source_kind}:${signal.source_ref}${paths} tx="${signal.text}"`);
879
+ }
880
+ else {
881
+ const paths = signal.related_paths?.length ? ` related_paths=[${signal.related_paths.join(',')}]` : '';
882
+ lines.push(` - id=${signal.id} seed_kind=${signal.seed_kind} confidence=${signal.confidence} source=${signal.source_kind}:${signal.source_ref}${paths} text="${signal.text}"`);
883
+ }
884
+ }
885
+ }
886
+ if (result.context_diff) {
887
+ lines.push(compact ? 'cd:' : 'context_diff_items:');
888
+ for (const item of result.context_diff.changed_items ?? []) {
889
+ if (compact) {
890
+ lines.push(` - tp=${item.section} id=${item.id} tx="${item.text}"`);
891
+ }
892
+ else {
893
+ lines.push(` - type=${item.section} id=${item.id} created_at=${item.created_at} text="${item.text}"`);
894
+ }
895
+ }
896
+ }
897
+ lines.push('```');
898
+ return lines.join('\n');
899
+ }
900
+ export function buildScopedActivity(input) {
901
+ const target = input.target?.trim();
902
+ if (!target) {
903
+ return undefined;
904
+ }
905
+ const project = input.project?.trim();
906
+ const matchingDecisions = input.state.recent_decisions.filter((item) => matchesScopeTarget(item, target, project));
907
+ const matchingTraps = [
908
+ ...input.state.known_traps.filter((item) => isTrapActive(item) && matchesScopeTarget(item, target, project)),
909
+ ].sort((a, b) => b.created_at.localeCompare(a.created_at));
910
+ const matchingRuntime = input.runtimeNotes
911
+ .filter((item) => matchesScopeTarget(item, target, project))
912
+ .sort((a, b) => b.created_at.localeCompare(a.created_at));
913
+ const matchingPending = input.pendingCandidates.filter((item) => matchesScopeTarget(item, target, project));
914
+ if (matchingDecisions.length === 0
915
+ && matchingTraps.length === 0
916
+ && matchingRuntime.length === 0
917
+ && matchingPending.length === 0) {
918
+ return undefined;
919
+ }
920
+ const lastDecision = matchingDecisions.sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
921
+ const lastTrap = matchingTraps[0];
922
+ const latestRuntime = matchingRuntime[0];
923
+ return {
924
+ scope: target,
925
+ last_decision: lastDecision ? summariseScopedItem(lastDecision) : undefined,
926
+ last_trap: lastTrap ? summariseScopedItem(lastTrap) : undefined,
927
+ recent_notes: matchingRuntime.filter((item) => isRecent(item.created_at, 7 * 24)).length,
928
+ pending_candidates: matchingPending.length,
929
+ last_agent: latestRuntime?.agent,
930
+ last_session: latestRuntime?.session_id,
931
+ };
932
+ }
933
+ export function buildContextDigest(result) {
934
+ const lines = [];
935
+ const highTraps = result.selected.filter((item) => item.section === 'trap' && item.extra?.includes('high'));
936
+ const constraints = result.selected.filter((item) => item.section === 'constraint');
937
+ const decisions = result.selected.filter((item) => item.section === 'decision');
938
+ const candidates = result.selected.filter((item) => item.section === 'candidate');
939
+ const scoped = result.scoped_activity;
940
+ if (highTraps.length > 0) {
941
+ lines.push(`High trap: ${highTraps[0].text}`);
942
+ }
943
+ if (constraints.length > 0) {
944
+ lines.push(`Active constraint: ${constraints[0].text}`);
945
+ }
946
+ if (decisions.length > 0) {
947
+ lines.push(`Recent decision: ${decisions[0].text}`);
948
+ }
949
+ if (candidates.length > 0 || (scoped?.pending_candidates ?? 0) > 0) {
950
+ const pendingCount = Math.max(candidates.length, scoped?.pending_candidates ?? 0);
951
+ lines.push(`Pending candidates: ${pendingCount}`);
952
+ }
953
+ if (scoped) {
954
+ const scopedParts = [`Scoped activity on ${scoped.scope}: ${scoped.recent_notes} recent note(s)`];
955
+ if (scoped.last_agent) {
956
+ scopedParts.push(`last agent ${scoped.last_agent}`);
957
+ }
958
+ lines.push(scopedParts.join(', '));
959
+ }
960
+ else if (result.selected.some((item) => item.section === 'runtime')) {
961
+ lines.push(`Runtime signal: ${result.selected.find((item) => item.section === 'runtime')?.text}`);
962
+ }
963
+ if (result.memory_density === 'low' && result.derived_signals && result.derived_signals.length > 0) {
964
+ const signal = result.derived_signals[0];
965
+ lines.push(`Derived ${signal.seed_kind}: ${signal.text}`);
966
+ }
967
+ if (result.context_diff && result.context_diff.counts.total > 0) {
968
+ lines.push(`New since session started: ${result.context_diff.summary}`);
969
+ }
970
+ if (result.agent_tooling?.agents_rules.length) {
971
+ lines.push(`Agent rule: ${result.agent_tooling.agents_rules[0]}`);
972
+ }
973
+ const blockingServer = result.agent_tooling?.mcp_servers.find((server) => server.availability === 'missing_command');
974
+ if (blockingServer) {
975
+ lines.push(`Tooling warning: MCP ${blockingServer.name} is configured but ${blockingServer.command ?? 'its command'} is unavailable.`);
976
+ }
977
+ if ((result.memory_density === 'low' || result.execution_context?.git_status === 'dirty') && result.execution_context) {
978
+ if (result.execution_context.git_status === 'dirty') {
979
+ lines.push('Execution: repository has uncommitted changes.');
980
+ }
981
+ else if (result.execution_context.branch) {
982
+ lines.push(`Execution: branch ${result.execution_context.branch}`);
983
+ }
984
+ else if (result.execution_context.toolchains[0]) {
985
+ const tool = result.execution_context.toolchains[0];
986
+ lines.push(`Execution: toolchain ${tool.name}${tool.version ? ` ${tool.version}` : ''}`);
987
+ }
988
+ }
989
+ return lines.slice(0, 5).join('\n');
990
+ }
991
+ function classifyMemoryDensity(selectedCount) {
992
+ if (selectedCount < 3)
993
+ return 'low';
994
+ if (selectedCount <= 6)
995
+ return 'medium';
996
+ return 'high';
997
+ }
998
+ function summariseAgentTooling(snapshot) {
999
+ return {
1000
+ agents_md_present: snapshot.agents_md_present,
1001
+ agents_md_title: snapshot.agents_md_title,
1002
+ agents_rules: snapshot.agents_rules.slice(0, 5),
1003
+ skills: snapshot.skills.slice(0, 5),
1004
+ mcp_servers: snapshot.mcp_servers.slice(0, 5),
1005
+ };
1006
+ }
1007
+ function formatSkillSummary(skill) {
1008
+ const markers = [];
1009
+ if (skill.scripts_present)
1010
+ markers.push('scripts');
1011
+ if (skill.references_present)
1012
+ markers.push('references');
1013
+ if (skill.assets_present)
1014
+ markers.push('assets');
1015
+ const suffix = markers.length > 0 ? ` [${markers.join(', ')}]` : '';
1016
+ return `${skill.name}${skill.description ? `: ${skill.description}` : ''}${suffix}`;
1017
+ }
1018
+ function formatMcpServerSummary(server) {
1019
+ const availability = server.availability === 'missing_command'
1020
+ ? 'missing-command'
1021
+ : server.availability;
1022
+ return `${server.name} (${server.transport}, ${availability})`;
1023
+ }
1024
+ function isExecutionSensitiveTarget(target) {
1025
+ const terms = target.toLowerCase();
1026
+ return [
1027
+ 'package.json',
1028
+ 'makefile',
1029
+ 'pyproject',
1030
+ 'cargo',
1031
+ 'go.mod',
1032
+ 'docker',
1033
+ 'workflow',
1034
+ 'github',
1035
+ 'git',
1036
+ 'npm',
1037
+ 'pnpm',
1038
+ 'python',
1039
+ 'shell',
1040
+ 'env',
1041
+ 'mcp',
1042
+ 'skill',
1043
+ 'agent',
1044
+ 'build',
1045
+ 'test',
1046
+ 'lint',
1047
+ ].some((token) => terms.includes(token));
1048
+ }
1049
+ function tokenise(input) {
1050
+ return input
1051
+ .toLowerCase()
1052
+ .split(/[^a-z0-9_\/-]+/)
1053
+ .map((x) => x.trim())
1054
+ .filter(Boolean);
1055
+ }
1056
+ function matchesPath(pattern, target) {
1057
+ if (pattern === target)
1058
+ return true;
1059
+ const regexStr = '^' + pattern
1060
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex chars but keep globs intact
1061
+ .replace(/\*\*/g, '__GLOBSTAR__')
1062
+ .replace(/\*/g, '__GLOB__')
1063
+ .replace(/__GLOBSTAR__/g, '.*')
1064
+ .replace(/__GLOB__/g, '[^/]*') + '$';
1065
+ return new RegExp(regexStr).test(target);
1066
+ }
1067
+ function summariseScopedItem(item) {
1068
+ return {
1069
+ id: item.id,
1070
+ text: item.text,
1071
+ age_hours: Math.max(0, Math.floor((Date.now() - Date.parse(item.created_at)) / 3_600_000)),
1072
+ };
1073
+ }
1074
+ function isRecent(createdAt, hours) {
1075
+ return Date.now() - Date.parse(createdAt) <= hours * 3_600_000;
1076
+ }
1077
+ function matchesScopeTarget(item, target, project) {
1078
+ if (project && item.project && item.project !== project) {
1079
+ return false;
1080
+ }
1081
+ if (item.related_paths && item.related_paths.length > 0) {
1082
+ return item.related_paths.some((pattern) => matchesPath(pattern, target));
1083
+ }
1084
+ const terms = scopeTerms(target);
1085
+ if (terms.length === 0) {
1086
+ return false;
1087
+ }
1088
+ const haystack = `${item.text.toLowerCase()} ${(item.tags ?? []).join(' ').toLowerCase()}`;
1089
+ return terms.some((term) => haystack.includes(term));
1090
+ }
1091
+ function scopeTerms(target) {
1092
+ const direct = tokenise(target);
1093
+ const segments = target
1094
+ .split(/[\\/]/)
1095
+ .flatMap((segment) => tokenise(segment));
1096
+ return [...new Set([...direct, ...segments])];
1097
+ }
1098
+ function computeRelevance(item, terms, profile, target) {
1099
+ let score = 1;
1100
+ const reasons = ['base memory signal'];
1101
+ // Path filtering logic
1102
+ if (item.related_paths && item.related_paths.length > 0 && target) {
1103
+ const isMatch = item.related_paths.some(p => matchesPath(p, target));
1104
+ if (isMatch) {
1105
+ score += 10; // High boost for direct spatial match
1106
+ reasons.push('path match');
1107
+ }
1108
+ else {
1109
+ return { score: -1, reasons: ['filtered out: path mismatch'] };
1110
+ }
1111
+ }
1112
+ // Profile weighting
1113
+ // Plans are always highest priority (actionable items)
1114
+ if (item.section === 'plan') {
1115
+ score += 4;
1116
+ reasons.push('execution boost');
1117
+ }
1118
+ // Open handoffs are second-highest (pending transitions)
1119
+ if (item.section === 'handoff') {
1120
+ score += 3;
1121
+ reasons.push('open handoff signal');
1122
+ }
1123
+ if (item.section === 'runtime') {
1124
+ score += 1;
1125
+ reasons.push('runtime execution signal');
1126
+ }
1127
+ if (profile === 'dev' && (item.section === 'decision' || item.section === 'trap')) {
1128
+ score += 2;
1129
+ reasons.push('profile boost: dev');
1130
+ }
1131
+ if (profile === 'openclaw' && (item.section === 'constraint' || item.section === 'handoff' || item.section === 'runtime')) {
1132
+ score += 2;
1133
+ reasons.push('profile boost: openclaw');
1134
+ }
1135
+ if (profile === 'ops' && (item.section === 'constraint' || item.section === 'trap')) {
1136
+ score += 2;
1137
+ reasons.push('profile boost: ops');
1138
+ }
1139
+ if (profile === 'research' && (item.section === 'decision' || item.section === 'candidate')) {
1140
+ score += 2;
1141
+ reasons.push('profile boost: research');
1142
+ }
1143
+ if (profile === 'compact' && item.section === 'plan' && (item.extra ?? '').includes('in_progress')) {
1144
+ score += 3;
1145
+ reasons.push('profile boost: compact');
1146
+ }
1147
+ if (profile === 'copilot' && item.section === 'constraint') {
1148
+ score += 3;
1149
+ reasons.push('profile boost: copilot');
1150
+ }
1151
+ if (profile === 'quick' && item.section === 'constraint') {
1152
+ score += 4;
1153
+ reasons.push('profile boost: quick');
1154
+ }
1155
+ if (item.section === 'candidate') {
1156
+ const starMatch = (item.extra ?? '').match(/stars:(\d+)/);
1157
+ const useMatch = (item.extra ?? '').match(/uses:(\d+)/);
1158
+ const stars = starMatch ? parseInt(starMatch[1], 10) : 0;
1159
+ const uses = useMatch ? parseInt(useMatch[1], 10) : 0;
1160
+ if (stars > 0) {
1161
+ score += Math.min(stars, 3);
1162
+ reasons.push(`adoption signal:${stars} star(s)`);
1163
+ }
1164
+ if (uses > 0) {
1165
+ score += Math.min(uses * 2, 4);
1166
+ reasons.push(`reuse signal:${uses} use(s)`);
1167
+ }
1168
+ }
1169
+ if (terms.length === 0)
1170
+ return { score, reasons };
1171
+ const text = item.text.toLowerCase();
1172
+ const tags = item.tags.map((t) => t.toLowerCase());
1173
+ const extra = (item.extra ?? '').toLowerCase();
1174
+ for (const term of terms) {
1175
+ if (text.includes(term)) {
1176
+ score += 3;
1177
+ reasons.push(`text match:${term}`);
1178
+ }
1179
+ if (tags.some((tag) => tag.includes(term))) {
1180
+ score += 2;
1181
+ reasons.push(`tag match:${term}`);
1182
+ }
1183
+ if (extra.includes(term)) {
1184
+ score += 1;
1185
+ reasons.push(`metadata match:${term}`);
1186
+ }
1187
+ }
1188
+ return { score, reasons: uniqueReasons(reasons) };
1189
+ }
1190
+ function uniqueReasons(reasons) {
1191
+ return [...new Set(reasons)];
1192
+ }
1193
+ function estimateItemChars(item) {
1194
+ const tagsLen = item.tags.join(', ').length;
1195
+ const reasonsLen = item.reasons.join(', ').length;
1196
+ const extraLen = item.extra?.length ?? 0;
1197
+ return item.text.length + tagsLen + reasonsLen + extraLen + 32;
1198
+ }
1199
+ function applyCharBudget(items, maxChars) {
1200
+ let used = 0;
1201
+ const selected = [];
1202
+ for (const item of items) {
1203
+ const itemChars = estimateItemChars(item);
1204
+ if (selected.length > 0 && used + itemChars > maxChars) {
1205
+ break;
1206
+ }
1207
+ selected.push(item);
1208
+ used += itemChars;
1209
+ }
1210
+ return selected;
1211
+ }
1212
+ //# sourceMappingURL=context.js.map