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.
- package/LICENSE +74 -0
- package/README.md +226 -0
- package/dist/cli.js +1037 -0
- package/dist/commands/accept.js +149 -0
- package/dist/commands/adapter-openclaw-import.js +75 -0
- package/dist/commands/add-step.js +35 -0
- package/dist/commands/agent-board.js +106 -0
- package/dist/commands/audit.js +35 -0
- package/dist/commands/bootstrap.js +34 -0
- package/dist/commands/capability.js +104 -0
- package/dist/commands/changes.js +112 -0
- package/dist/commands/check-constraints.js +63 -0
- package/dist/commands/claim-resource.js +54 -0
- package/dist/commands/claim.js +92 -0
- package/dist/commands/complete-step.js +34 -0
- package/dist/commands/constraint.js +44 -0
- package/dist/commands/context-diff.js +32 -0
- package/dist/commands/context.js +63 -0
- package/dist/commands/decision.js +45 -0
- package/dist/commands/delete-plan.js +20 -0
- package/dist/commands/diff.js +99 -0
- package/dist/commands/doctor.js +1275 -0
- package/dist/commands/enable-agent.js +63 -0
- package/dist/commands/env.js +46 -0
- package/dist/commands/estimation-report.js +167 -0
- package/dist/commands/explore.js +47 -0
- package/dist/commands/export.js +381 -0
- package/dist/commands/handoff.js +63 -0
- package/dist/commands/history.js +22 -0
- package/dist/commands/hooks.js +123 -0
- package/dist/commands/init.js +356 -0
- package/dist/commands/install-hooks.js +115 -0
- package/dist/commands/instruction.js +56 -0
- package/dist/commands/list-agents.js +44 -0
- package/dist/commands/list-claims.js +45 -0
- package/dist/commands/list-instructions.js +50 -0
- package/dist/commands/list-plans.js +48 -0
- package/dist/commands/mcp-worker.js +12 -0
- package/dist/commands/mcp.js +2272 -0
- package/dist/commands/memory.js +283 -0
- package/dist/commands/metrics.js +175 -0
- package/dist/commands/plan-resource.js +62 -0
- package/dist/commands/plan.js +76 -0
- package/dist/commands/prune-candidates.js +36 -0
- package/dist/commands/prune.js +48 -0
- package/dist/commands/pull.js +25 -0
- package/dist/commands/push.js +28 -0
- package/dist/commands/rebuild.js +14 -0
- package/dist/commands/reflect-runtime-note.js +74 -0
- package/dist/commands/reflect.js +286 -0
- package/dist/commands/register-agent.js +29 -0
- package/dist/commands/reject.js +52 -0
- package/dist/commands/release-claim.js +41 -0
- package/dist/commands/release-claims.js +67 -0
- package/dist/commands/review.js +242 -0
- package/dist/commands/rollback.js +156 -0
- package/dist/commands/runtime-note.js +144 -0
- package/dist/commands/runtime-status.js +49 -0
- package/dist/commands/search.js +36 -0
- package/dist/commands/session-end.js +187 -0
- package/dist/commands/session-start.js +147 -0
- package/dist/commands/set-trust.js +92 -0
- package/dist/commands/setup.js +446 -0
- package/dist/commands/show-candidate.js +31 -0
- package/dist/commands/star-candidate.js +28 -0
- package/dist/commands/status.js +133 -0
- package/dist/commands/sync.js +159 -0
- package/dist/commands/tool.js +126 -0
- package/dist/commands/trap.js +74 -0
- package/dist/commands/update-handoff.js +23 -0
- package/dist/commands/update-plan.js +37 -0
- package/dist/commands/upgrade.js +382 -0
- package/dist/commands/use-candidate.js +35 -0
- package/dist/commands/version.js +96 -0
- package/dist/commands/watch.js +215 -0
- package/dist/commands/whoami.js +104 -0
- package/dist/core/agent-context.js +340 -0
- package/dist/core/agent-files.js +874 -0
- package/dist/core/agent-integrations.js +135 -0
- package/dist/core/agent-inventory.js +401 -0
- package/dist/core/agent-registry.js +420 -0
- package/dist/core/ai-agent-detection.js +140 -0
- package/dist/core/audit.js +85 -0
- package/dist/core/bootstrap.js +658 -0
- package/dist/core/brainclaw-version.js +433 -0
- package/dist/core/candidates.js +137 -0
- package/dist/core/circuit-breaker.js +118 -0
- package/dist/core/claims.js +72 -0
- package/dist/core/config.js +86 -0
- package/dist/core/context-diff.js +122 -0
- package/dist/core/context.js +1212 -0
- package/dist/core/contradictions.js +270 -0
- package/dist/core/coordination.js +86 -0
- package/dist/core/cross-project.js +99 -0
- package/dist/core/duplicates.js +72 -0
- package/dist/core/event-log.js +152 -0
- package/dist/core/events.js +56 -0
- package/dist/core/execution-context.js +204 -0
- package/dist/core/freshness.js +87 -0
- package/dist/core/global-registry.js +182 -0
- package/dist/core/host.js +10 -0
- package/dist/core/identity.js +151 -0
- package/dist/core/ids.js +56 -0
- package/dist/core/input-validation.js +81 -0
- package/dist/core/instructions.js +117 -0
- package/dist/core/io.js +191 -0
- package/dist/core/json-store.js +63 -0
- package/dist/core/lifecycle.js +45 -0
- package/dist/core/lock.js +129 -0
- package/dist/core/logger.js +49 -0
- package/dist/core/machine-profile.js +332 -0
- package/dist/core/markdown.js +120 -0
- package/dist/core/memory-git.js +133 -0
- package/dist/core/migration.js +247 -0
- package/dist/core/project-registry.js +64 -0
- package/dist/core/reflection-safety.js +21 -0
- package/dist/core/repo-analysis.js +133 -0
- package/dist/core/reputation.js +409 -0
- package/dist/core/runtime.js +134 -0
- package/dist/core/schema.js +580 -0
- package/dist/core/search.js +115 -0
- package/dist/core/security.js +66 -0
- package/dist/core/setup-state.js +50 -0
- package/dist/core/state.js +83 -0
- package/dist/core/store-resolution.js +119 -0
- package/dist/core/sync-remote.js +83 -0
- package/dist/core/traps.js +86 -0
- 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
|