@andespindola/brainlink 1.0.5 → 1.0.6
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/README.md +8 -0
- package/dist/application/add-note.js +2 -2
- package/dist/application/build-context.js +16 -10
- package/dist/application/canonical-context-links.js +44 -5
- package/dist/application/check-package-update.js +105 -0
- package/dist/application/frontend/client/chunk-fetch.js +236 -0
- package/dist/application/frontend/client/controls.js +178 -0
- package/dist/application/frontend/client/elements.js +122 -0
- package/dist/application/frontend/client/input.js +202 -0
- package/dist/application/frontend/client/node-details.js +191 -0
- package/dist/application/frontend/client/rendering.js +296 -0
- package/dist/application/frontend/client/scope-theme.js +114 -0
- package/dist/application/frontend/client/spatial.js +98 -0
- package/dist/application/frontend/client/storage.js +215 -0
- package/dist/application/frontend/client/upload.js +90 -0
- package/dist/application/frontend/client/worker-bootstrap.js +147 -0
- package/dist/application/frontend/client-js.js +24 -1837
- package/dist/application/frontend/client-render-worker-js.js +1 -1
- package/dist/application/index-vault-phases.js +189 -0
- package/dist/application/index-vault.js +44 -165
- package/dist/cli/commands/write/dedupe-commands.js +59 -0
- package/dist/cli/commands/write/index-commands.js +205 -0
- package/dist/cli/commands/write/link-commands.js +68 -0
- package/dist/cli/commands/write/note-commands.js +146 -0
- package/dist/cli/commands/write/server-commands.js +553 -0
- package/dist/cli/commands/write/shared.js +35 -0
- package/dist/cli/commands/write/vault-lifecycle-commands.js +270 -0
- package/dist/cli/commands/write-commands.js +12 -1303
- package/dist/cli/main.js +39 -3
- package/dist/domain/context.js +39 -3
- package/dist/domain/embeddings.js +31 -5
- package/dist/domain/graph-contexts.js +62 -57
- package/dist/domain/graph-layout/cauliflower-layout.js +116 -0
- package/dist/domain/graph-layout/collisions.js +100 -0
- package/dist/domain/graph-layout/hierarchy.js +135 -0
- package/dist/domain/graph-layout/metrics.js +111 -0
- package/dist/domain/graph-layout/segments.js +76 -0
- package/dist/domain/graph-layout/star-layout.js +110 -0
- package/dist/domain/graph-layout.js +4 -625
- package/dist/infrastructure/config.js +6 -0
- package/dist/infrastructure/file-index.js +13 -4
- package/dist/infrastructure/semantic-prefilter.js +24 -0
- package/dist/mcp/server.js +7 -0
- package/dist/mcp/tool-guard.js +29 -0
- package/dist/mcp/tools/maintenance-tools.js +409 -0
- package/dist/mcp/tools/read-tools.js +504 -0
- package/dist/mcp/tools/shared.js +216 -0
- package/dist/mcp/tools/write-tools.js +247 -0
- package/dist/mcp/tools.js +3 -1357
- package/docs/QUICKSTART.md +4 -0
- package/package.json +2 -2
package/dist/mcp/tools.js
CHANGED
|
@@ -1,1357 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { getBrokenLinksReport, getOrphansReport, getStats, validateVault } from '../application/analyze-vault.js';
|
|
5
|
-
import { addNoteWithMetadata } from '../application/add-note.js';
|
|
6
|
-
import { buildContextPackage, readContextDataSignature } from '../application/build-context.js';
|
|
7
|
-
import { canonicalizeContextLinks } from '../application/canonical-context-links.js';
|
|
8
|
-
import { deleteNote } from '../application/delete-note.js';
|
|
9
|
-
import { resolveDuplicateNotes, scanDuplicateNotes } from '../application/dedupe-notes.js';
|
|
10
|
-
import { getGraph } from '../application/get-graph.js';
|
|
11
|
-
import { getGraphContexts } from '../application/get-graph-contexts.js';
|
|
12
|
-
import { addInboxItem, listInboxItems, processInboxItems } from '../application/inbox.js';
|
|
13
|
-
import { indexVault } from '../application/index-vault.js';
|
|
14
|
-
import { buildRememberSuggestion, explainSearchResults, suggestBrokenLinkFixes, suggestContextLinks } from '../application/memory-suggestions.js';
|
|
15
|
-
import { buildActionableDoctor, closeSession, initializeProjectMemory } from '../application/operational-workflows.js';
|
|
16
|
-
import { repairBrokenLinks } from '../application/repair-broken-links.js';
|
|
17
|
-
import { searchKnowledge } from '../application/search-knowledge.js';
|
|
18
|
-
import { resolveAgentRuntimeDefaults, sanitizeContextStrategy, sanitizeSearchMode } from '../infrastructure/config.js';
|
|
19
|
-
import { clearContextPacks, listContextPacks } from '../infrastructure/context-packs.js';
|
|
20
|
-
import { loadBrainlinkConfig } from '../infrastructure/config.js';
|
|
21
|
-
import { assertVaultAllowed } from '../infrastructure/file-system-vault.js';
|
|
22
|
-
import { addVolatileMemory, clearVolatileMemory } from '../infrastructure/volatile-memory.js';
|
|
23
|
-
import { getBootstrapPolicy, getBootstrapSessionStatus, getContextSessionStatus, setBootstrapPolicy, touchBootstrapSession, touchContextSession } from '../infrastructure/session-state.js';
|
|
24
|
-
import { getRuntimeMetadata } from './runtime.js';
|
|
25
|
-
const positiveInteger = (fallback) => z
|
|
26
|
-
.number()
|
|
27
|
-
.int()
|
|
28
|
-
.positive()
|
|
29
|
-
.optional()
|
|
30
|
-
.transform((value) => value ?? fallback);
|
|
31
|
-
const optionalPositiveInteger = () => z
|
|
32
|
-
.number()
|
|
33
|
-
.int()
|
|
34
|
-
.positive()
|
|
35
|
-
.optional();
|
|
36
|
-
const vaultInput = {
|
|
37
|
-
vault: z.string().min(1).optional().describe('Vault directory. Omit to use the configured Brainlink default vault.')
|
|
38
|
-
};
|
|
39
|
-
const agentInput = {
|
|
40
|
-
agent: z
|
|
41
|
-
.string()
|
|
42
|
-
.min(1)
|
|
43
|
-
.optional()
|
|
44
|
-
.describe('Agent memory namespace. Omit to use Brainlink.config defaultAgent, otherwise read all agent namespaces.')
|
|
45
|
-
};
|
|
46
|
-
const searchModeInput = {
|
|
47
|
-
mode: z.enum(['fts', 'semantic', 'hybrid']).optional().describe('Search mode. Defaults to the Brainlink config value.')
|
|
48
|
-
};
|
|
49
|
-
const contextStrategyInput = {
|
|
50
|
-
strategy: z
|
|
51
|
-
.enum(['rag', 'cag', 'auto'])
|
|
52
|
-
.optional()
|
|
53
|
-
.describe('Context strategy per call. Use rag for fresh retrieval assembly, cag to reuse persisted context packs when fresh, or auto to choose CAG on fresh pack hits and RAG otherwise. Defaults to the Brainlink config value.')
|
|
54
|
-
};
|
|
55
|
-
const resolveExecutionContext = async (input) => {
|
|
56
|
-
const config = await loadBrainlinkConfig();
|
|
57
|
-
const vault = await assertVaultAllowed(input.vault ?? config.vault, config.allowedVaults);
|
|
58
|
-
const agent = input.agent ?? config.defaultAgent;
|
|
59
|
-
const defaults = resolveAgentRuntimeDefaults(config, agent);
|
|
60
|
-
return {
|
|
61
|
-
config,
|
|
62
|
-
vault,
|
|
63
|
-
agent,
|
|
64
|
-
defaults
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
const inferTitleFromPath = (filePath) => {
|
|
68
|
-
const extension = extname(filePath);
|
|
69
|
-
const fromFileName = basename(filePath, extension);
|
|
70
|
-
return fromFileName
|
|
71
|
-
.trim()
|
|
72
|
-
.replace(/[-_]+/g, ' ')
|
|
73
|
-
.replace(/\s+/g, ' ')
|
|
74
|
-
.trim();
|
|
75
|
-
};
|
|
76
|
-
const isTruthy = (value) => value !== false;
|
|
77
|
-
const jsonResult = (value) => ({
|
|
78
|
-
content: [
|
|
79
|
-
{
|
|
80
|
-
type: 'text',
|
|
81
|
-
text: JSON.stringify(value, null, 2)
|
|
82
|
-
}
|
|
83
|
-
],
|
|
84
|
-
structuredContent: value
|
|
85
|
-
});
|
|
86
|
-
const preflightResult = (value) => jsonResult({
|
|
87
|
-
preflightRequired: true,
|
|
88
|
-
...value
|
|
89
|
-
});
|
|
90
|
-
const withNextActions = (value, nextActions) => ({
|
|
91
|
-
...value,
|
|
92
|
-
nextActions
|
|
93
|
-
});
|
|
94
|
-
const ensureBootstrapReady = async (context, input, toolName) => {
|
|
95
|
-
const policy = await getBootstrapPolicy();
|
|
96
|
-
if (!policy.enforceBootstrap) {
|
|
97
|
-
return {
|
|
98
|
-
bootstrap: {
|
|
99
|
-
autoBootstrapped: false,
|
|
100
|
-
policy,
|
|
101
|
-
statusBefore: {
|
|
102
|
-
ready: true,
|
|
103
|
-
stale: false
|
|
104
|
-
},
|
|
105
|
-
reason: 'Bootstrap enforcement is disabled by policy.'
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
const status = await getBootstrapSessionStatus(context.vault, context.agent);
|
|
110
|
-
if (status.ready) {
|
|
111
|
-
return {
|
|
112
|
-
bootstrap: {
|
|
113
|
-
autoBootstrapped: false,
|
|
114
|
-
policy,
|
|
115
|
-
statusBefore: status,
|
|
116
|
-
reason: 'Bootstrap session is already fresh for this vault/agent.'
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if (policy.autoBootstrapOnRead) {
|
|
121
|
-
const index = await indexVault(context.vault);
|
|
122
|
-
const session = await touchBootstrapSession(context.vault, context.agent);
|
|
123
|
-
const statusAfter = await getBootstrapSessionStatus(context.vault, context.agent);
|
|
124
|
-
return {
|
|
125
|
-
bootstrap: {
|
|
126
|
-
autoBootstrapped: true,
|
|
127
|
-
policy,
|
|
128
|
-
statusBefore: status,
|
|
129
|
-
statusAfter,
|
|
130
|
-
session,
|
|
131
|
-
index,
|
|
132
|
-
reason: 'Auto-bootstrap was applied for this read call because bootstrap was missing or stale.'
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
const mode = typeof input.mode === 'string' && ['fts', 'semantic', 'hybrid'].includes(input.mode) ? input.mode : 'hybrid';
|
|
137
|
-
const strategy = sanitizeContextStrategy(typeof input.strategy === 'string' ? input.strategy : undefined, 'rag');
|
|
138
|
-
const query = typeof input.query === 'string' && input.query.trim().length > 0 ? input.query : undefined;
|
|
139
|
-
const bootstrapArgs = {
|
|
140
|
-
vault: context.vault,
|
|
141
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
142
|
-
...(query ? { query } : {}),
|
|
143
|
-
mode,
|
|
144
|
-
strategy
|
|
145
|
-
};
|
|
146
|
-
const nextActions = [
|
|
147
|
-
{
|
|
148
|
-
tool: 'brainlink_bootstrap',
|
|
149
|
-
reason: 'Bootstrap is required before read tools so retrieval stays grounded in current vault state.',
|
|
150
|
-
args: bootstrapArgs
|
|
151
|
-
}
|
|
152
|
-
];
|
|
153
|
-
return {
|
|
154
|
-
preflight: preflightResult(withNextActions({
|
|
155
|
-
vault: context.vault,
|
|
156
|
-
agent: context.agent,
|
|
157
|
-
blockedTool: toolName,
|
|
158
|
-
policy,
|
|
159
|
-
bootstrapStatus: status,
|
|
160
|
-
guidance: 'Run brainlink_bootstrap first for this vault/agent before using read tools. This keeps retrieval grounded and memory state consistent.',
|
|
161
|
-
bootstrapArgs
|
|
162
|
-
}, nextActions))
|
|
163
|
-
};
|
|
164
|
-
};
|
|
165
|
-
const ensureContextReady = async (context, input, toolName) => {
|
|
166
|
-
const policy = await getBootstrapPolicy();
|
|
167
|
-
if (!policy.enforceContextFirst) {
|
|
168
|
-
return {
|
|
169
|
-
context: {
|
|
170
|
-
policy,
|
|
171
|
-
statusBefore: {
|
|
172
|
-
ready: true,
|
|
173
|
-
stale: false
|
|
174
|
-
},
|
|
175
|
-
reason: 'Context-first enforcement is disabled by policy.'
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
const status = await getContextSessionStatus(context.vault, context.agent);
|
|
180
|
-
if (status.ready) {
|
|
181
|
-
return {
|
|
182
|
-
context: {
|
|
183
|
-
policy,
|
|
184
|
-
statusBefore: status,
|
|
185
|
-
reason: 'Context session is already fresh for this vault/agent.'
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
const queryFromInput = typeof input.query === 'string' && input.query.trim().length > 0
|
|
190
|
-
? input.query
|
|
191
|
-
: typeof input.contextQuery === 'string' && input.contextQuery.trim().length > 0
|
|
192
|
-
? input.contextQuery
|
|
193
|
-
: '<task>';
|
|
194
|
-
const mode = sanitizeSearchMode(typeof input.mode === 'string' ? input.mode : undefined, context.defaults.defaultSearchMode);
|
|
195
|
-
const strategy = sanitizeContextStrategy(typeof input.strategy === 'string' ? input.strategy : undefined, context.defaults.defaultContextStrategy);
|
|
196
|
-
const limit = typeof input.limit === 'number' && Number.isFinite(input.limit) && input.limit > 0
|
|
197
|
-
? input.limit
|
|
198
|
-
: typeof input.contextLimit === 'number' && Number.isFinite(input.contextLimit) && input.contextLimit > 0
|
|
199
|
-
? input.contextLimit
|
|
200
|
-
: context.defaults.defaultSearchLimit;
|
|
201
|
-
const tokens = typeof input.tokens === 'number' && Number.isFinite(input.tokens) && input.tokens > 0
|
|
202
|
-
? input.tokens
|
|
203
|
-
: typeof input.contextTokens === 'number' && Number.isFinite(input.contextTokens) && input.contextTokens > 0
|
|
204
|
-
? input.contextTokens
|
|
205
|
-
: context.defaults.defaultContextTokens;
|
|
206
|
-
const contextArgs = {
|
|
207
|
-
vault: context.vault,
|
|
208
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
209
|
-
query: queryFromInput,
|
|
210
|
-
mode,
|
|
211
|
-
strategy,
|
|
212
|
-
limit,
|
|
213
|
-
tokens
|
|
214
|
-
};
|
|
215
|
-
const nextActions = [
|
|
216
|
-
{
|
|
217
|
-
tool: 'brainlink_context',
|
|
218
|
-
reason: 'Context must be loaded first so Brainlink is the primary retrieval source before other read tools.',
|
|
219
|
-
args: contextArgs
|
|
220
|
-
}
|
|
221
|
-
];
|
|
222
|
-
return {
|
|
223
|
-
preflight: preflightResult(withNextActions({
|
|
224
|
-
vault: context.vault,
|
|
225
|
-
agent: context.agent,
|
|
226
|
-
blockedTool: toolName,
|
|
227
|
-
policy,
|
|
228
|
-
contextStatus: status,
|
|
229
|
-
guidance: 'Run brainlink_context first for this vault/agent before other read tools so answers are grounded on Brainlink context.',
|
|
230
|
-
contextArgs
|
|
231
|
-
}, nextActions))
|
|
232
|
-
};
|
|
233
|
-
};
|
|
234
|
-
export const contextInputSchema = {
|
|
235
|
-
...vaultInput,
|
|
236
|
-
...agentInput,
|
|
237
|
-
...searchModeInput,
|
|
238
|
-
...contextStrategyInput,
|
|
239
|
-
query: z.string().min(1).describe('Task or question to retrieve Brainlink context for.'),
|
|
240
|
-
limit: optionalPositiveInteger().describe('Maximum search results before context selection.'),
|
|
241
|
-
tokens: optionalPositiveInteger().describe('Maximum estimated context tokens.')
|
|
242
|
-
};
|
|
243
|
-
export const contextPacksInputSchema = {
|
|
244
|
-
...vaultInput,
|
|
245
|
-
...agentInput,
|
|
246
|
-
action: z.enum(['list', 'clear']).optional().default('list').describe('Action to perform on persisted CAG context packs.'),
|
|
247
|
-
staleOnly: z.boolean().optional().default(false).describe('When clearing, remove only packs stale for the current index and volatile-memory signature.')
|
|
248
|
-
};
|
|
249
|
-
export const searchInputSchema = {
|
|
250
|
-
...vaultInput,
|
|
251
|
-
...agentInput,
|
|
252
|
-
...searchModeInput,
|
|
253
|
-
query: z.string().min(1).describe('Search query.'),
|
|
254
|
-
limit: optionalPositiveInteger().describe('Maximum result count.')
|
|
255
|
-
};
|
|
256
|
-
export const explainInputSchema = {
|
|
257
|
-
...vaultInput,
|
|
258
|
-
...agentInput,
|
|
259
|
-
...searchModeInput,
|
|
260
|
-
query: z.string().min(1).describe('Search query to explain.'),
|
|
261
|
-
limit: optionalPositiveInteger().describe('Maximum result count.')
|
|
262
|
-
};
|
|
263
|
-
export const addNoteInputSchema = {
|
|
264
|
-
...vaultInput,
|
|
265
|
-
title: z.string().min(1).describe('Markdown note title.'),
|
|
266
|
-
content: z
|
|
267
|
-
.string()
|
|
268
|
-
.min(1)
|
|
269
|
-
.describe('Durable Markdown memory. Include explicit [[wiki links]] and #tags when the memory should be connected. Put priority markers near important links, for example priority: high, #important or #critical.'),
|
|
270
|
-
...agentInput,
|
|
271
|
-
allowSensitive: z.boolean().optional().default(false).describe('Allow content that looks like a secret.'),
|
|
272
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after writing note.'),
|
|
273
|
-
autoContextLinks: z
|
|
274
|
-
.boolean()
|
|
275
|
-
.optional()
|
|
276
|
-
.describe('Automatically add canonical Context Links to the inferred visual context hub. Defaults to Brainlink config.')
|
|
277
|
-
};
|
|
278
|
-
export const rememberInputSchema = {
|
|
279
|
-
...vaultInput,
|
|
280
|
-
...agentInput,
|
|
281
|
-
title: z.string().min(1).optional().describe('Optional note title. When omitted, Brainlink infers it from content.'),
|
|
282
|
-
content: z.string().min(1).describe('Memory content to capture as a durable Markdown note.'),
|
|
283
|
-
tags: z.array(z.string()).optional().default([]).describe('Extra tags to include.'),
|
|
284
|
-
links: z.array(z.string()).optional().default([]).describe('Explicit Context Links to include.'),
|
|
285
|
-
linkLimit: positiveInteger(5).describe('Maximum suggested Context Links to include.'),
|
|
286
|
-
dryRun: z.boolean().optional().default(false).describe('Preview inferred note without writing it.'),
|
|
287
|
-
allowSensitive: z.boolean().optional().default(false).describe('Allow content that looks like a secret.'),
|
|
288
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after writing note.')
|
|
289
|
-
};
|
|
290
|
-
export const inboxAddInputSchema = {
|
|
291
|
-
...vaultInput,
|
|
292
|
-
...agentInput,
|
|
293
|
-
content: z.string().min(1).describe('Quick memory content to store as an untriaged inbox note.'),
|
|
294
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after writing inbox item.')
|
|
295
|
-
};
|
|
296
|
-
export const inboxListInputSchema = {
|
|
297
|
-
...vaultInput,
|
|
298
|
-
...agentInput,
|
|
299
|
-
limit: positiveInteger(20).describe('Maximum inbox items to return.')
|
|
300
|
-
};
|
|
301
|
-
export const inboxProcessInputSchema = {
|
|
302
|
-
...vaultInput,
|
|
303
|
-
...agentInput,
|
|
304
|
-
limit: positiveInteger(10).describe('Maximum inbox items to inspect.')
|
|
305
|
-
};
|
|
306
|
-
export const deleteNoteInputSchema = {
|
|
307
|
-
...vaultInput,
|
|
308
|
-
...agentInput,
|
|
309
|
-
title: z.string().min(1).optional().describe('Note title to delete. Use agent to disambiguate namespaced notes.'),
|
|
310
|
-
path: z.string().min(1).optional().describe('Vault-relative or absolute Markdown note path to delete.'),
|
|
311
|
-
confirm: z.boolean().describe('Must be true to confirm deletion.'),
|
|
312
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after deletion. Defaults to true.')
|
|
313
|
-
};
|
|
314
|
-
export const volatileAddInputSchema = {
|
|
315
|
-
...vaultInput,
|
|
316
|
-
...agentInput,
|
|
317
|
-
content: z
|
|
318
|
-
.string()
|
|
319
|
-
.min(1)
|
|
320
|
-
.describe('Temporary agent-decided memory. Use for current task state, hypotheses, transient user preferences and unconfirmed findings.'),
|
|
321
|
-
ttlMinutes: optionalPositiveInteger().describe('Minutes before this volatile memory expires. Defaults to 240.'),
|
|
322
|
-
tags: z.array(z.string()).optional().default([]).describe('Optional tags for volatile retrieval.')
|
|
323
|
-
};
|
|
324
|
-
export const volatileClearInputSchema = {
|
|
325
|
-
...vaultInput,
|
|
326
|
-
...agentInput
|
|
327
|
-
};
|
|
328
|
-
export const addFileInputSchema = {
|
|
329
|
-
...vaultInput,
|
|
330
|
-
...agentInput,
|
|
331
|
-
title: z.string().min(1).optional().describe('Optional note title override. If omitted, uses file name.'),
|
|
332
|
-
filePath: z.string().min(1).describe('Filesystem path to markdown or text file to ingest.'),
|
|
333
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after ingesting file.'),
|
|
334
|
-
allowSensitive: z.boolean().optional().default(false).describe('Allow content that looks like a secret.')
|
|
335
|
-
};
|
|
336
|
-
export const canonicalizeContextLinksInputSchema = {
|
|
337
|
-
...vaultInput,
|
|
338
|
-
...agentInput,
|
|
339
|
-
dryRun: z.boolean().optional().default(false).describe('Preview canonical context-link writes without changing Markdown.'),
|
|
340
|
-
createHubs: z.boolean().optional().default(true).describe('Create missing context hub notes when needed.'),
|
|
341
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex after canonicalization when files changed.')
|
|
342
|
-
};
|
|
343
|
-
export const indexInputSchema = {
|
|
344
|
-
...vaultInput,
|
|
345
|
-
full: z
|
|
346
|
-
.boolean()
|
|
347
|
-
.optional()
|
|
348
|
-
.default(false)
|
|
349
|
-
.describe('Force a complete reindex from Markdown source without reusing unchanged index entries.')
|
|
350
|
-
};
|
|
351
|
-
export const validateInputSchema = {
|
|
352
|
-
...vaultInput,
|
|
353
|
-
...agentInput
|
|
354
|
-
};
|
|
355
|
-
export const doctorActionsInputSchema = {
|
|
356
|
-
...vaultInput,
|
|
357
|
-
...agentInput
|
|
358
|
-
};
|
|
359
|
-
export const graphInputSchema = {
|
|
360
|
-
...vaultInput,
|
|
361
|
-
...agentInput
|
|
362
|
-
};
|
|
363
|
-
export const graphContextsInputSchema = {
|
|
364
|
-
...vaultInput,
|
|
365
|
-
...agentInput
|
|
366
|
-
};
|
|
367
|
-
export const brokenLinksInputSchema = {
|
|
368
|
-
...vaultInput,
|
|
369
|
-
...agentInput
|
|
370
|
-
};
|
|
371
|
-
export const suggestLinksInputSchema = {
|
|
372
|
-
...vaultInput,
|
|
373
|
-
...agentInput,
|
|
374
|
-
content: z.string().min(1).optional().describe('Content to inspect for Context Link suggestions. Required unless broken=true.'),
|
|
375
|
-
broken: z.boolean().optional().default(false).describe('Suggest fixes for unresolved wiki links instead of content links.'),
|
|
376
|
-
limit: positiveInteger(5).describe('Maximum suggestions to return.')
|
|
377
|
-
};
|
|
378
|
-
export const repairLinksInputSchema = {
|
|
379
|
-
...vaultInput,
|
|
380
|
-
...agentInput,
|
|
381
|
-
dryRun: z.boolean().optional().default(false).describe('Preview repairs without writing files.'),
|
|
382
|
-
createMissing: z.boolean().optional().default(true).describe('Create placeholder notes for unresolved targets without a safe existing match.'),
|
|
383
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after repairs.'),
|
|
384
|
-
minScore: z.number().min(0).max(1).optional().default(0.88).describe('Minimum similarity score for automatic retargeting.'),
|
|
385
|
-
margin: z.number().min(0).max(1).optional().default(0.12).describe('Minimum score gap between first and second candidate.')
|
|
386
|
-
};
|
|
387
|
-
export const orphansInputSchema = {
|
|
388
|
-
...vaultInput,
|
|
389
|
-
...agentInput
|
|
390
|
-
};
|
|
391
|
-
export const statsInputSchema = {
|
|
392
|
-
...vaultInput,
|
|
393
|
-
...agentInput
|
|
394
|
-
};
|
|
395
|
-
export const syncInputSchema = {
|
|
396
|
-
...vaultInput,
|
|
397
|
-
...agentInput,
|
|
398
|
-
contextQuery: z.string().min(1).optional().describe('Optional context smoke query. Omit to skip context probe.'),
|
|
399
|
-
mode: z.enum(['fts', 'semantic', 'hybrid']).optional().describe('Search mode for the optional context probe. Defaults to config value.'),
|
|
400
|
-
strategy: z.enum(['rag', 'cag', 'auto']).optional().describe('Context strategy for the optional context probe. Defaults to the Brainlink config value.'),
|
|
401
|
-
contextLimit: optionalPositiveInteger().describe('Context smoke result limit when contextQuery is provided.'),
|
|
402
|
-
contextTokens: optionalPositiveInteger().describe('Context smoke token target when contextQuery is provided.')
|
|
403
|
-
};
|
|
404
|
-
export const bootstrapInputSchema = {
|
|
405
|
-
...vaultInput,
|
|
406
|
-
...agentInput,
|
|
407
|
-
...searchModeInput,
|
|
408
|
-
...contextStrategyInput,
|
|
409
|
-
query: z
|
|
410
|
-
.string()
|
|
411
|
-
.min(1)
|
|
412
|
-
.optional()
|
|
413
|
-
.describe('Optional task query. When provided, Brainlink also returns a context package in the same call.'),
|
|
414
|
-
limit: optionalPositiveInteger().describe('Context limit used when query is provided.'),
|
|
415
|
-
tokens: optionalPositiveInteger().describe('Context token target used when query is provided.')
|
|
416
|
-
};
|
|
417
|
-
export const policyInputSchema = {
|
|
418
|
-
...vaultInput,
|
|
419
|
-
...agentInput,
|
|
420
|
-
preset: z.enum(['fully-auto', 'strict']).optional().describe('Apply an opinionated policy preset before explicit overrides.'),
|
|
421
|
-
enforceBootstrap: z.boolean().optional().describe('Enable or disable bootstrap enforcement for MCP read tools.'),
|
|
422
|
-
enforceContextFirst: z.boolean().optional().describe('Require brainlink_context before other MCP read tools.'),
|
|
423
|
-
autoBootstrapOnRead: z
|
|
424
|
-
.boolean()
|
|
425
|
-
.optional()
|
|
426
|
-
.describe('When bootstrap is missing/stale, run automatic bootstrap on read tools instead of returning preflight-required responses.'),
|
|
427
|
-
autoBootstrapOnStartup: z
|
|
428
|
-
.boolean()
|
|
429
|
-
.optional()
|
|
430
|
-
.describe('Run automatic bootstrap during MCP server startup using configured default vault/agent.'),
|
|
431
|
-
staleAfterMinutes: positiveInteger(120).describe('Bootstrap freshness window in minutes before read tools require a new bootstrap.')
|
|
432
|
-
};
|
|
433
|
-
export const versionInputSchema = {
|
|
434
|
-
...vaultInput,
|
|
435
|
-
...agentInput
|
|
436
|
-
};
|
|
437
|
-
export const sessionCloseInputSchema = {
|
|
438
|
-
...vaultInput,
|
|
439
|
-
...agentInput,
|
|
440
|
-
content: z.string().min(1).optional().describe('Optional extra session notes to include in the handoff.'),
|
|
441
|
-
cwd: z.string().min(1).optional().describe('Workspace path used for git status. Defaults to current process working directory.'),
|
|
442
|
-
dryRun: z.boolean().optional().default(false).describe('Preview handoff note without writing it.'),
|
|
443
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex vault after writing handoff.')
|
|
444
|
-
};
|
|
445
|
-
export const projectInitInputSchema = {
|
|
446
|
-
...vaultInput,
|
|
447
|
-
...agentInput,
|
|
448
|
-
projectPath: z.string().min(1).optional().describe('Project path to inspect. Defaults to current process working directory.')
|
|
449
|
-
};
|
|
450
|
-
export const recommendationsInputSchema = {
|
|
451
|
-
...vaultInput,
|
|
452
|
-
...agentInput,
|
|
453
|
-
...searchModeInput,
|
|
454
|
-
...contextStrategyInput,
|
|
455
|
-
query: z.string().min(1).optional().describe('Optional current task query to generate context-focused recommendations.'),
|
|
456
|
-
limit: optionalPositiveInteger().describe('Optional context limit override for generated recommendations.'),
|
|
457
|
-
tokens: optionalPositiveInteger().describe('Optional context token budget override for generated recommendations.')
|
|
458
|
-
};
|
|
459
|
-
export const dedupeInputSchema = {
|
|
460
|
-
...vaultInput,
|
|
461
|
-
...agentInput,
|
|
462
|
-
limit: optionalPositiveInteger().describe('Maximum duplicate candidate pairs to return.'),
|
|
463
|
-
minScore: z.number().min(0).max(1).optional().describe('Minimum semantic similarity score between 0 and 1.'),
|
|
464
|
-
semantic: z.boolean().optional().default(true).describe('Enable semantic duplicate detection in addition to exact content hash matches.')
|
|
465
|
-
};
|
|
466
|
-
export const dedupeResolveInputSchema = {
|
|
467
|
-
...vaultInput,
|
|
468
|
-
leftPath: z.string().min(1).describe('Left note path from dedupe results.'),
|
|
469
|
-
rightPath: z.string().min(1).describe('Right note path from dedupe results.'),
|
|
470
|
-
action: z.enum(['merge', 'link', 'ignore']).describe('Resolution action.'),
|
|
471
|
-
autoIndex: z.boolean().optional().default(true).describe('Reindex after duplicate resolution.')
|
|
472
|
-
};
|
|
473
|
-
export const contextTool = async (input) => {
|
|
474
|
-
const context = await resolveExecutionContext(input);
|
|
475
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_context');
|
|
476
|
-
if (readiness.preflight) {
|
|
477
|
-
return readiness.preflight;
|
|
478
|
-
}
|
|
479
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
480
|
-
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
481
|
-
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
482
|
-
const tokens = input.tokens ?? context.defaults.defaultContextTokens;
|
|
483
|
-
const contextPackage = await buildContextPackage(context.vault, input.query, limit, tokens, context.agent, mode, strategy, context.defaults.defaultContextCacheTtlMs);
|
|
484
|
-
const contextSession = await touchContextSession(context.vault, context.agent);
|
|
485
|
-
return jsonResult({
|
|
486
|
-
vault: context.vault,
|
|
487
|
-
agent: context.agent,
|
|
488
|
-
mode,
|
|
489
|
-
strategy,
|
|
490
|
-
limit,
|
|
491
|
-
tokens,
|
|
492
|
-
contextSession,
|
|
493
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
494
|
-
...contextPackage
|
|
495
|
-
});
|
|
496
|
-
};
|
|
497
|
-
export const contextPacksTool = async (input) => {
|
|
498
|
-
const context = await resolveExecutionContext(input);
|
|
499
|
-
const dataSignature = await readContextDataSignature(context.vault);
|
|
500
|
-
if (input.action === 'clear') {
|
|
501
|
-
const result = await clearContextPacks(context.vault, {
|
|
502
|
-
staleOnly: input.staleOnly === true,
|
|
503
|
-
dataSignature
|
|
504
|
-
});
|
|
505
|
-
return jsonResult({
|
|
506
|
-
vault: context.vault,
|
|
507
|
-
agent: context.agent,
|
|
508
|
-
dataSignature,
|
|
509
|
-
action: 'clear',
|
|
510
|
-
staleOnly: input.staleOnly === true,
|
|
511
|
-
...result
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
const packs = await listContextPacks(context.vault, dataSignature);
|
|
515
|
-
return jsonResult({
|
|
516
|
-
vault: context.vault,
|
|
517
|
-
agent: context.agent,
|
|
518
|
-
dataSignature,
|
|
519
|
-
action: 'list',
|
|
520
|
-
packs
|
|
521
|
-
});
|
|
522
|
-
};
|
|
523
|
-
export const searchTool = async (input) => {
|
|
524
|
-
const context = await resolveExecutionContext(input);
|
|
525
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_search');
|
|
526
|
-
if (readiness.preflight) {
|
|
527
|
-
return readiness.preflight;
|
|
528
|
-
}
|
|
529
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_search');
|
|
530
|
-
if (contextReadiness.preflight) {
|
|
531
|
-
return contextReadiness.preflight;
|
|
532
|
-
}
|
|
533
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
534
|
-
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
535
|
-
const results = await searchKnowledge(context.vault, input.query, limit, context.agent, mode);
|
|
536
|
-
return jsonResult({
|
|
537
|
-
vault: context.vault,
|
|
538
|
-
agent: context.agent,
|
|
539
|
-
query: input.query,
|
|
540
|
-
limit,
|
|
541
|
-
mode,
|
|
542
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
543
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
544
|
-
results
|
|
545
|
-
});
|
|
546
|
-
};
|
|
547
|
-
export const explainTool = async (input) => {
|
|
548
|
-
const context = await resolveExecutionContext(input);
|
|
549
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_explain');
|
|
550
|
-
if (readiness.preflight) {
|
|
551
|
-
return readiness.preflight;
|
|
552
|
-
}
|
|
553
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_explain');
|
|
554
|
-
if (contextReadiness.preflight) {
|
|
555
|
-
return contextReadiness.preflight;
|
|
556
|
-
}
|
|
557
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
558
|
-
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
559
|
-
const results = await explainSearchResults(context.vault, input.query, limit, context.agent, mode);
|
|
560
|
-
return jsonResult({
|
|
561
|
-
vault: context.vault,
|
|
562
|
-
agent: context.agent,
|
|
563
|
-
query: input.query,
|
|
564
|
-
limit,
|
|
565
|
-
mode,
|
|
566
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
567
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
568
|
-
results
|
|
569
|
-
});
|
|
570
|
-
};
|
|
571
|
-
export const addNoteTool = async (input) => {
|
|
572
|
-
const context = await resolveExecutionContext(input);
|
|
573
|
-
const shouldIndex = isTruthy(input.autoIndex);
|
|
574
|
-
const added = await addNoteWithMetadata(context.vault, input.title, input.content, context.agent, {
|
|
575
|
-
allowSensitive: input.allowSensitive,
|
|
576
|
-
autoContextLinks: input.autoContextLinks ?? context.config.autoCanonicalContextLinks
|
|
577
|
-
});
|
|
578
|
-
const index = shouldIndex ? await indexVault(context.vault) : undefined;
|
|
579
|
-
const focusPath = added.path.includes('agents/') ? added.path.slice(added.path.indexOf('agents/')).replaceAll('\\', '/') : undefined;
|
|
580
|
-
const possibleDuplicates = await scanDuplicateNotes(context.vault, {
|
|
581
|
-
agentId: context.agent,
|
|
582
|
-
focusPath,
|
|
583
|
-
limit: 5,
|
|
584
|
-
minSemanticScore: 0.92,
|
|
585
|
-
includeSemantic: true
|
|
586
|
-
});
|
|
587
|
-
return jsonResult({
|
|
588
|
-
vault: context.vault,
|
|
589
|
-
title: input.title,
|
|
590
|
-
agent: context.agent,
|
|
591
|
-
path: added.path,
|
|
592
|
-
writeConnectivity: {
|
|
593
|
-
autoLinked: added.autoLinked,
|
|
594
|
-
linkTarget: added.linkTarget,
|
|
595
|
-
context: added.context,
|
|
596
|
-
hubCreated: added.hubCreated,
|
|
597
|
-
guaranteedEdge: added.autoLinked
|
|
598
|
-
},
|
|
599
|
-
possibleDuplicates,
|
|
600
|
-
...(index ? { index } : {})
|
|
601
|
-
});
|
|
602
|
-
};
|
|
603
|
-
export const rememberTool = async (input) => {
|
|
604
|
-
const context = await resolveExecutionContext(input);
|
|
605
|
-
const suggestion = await buildRememberSuggestion({
|
|
606
|
-
vaultPath: context.vault,
|
|
607
|
-
content: input.content,
|
|
608
|
-
agentId: context.agent,
|
|
609
|
-
title: input.title,
|
|
610
|
-
tags: input.tags,
|
|
611
|
-
links: input.links,
|
|
612
|
-
linkLimit: input.linkLimit
|
|
613
|
-
});
|
|
614
|
-
if (input.dryRun) {
|
|
615
|
-
return jsonResult({
|
|
616
|
-
dryRun: true,
|
|
617
|
-
vault: context.vault,
|
|
618
|
-
agent: context.agent,
|
|
619
|
-
suggestion
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
const added = await addNoteWithMetadata(context.vault, suggestion.title, suggestion.content, context.agent, {
|
|
623
|
-
allowSensitive: input.allowSensitive,
|
|
624
|
-
autoContextLinks: false
|
|
625
|
-
});
|
|
626
|
-
const index = input.autoIndex ? await indexVault(context.vault) : undefined;
|
|
627
|
-
return jsonResult({
|
|
628
|
-
dryRun: false,
|
|
629
|
-
vault: context.vault,
|
|
630
|
-
agent: context.agent,
|
|
631
|
-
suggestion,
|
|
632
|
-
path: added.path,
|
|
633
|
-
...(index ? { index } : {})
|
|
634
|
-
});
|
|
635
|
-
};
|
|
636
|
-
export const inboxAddTool = async (input) => {
|
|
637
|
-
const context = await resolveExecutionContext(input);
|
|
638
|
-
const result = await addInboxItem({
|
|
639
|
-
vaultPath: context.vault,
|
|
640
|
-
content: input.content,
|
|
641
|
-
agentId: context.agent,
|
|
642
|
-
autoIndex: input.autoIndex
|
|
643
|
-
});
|
|
644
|
-
return jsonResult({
|
|
645
|
-
vault: context.vault,
|
|
646
|
-
agent: context.agent,
|
|
647
|
-
...result
|
|
648
|
-
});
|
|
649
|
-
};
|
|
650
|
-
export const inboxListTool = async (input) => {
|
|
651
|
-
const context = await resolveExecutionContext(input);
|
|
652
|
-
const items = await listInboxItems(context.vault, input.limit);
|
|
653
|
-
return jsonResult({
|
|
654
|
-
vault: context.vault,
|
|
655
|
-
agent: context.agent,
|
|
656
|
-
items
|
|
657
|
-
});
|
|
658
|
-
};
|
|
659
|
-
export const inboxProcessTool = async (input) => {
|
|
660
|
-
const context = await resolveExecutionContext(input);
|
|
661
|
-
const items = await processInboxItems({
|
|
662
|
-
vaultPath: context.vault,
|
|
663
|
-
agentId: context.agent,
|
|
664
|
-
limit: input.limit
|
|
665
|
-
});
|
|
666
|
-
return jsonResult({
|
|
667
|
-
vault: context.vault,
|
|
668
|
-
agent: context.agent,
|
|
669
|
-
items
|
|
670
|
-
});
|
|
671
|
-
};
|
|
672
|
-
export const deleteNoteTool = async (input) => {
|
|
673
|
-
const context = await resolveExecutionContext(input);
|
|
674
|
-
const result = await deleteNote(context.vault, {
|
|
675
|
-
title: input.title,
|
|
676
|
-
path: input.path,
|
|
677
|
-
agentId: context.agent,
|
|
678
|
-
confirm: input.confirm,
|
|
679
|
-
autoIndex: input.autoIndex
|
|
680
|
-
});
|
|
681
|
-
return jsonResult({
|
|
682
|
-
vault: context.vault,
|
|
683
|
-
...result
|
|
684
|
-
});
|
|
685
|
-
};
|
|
686
|
-
export const volatileAddTool = async (input) => {
|
|
687
|
-
const context = await resolveExecutionContext(input);
|
|
688
|
-
const entry = await addVolatileMemory(context.vault, input.content, context.agent ?? 'shared', input.ttlMinutes ?? 240, input.tags);
|
|
689
|
-
return jsonResult({
|
|
690
|
-
vault: context.vault,
|
|
691
|
-
agent: context.agent,
|
|
692
|
-
volatile: true,
|
|
693
|
-
entry
|
|
694
|
-
});
|
|
695
|
-
};
|
|
696
|
-
export const volatileClearTool = async (input) => {
|
|
697
|
-
const context = await resolveExecutionContext(input);
|
|
698
|
-
const cleared = await clearVolatileMemory(context.vault, context.agent);
|
|
699
|
-
return jsonResult({
|
|
700
|
-
vault: context.vault,
|
|
701
|
-
agent: context.agent,
|
|
702
|
-
cleared
|
|
703
|
-
});
|
|
704
|
-
};
|
|
705
|
-
export const addFileTool = async (input) => {
|
|
706
|
-
const context = await resolveExecutionContext(input);
|
|
707
|
-
const content = await readFile(input.filePath, 'utf8');
|
|
708
|
-
const inferredTitle = inferTitleFromPath(input.filePath);
|
|
709
|
-
const title = input.title ?? inferredTitle;
|
|
710
|
-
if (title == null || title.length === 0) {
|
|
711
|
-
throw new Error('Cannot infer note title from file path. Provide a title explicitly.');
|
|
712
|
-
}
|
|
713
|
-
const shouldIndex = isTruthy(input.autoIndex);
|
|
714
|
-
const added = await addNoteWithMetadata(context.vault, title, content, context.agent, {
|
|
715
|
-
allowSensitive: input.allowSensitive,
|
|
716
|
-
autoContextLinks: context.config.autoCanonicalContextLinks
|
|
717
|
-
});
|
|
718
|
-
const index = shouldIndex ? await indexVault(context.vault) : undefined;
|
|
719
|
-
return jsonResult({
|
|
720
|
-
vault: context.vault,
|
|
721
|
-
title,
|
|
722
|
-
agent: context.agent,
|
|
723
|
-
filePath: input.filePath,
|
|
724
|
-
path: added.path,
|
|
725
|
-
writeConnectivity: {
|
|
726
|
-
autoLinked: added.autoLinked,
|
|
727
|
-
linkTarget: added.linkTarget,
|
|
728
|
-
context: added.context,
|
|
729
|
-
hubCreated: added.hubCreated,
|
|
730
|
-
guaranteedEdge: added.autoLinked
|
|
731
|
-
},
|
|
732
|
-
...(index ? { index } : {})
|
|
733
|
-
});
|
|
734
|
-
};
|
|
735
|
-
export const canonicalizeContextLinksTool = async (input) => {
|
|
736
|
-
const context = await resolveExecutionContext(input);
|
|
737
|
-
const result = await canonicalizeContextLinks(context.vault, {
|
|
738
|
-
agentId: context.agent,
|
|
739
|
-
dryRun: input.dryRun === true,
|
|
740
|
-
createMissingHubs: input.createHubs !== false
|
|
741
|
-
});
|
|
742
|
-
const index = input.autoIndex !== false && !result.dryRun && result.changed > 0
|
|
743
|
-
? await indexVault(context.vault, { full: true })
|
|
744
|
-
: undefined;
|
|
745
|
-
return jsonResult({
|
|
746
|
-
vault: context.vault,
|
|
747
|
-
agent: context.agent,
|
|
748
|
-
...result,
|
|
749
|
-
...(index ? { index } : {})
|
|
750
|
-
});
|
|
751
|
-
};
|
|
752
|
-
export const indexTool = async (input) => {
|
|
753
|
-
const context = await resolveExecutionContext(input);
|
|
754
|
-
const result = await indexVault(context.vault, {
|
|
755
|
-
full: input.full === true
|
|
756
|
-
});
|
|
757
|
-
return jsonResult({
|
|
758
|
-
vault: context.vault,
|
|
759
|
-
...result
|
|
760
|
-
});
|
|
761
|
-
};
|
|
762
|
-
export const validateTool = async (input) => {
|
|
763
|
-
const context = await resolveExecutionContext(input);
|
|
764
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_validate');
|
|
765
|
-
if (readiness.preflight) {
|
|
766
|
-
return readiness.preflight;
|
|
767
|
-
}
|
|
768
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_validate');
|
|
769
|
-
if (contextReadiness.preflight) {
|
|
770
|
-
return contextReadiness.preflight;
|
|
771
|
-
}
|
|
772
|
-
const validation = await validateVault(context.vault, context.agent);
|
|
773
|
-
return jsonResult({
|
|
774
|
-
vault: context.vault,
|
|
775
|
-
agent: context.agent,
|
|
776
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
777
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
778
|
-
...validation
|
|
779
|
-
});
|
|
780
|
-
};
|
|
781
|
-
export const doctorActionsTool = async (input) => {
|
|
782
|
-
const context = await resolveExecutionContext(input);
|
|
783
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_doctor_actions');
|
|
784
|
-
if (readiness.preflight) {
|
|
785
|
-
return readiness.preflight;
|
|
786
|
-
}
|
|
787
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_doctor_actions');
|
|
788
|
-
if (contextReadiness.preflight) {
|
|
789
|
-
return contextReadiness.preflight;
|
|
790
|
-
}
|
|
791
|
-
const report = await buildActionableDoctor(context.vault);
|
|
792
|
-
return jsonResult({
|
|
793
|
-
vault: context.vault,
|
|
794
|
-
agent: context.agent,
|
|
795
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
796
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
797
|
-
...report
|
|
798
|
-
});
|
|
799
|
-
};
|
|
800
|
-
export const graphTool = async (input) => {
|
|
801
|
-
const context = await resolveExecutionContext(input);
|
|
802
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_graph');
|
|
803
|
-
if (readiness.preflight) {
|
|
804
|
-
return readiness.preflight;
|
|
805
|
-
}
|
|
806
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_graph');
|
|
807
|
-
if (contextReadiness.preflight) {
|
|
808
|
-
return contextReadiness.preflight;
|
|
809
|
-
}
|
|
810
|
-
const graph = await getGraph(context.vault, context.agent);
|
|
811
|
-
return jsonResult({
|
|
812
|
-
vault: context.vault,
|
|
813
|
-
agent: context.agent,
|
|
814
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
815
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
816
|
-
...graph
|
|
817
|
-
});
|
|
818
|
-
};
|
|
819
|
-
export const graphContextsTool = async (input) => {
|
|
820
|
-
const context = await resolveExecutionContext(input);
|
|
821
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_graph_contexts');
|
|
822
|
-
if (readiness.preflight) {
|
|
823
|
-
return readiness.preflight;
|
|
824
|
-
}
|
|
825
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_graph_contexts');
|
|
826
|
-
if (contextReadiness.preflight) {
|
|
827
|
-
return contextReadiness.preflight;
|
|
828
|
-
}
|
|
829
|
-
const contexts = await getGraphContexts(context.vault, context.agent);
|
|
830
|
-
return jsonResult({
|
|
831
|
-
vault: context.vault,
|
|
832
|
-
agent: context.agent,
|
|
833
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
834
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
835
|
-
contexts
|
|
836
|
-
});
|
|
837
|
-
};
|
|
838
|
-
export const brokenLinksTool = async (input) => {
|
|
839
|
-
const context = await resolveExecutionContext(input);
|
|
840
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_broken_links');
|
|
841
|
-
if (readiness.preflight) {
|
|
842
|
-
return readiness.preflight;
|
|
843
|
-
}
|
|
844
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_broken_links');
|
|
845
|
-
if (contextReadiness.preflight) {
|
|
846
|
-
return contextReadiness.preflight;
|
|
847
|
-
}
|
|
848
|
-
const brokenLinks = await getBrokenLinksReport(context.vault, context.agent);
|
|
849
|
-
return jsonResult({
|
|
850
|
-
vault: context.vault,
|
|
851
|
-
agent: context.agent,
|
|
852
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
853
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
854
|
-
brokenLinks
|
|
855
|
-
});
|
|
856
|
-
};
|
|
857
|
-
export const suggestLinksTool = async (input) => {
|
|
858
|
-
const context = await resolveExecutionContext(input);
|
|
859
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_suggest_links');
|
|
860
|
-
if (readiness.preflight) {
|
|
861
|
-
return readiness.preflight;
|
|
862
|
-
}
|
|
863
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_suggest_links');
|
|
864
|
-
if (contextReadiness.preflight) {
|
|
865
|
-
return contextReadiness.preflight;
|
|
866
|
-
}
|
|
867
|
-
if (input.broken) {
|
|
868
|
-
const suggestions = await suggestBrokenLinkFixes(context.vault, context.agent, input.limit);
|
|
869
|
-
return jsonResult({
|
|
870
|
-
vault: context.vault,
|
|
871
|
-
agent: context.agent,
|
|
872
|
-
mode: 'broken-links',
|
|
873
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
874
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
875
|
-
suggestions
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
if (!input.content || input.content.trim().length === 0) {
|
|
879
|
-
throw new Error('content is required when broken=false.');
|
|
880
|
-
}
|
|
881
|
-
const suggestions = await suggestContextLinks(context.vault, input.content, context.agent, input.limit);
|
|
882
|
-
return jsonResult({
|
|
883
|
-
vault: context.vault,
|
|
884
|
-
agent: context.agent,
|
|
885
|
-
mode: 'content',
|
|
886
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
887
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
888
|
-
suggestions
|
|
889
|
-
});
|
|
890
|
-
};
|
|
891
|
-
export const repairLinksTool = async (input) => {
|
|
892
|
-
const context = await resolveExecutionContext(input);
|
|
893
|
-
const result = await repairBrokenLinks(context.vault, {
|
|
894
|
-
agentId: context.agent,
|
|
895
|
-
dryRun: input.dryRun,
|
|
896
|
-
createMissing: input.createMissing,
|
|
897
|
-
autoIndex: input.autoIndex,
|
|
898
|
-
minScore: input.minScore,
|
|
899
|
-
margin: input.margin
|
|
900
|
-
});
|
|
901
|
-
return jsonResult({
|
|
902
|
-
vault: context.vault,
|
|
903
|
-
agent: context.agent,
|
|
904
|
-
...result
|
|
905
|
-
});
|
|
906
|
-
};
|
|
907
|
-
export const orphansTool = async (input) => {
|
|
908
|
-
const context = await resolveExecutionContext(input);
|
|
909
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_orphans');
|
|
910
|
-
if (readiness.preflight) {
|
|
911
|
-
return readiness.preflight;
|
|
912
|
-
}
|
|
913
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_orphans');
|
|
914
|
-
if (contextReadiness.preflight) {
|
|
915
|
-
return contextReadiness.preflight;
|
|
916
|
-
}
|
|
917
|
-
const orphans = await getOrphansReport(context.vault, context.agent);
|
|
918
|
-
return jsonResult({
|
|
919
|
-
vault: context.vault,
|
|
920
|
-
agent: context.agent,
|
|
921
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
922
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
923
|
-
orphans
|
|
924
|
-
});
|
|
925
|
-
};
|
|
926
|
-
export const statsTool = async (input) => {
|
|
927
|
-
const context = await resolveExecutionContext(input);
|
|
928
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_stats');
|
|
929
|
-
if (readiness.preflight) {
|
|
930
|
-
return readiness.preflight;
|
|
931
|
-
}
|
|
932
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_stats');
|
|
933
|
-
if (contextReadiness.preflight) {
|
|
934
|
-
return contextReadiness.preflight;
|
|
935
|
-
}
|
|
936
|
-
const stats = await getStats(context.vault, context.agent);
|
|
937
|
-
return jsonResult({
|
|
938
|
-
vault: context.vault,
|
|
939
|
-
agent: context.agent,
|
|
940
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
941
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
942
|
-
stats
|
|
943
|
-
});
|
|
944
|
-
};
|
|
945
|
-
export const syncTool = async (input) => {
|
|
946
|
-
const context = await resolveExecutionContext(input);
|
|
947
|
-
const readiness = await ensureBootstrapReady(context, input, 'brainlink_sync');
|
|
948
|
-
if (readiness.preflight) {
|
|
949
|
-
return readiness.preflight;
|
|
950
|
-
}
|
|
951
|
-
const contextReadiness = await ensureContextReady(context, input, 'brainlink_sync');
|
|
952
|
-
if (contextReadiness.preflight) {
|
|
953
|
-
return contextReadiness.preflight;
|
|
954
|
-
}
|
|
955
|
-
const index = await indexVault(context.vault);
|
|
956
|
-
const stats = await getStats(context.vault, context.agent);
|
|
957
|
-
const validation = await validateVault(context.vault, context.agent);
|
|
958
|
-
const brokenLinks = await getBrokenLinksReport(context.vault, context.agent);
|
|
959
|
-
const orphans = await getOrphansReport(context.vault, context.agent);
|
|
960
|
-
const response = {
|
|
961
|
-
vault: context.vault,
|
|
962
|
-
agent: context.agent,
|
|
963
|
-
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
964
|
-
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
965
|
-
index,
|
|
966
|
-
stats,
|
|
967
|
-
validation,
|
|
968
|
-
brokenLinks,
|
|
969
|
-
orphans
|
|
970
|
-
};
|
|
971
|
-
if (!input.contextQuery) {
|
|
972
|
-
return jsonResult(response);
|
|
973
|
-
}
|
|
974
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
975
|
-
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
976
|
-
const contextLimit = input.contextLimit ?? context.defaults.defaultSearchLimit;
|
|
977
|
-
const contextTokens = input.contextTokens ?? context.defaults.defaultContextTokens;
|
|
978
|
-
const contextPackage = await buildContextPackage(context.vault, input.contextQuery, contextLimit, contextTokens, context.agent, mode, strategy, context.defaults.defaultContextCacheTtlMs);
|
|
979
|
-
const contextSession = await touchContextSession(context.vault, context.agent);
|
|
980
|
-
return jsonResult({
|
|
981
|
-
...response,
|
|
982
|
-
context: {
|
|
983
|
-
mode,
|
|
984
|
-
strategy,
|
|
985
|
-
contextSession,
|
|
986
|
-
...contextPackage
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
};
|
|
990
|
-
export const bootstrapTool = async (input) => {
|
|
991
|
-
const context = await resolveExecutionContext(input);
|
|
992
|
-
const index = await indexVault(context.vault);
|
|
993
|
-
const stats = await getStats(context.vault, context.agent);
|
|
994
|
-
const validation = await validateVault(context.vault, context.agent);
|
|
995
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
996
|
-
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
997
|
-
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
998
|
-
const tokens = input.tokens ?? context.defaults.defaultContextTokens;
|
|
999
|
-
const contextPackage = input.query
|
|
1000
|
-
? await buildContextPackage(context.vault, input.query, limit, tokens, context.agent, mode, strategy, context.defaults.defaultContextCacheTtlMs)
|
|
1001
|
-
: undefined;
|
|
1002
|
-
const contextSession = input.query ? await touchContextSession(context.vault, context.agent) : undefined;
|
|
1003
|
-
const guidance = stats.documentCount === 0
|
|
1004
|
-
? 'Vault indexed with zero documents. Add durable notes with brainlink_add_note, then run brainlink_bootstrap again.'
|
|
1005
|
-
: input.query
|
|
1006
|
-
? 'Use returned context as grounding baseline, then write durable updates with brainlink_add_note when needed.'
|
|
1007
|
-
: 'Run brainlink_context with the current task query to retrieve grounded context before answering.';
|
|
1008
|
-
const session = await touchBootstrapSession(context.vault, context.agent);
|
|
1009
|
-
const policy = await getBootstrapPolicy();
|
|
1010
|
-
const nextActions = stats.documentCount === 0
|
|
1011
|
-
? [
|
|
1012
|
-
{
|
|
1013
|
-
tool: 'brainlink_add_note',
|
|
1014
|
-
reason: 'No indexed documents were found. Add durable Markdown memory first.',
|
|
1015
|
-
args: {
|
|
1016
|
-
vault: context.vault,
|
|
1017
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1018
|
-
title: 'Architecture',
|
|
1019
|
-
content: 'Durable memory with explicit [[links]] and #tags.'
|
|
1020
|
-
}
|
|
1021
|
-
},
|
|
1022
|
-
{
|
|
1023
|
-
tool: 'brainlink_bootstrap',
|
|
1024
|
-
reason: 'Re-run bootstrap after writing notes so context tools can work on fresh index state.',
|
|
1025
|
-
args: {
|
|
1026
|
-
vault: context.vault,
|
|
1027
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1028
|
-
mode
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
]
|
|
1032
|
-
: input.query
|
|
1033
|
-
? [
|
|
1034
|
-
{
|
|
1035
|
-
tool: 'brainlink_add_note',
|
|
1036
|
-
reason: 'Persist relevant outcomes from this task as durable memory.',
|
|
1037
|
-
args: {
|
|
1038
|
-
vault: context.vault,
|
|
1039
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1040
|
-
title: 'Task Update',
|
|
1041
|
-
content: 'Summarize durable findings and connect with [[existing notes]].'
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
]
|
|
1045
|
-
: [
|
|
1046
|
-
{
|
|
1047
|
-
tool: 'brainlink_context',
|
|
1048
|
-
reason: 'Fetch grounded context for the current task.',
|
|
1049
|
-
args: {
|
|
1050
|
-
vault: context.vault,
|
|
1051
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1052
|
-
query: '<task>',
|
|
1053
|
-
mode,
|
|
1054
|
-
strategy,
|
|
1055
|
-
limit,
|
|
1056
|
-
tokens
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
];
|
|
1060
|
-
return jsonResult(withNextActions({
|
|
1061
|
-
vault: context.vault,
|
|
1062
|
-
agent: context.agent,
|
|
1063
|
-
mode,
|
|
1064
|
-
strategy,
|
|
1065
|
-
limit,
|
|
1066
|
-
tokens,
|
|
1067
|
-
index,
|
|
1068
|
-
stats,
|
|
1069
|
-
validation,
|
|
1070
|
-
policy,
|
|
1071
|
-
session,
|
|
1072
|
-
guidance,
|
|
1073
|
-
...(contextPackage ? { context: contextPackage } : {}),
|
|
1074
|
-
...(contextSession ? { contextSession } : {})
|
|
1075
|
-
}, nextActions));
|
|
1076
|
-
};
|
|
1077
|
-
export const policyTool = async (input) => {
|
|
1078
|
-
const context = await resolveExecutionContext(input);
|
|
1079
|
-
const presetPatch = input.preset === 'strict'
|
|
1080
|
-
? {
|
|
1081
|
-
enforceBootstrap: true,
|
|
1082
|
-
enforceContextFirst: true,
|
|
1083
|
-
autoBootstrapOnRead: false,
|
|
1084
|
-
autoBootstrapOnStartup: false
|
|
1085
|
-
}
|
|
1086
|
-
: input.preset === 'fully-auto'
|
|
1087
|
-
? {
|
|
1088
|
-
enforceBootstrap: true,
|
|
1089
|
-
enforceContextFirst: true,
|
|
1090
|
-
autoBootstrapOnRead: true,
|
|
1091
|
-
autoBootstrapOnStartup: true
|
|
1092
|
-
}
|
|
1093
|
-
: {};
|
|
1094
|
-
const policy = input.preset !== undefined ||
|
|
1095
|
-
typeof input.enforceBootstrap === 'boolean' ||
|
|
1096
|
-
typeof input.enforceContextFirst === 'boolean' ||
|
|
1097
|
-
typeof input.autoBootstrapOnRead === 'boolean' ||
|
|
1098
|
-
typeof input.autoBootstrapOnStartup === 'boolean' ||
|
|
1099
|
-
typeof input.staleAfterMinutes === 'number'
|
|
1100
|
-
? await setBootstrapPolicy({
|
|
1101
|
-
...presetPatch,
|
|
1102
|
-
...(typeof input.enforceBootstrap === 'boolean' ? { enforceBootstrap: input.enforceBootstrap } : {}),
|
|
1103
|
-
...(typeof input.enforceContextFirst === 'boolean' ? { enforceContextFirst: input.enforceContextFirst } : {}),
|
|
1104
|
-
...(typeof input.autoBootstrapOnRead === 'boolean' ? { autoBootstrapOnRead: input.autoBootstrapOnRead } : {}),
|
|
1105
|
-
...(typeof input.autoBootstrapOnStartup === 'boolean' ? { autoBootstrapOnStartup: input.autoBootstrapOnStartup } : {}),
|
|
1106
|
-
...(typeof input.staleAfterMinutes === 'number' ? { staleAfterMinutes: input.staleAfterMinutes } : {})
|
|
1107
|
-
})
|
|
1108
|
-
: await getBootstrapPolicy();
|
|
1109
|
-
const bootstrapStatus = await getBootstrapSessionStatus(context.vault, context.agent);
|
|
1110
|
-
const contextStatus = await getContextSessionStatus(context.vault, context.agent);
|
|
1111
|
-
const nextActions = bootstrapStatus.ready
|
|
1112
|
-
? []
|
|
1113
|
-
: [
|
|
1114
|
-
{
|
|
1115
|
-
tool: 'brainlink_bootstrap',
|
|
1116
|
-
reason: 'Bootstrap status is not ready. Run bootstrap before using read tools.',
|
|
1117
|
-
args: {
|
|
1118
|
-
vault: context.vault,
|
|
1119
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1120
|
-
mode: context.defaults.defaultSearchMode,
|
|
1121
|
-
strategy: context.defaults.defaultContextStrategy
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
];
|
|
1125
|
-
const withContextAction = policy.enforceContextFirst && !contextStatus.ready
|
|
1126
|
-
? [
|
|
1127
|
-
...nextActions,
|
|
1128
|
-
{
|
|
1129
|
-
tool: 'brainlink_context',
|
|
1130
|
-
reason: 'Context-first policy is enabled. Load context before other read tools.',
|
|
1131
|
-
args: {
|
|
1132
|
-
vault: context.vault,
|
|
1133
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1134
|
-
query: '<task>',
|
|
1135
|
-
mode: context.defaults.defaultSearchMode,
|
|
1136
|
-
strategy: context.defaults.defaultContextStrategy,
|
|
1137
|
-
limit: context.defaults.defaultSearchLimit,
|
|
1138
|
-
tokens: context.defaults.defaultContextTokens
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
]
|
|
1142
|
-
: nextActions;
|
|
1143
|
-
return jsonResult(withNextActions({
|
|
1144
|
-
vault: context.vault,
|
|
1145
|
-
agent: context.agent,
|
|
1146
|
-
runtime: getRuntimeMetadata(),
|
|
1147
|
-
policy,
|
|
1148
|
-
bootstrapStatus,
|
|
1149
|
-
contextStatus,
|
|
1150
|
-
...(input.preset ? { presetApplied: input.preset } : {})
|
|
1151
|
-
}, withContextAction));
|
|
1152
|
-
};
|
|
1153
|
-
export const versionTool = async (input) => {
|
|
1154
|
-
const context = await resolveExecutionContext(input);
|
|
1155
|
-
return jsonResult({
|
|
1156
|
-
vault: context.vault,
|
|
1157
|
-
agent: context.agent,
|
|
1158
|
-
runtime: getRuntimeMetadata()
|
|
1159
|
-
});
|
|
1160
|
-
};
|
|
1161
|
-
export const sessionCloseTool = async (input) => {
|
|
1162
|
-
const context = await resolveExecutionContext(input);
|
|
1163
|
-
const result = await closeSession({
|
|
1164
|
-
vaultPath: context.vault,
|
|
1165
|
-
agentId: context.agent,
|
|
1166
|
-
cwd: resolve(input.cwd ?? process.cwd()),
|
|
1167
|
-
content: input.content,
|
|
1168
|
-
write: input.dryRun !== true,
|
|
1169
|
-
autoIndex: input.autoIndex
|
|
1170
|
-
});
|
|
1171
|
-
return jsonResult({
|
|
1172
|
-
vault: context.vault,
|
|
1173
|
-
agent: context.agent,
|
|
1174
|
-
dryRun: input.dryRun === true,
|
|
1175
|
-
...result
|
|
1176
|
-
});
|
|
1177
|
-
};
|
|
1178
|
-
export const projectInitTool = async (input) => {
|
|
1179
|
-
const context = await resolveExecutionContext(input);
|
|
1180
|
-
const result = await initializeProjectMemory({
|
|
1181
|
-
vaultPath: context.vault,
|
|
1182
|
-
projectPath: resolve(input.projectPath ?? process.cwd()),
|
|
1183
|
-
agentId: context.agent
|
|
1184
|
-
});
|
|
1185
|
-
return jsonResult({
|
|
1186
|
-
agent: context.agent,
|
|
1187
|
-
...result
|
|
1188
|
-
});
|
|
1189
|
-
};
|
|
1190
|
-
export const recommendationsTool = async (input) => {
|
|
1191
|
-
const context = await resolveExecutionContext(input);
|
|
1192
|
-
const policy = await getBootstrapPolicy();
|
|
1193
|
-
const bootstrapStatus = await getBootstrapSessionStatus(context.vault, context.agent);
|
|
1194
|
-
const contextStatus = await getContextSessionStatus(context.vault, context.agent);
|
|
1195
|
-
const stats = await getStats(context.vault, context.agent);
|
|
1196
|
-
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
1197
|
-
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
1198
|
-
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
1199
|
-
const tokens = input.tokens ?? context.defaults.defaultContextTokens;
|
|
1200
|
-
const query = input.query?.trim();
|
|
1201
|
-
const recommendations = [
|
|
1202
|
-
...(policy.enforceBootstrap && (!policy.autoBootstrapOnRead || !policy.autoBootstrapOnStartup)
|
|
1203
|
-
? [
|
|
1204
|
-
{
|
|
1205
|
-
tool: 'brainlink_policy',
|
|
1206
|
-
reason: 'Enable fully automatic bootstrap for plug-and-play agent usage.',
|
|
1207
|
-
args: {
|
|
1208
|
-
preset: 'fully-auto'
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
]
|
|
1212
|
-
: []),
|
|
1213
|
-
...(!bootstrapStatus.ready && !policy.autoBootstrapOnRead
|
|
1214
|
-
? [
|
|
1215
|
-
{
|
|
1216
|
-
tool: 'brainlink_bootstrap',
|
|
1217
|
-
reason: 'Bootstrap is required before read tools when auto-bootstrap-on-read is disabled.',
|
|
1218
|
-
args: {
|
|
1219
|
-
vault: context.vault,
|
|
1220
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1221
|
-
mode,
|
|
1222
|
-
strategy,
|
|
1223
|
-
...(query ? { query } : {})
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
]
|
|
1227
|
-
: []),
|
|
1228
|
-
...(policy.enforceContextFirst && !contextStatus.ready
|
|
1229
|
-
? [
|
|
1230
|
-
{
|
|
1231
|
-
tool: 'brainlink_context',
|
|
1232
|
-
reason: 'Context-first policy is enabled. Load context before other read operations.',
|
|
1233
|
-
args: {
|
|
1234
|
-
vault: context.vault,
|
|
1235
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1236
|
-
query: query ?? '<task>',
|
|
1237
|
-
mode,
|
|
1238
|
-
strategy,
|
|
1239
|
-
limit,
|
|
1240
|
-
tokens
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
]
|
|
1244
|
-
: []),
|
|
1245
|
-
...(stats.documentCount === 0
|
|
1246
|
-
? [
|
|
1247
|
-
{
|
|
1248
|
-
tool: 'brainlink_add_note',
|
|
1249
|
-
reason: 'Seed the vault with a first durable note so retrieval can return useful context.',
|
|
1250
|
-
args: {
|
|
1251
|
-
vault: context.vault,
|
|
1252
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1253
|
-
title: 'Architecture',
|
|
1254
|
-
content: 'Seed durable memory with explicit [[links]] and #tags.'
|
|
1255
|
-
}
|
|
1256
|
-
},
|
|
1257
|
-
{
|
|
1258
|
-
tool: 'brainlink_index',
|
|
1259
|
-
reason: 'Rebuild index after writing the first notes.',
|
|
1260
|
-
args: {
|
|
1261
|
-
vault: context.vault
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
]
|
|
1265
|
-
: []),
|
|
1266
|
-
{
|
|
1267
|
-
tool: 'brainlink_context',
|
|
1268
|
-
reason: 'Retrieve grounded memory context before responding.',
|
|
1269
|
-
args: {
|
|
1270
|
-
vault: context.vault,
|
|
1271
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1272
|
-
query: query ?? '<task>',
|
|
1273
|
-
mode,
|
|
1274
|
-
strategy,
|
|
1275
|
-
limit,
|
|
1276
|
-
tokens
|
|
1277
|
-
}
|
|
1278
|
-
},
|
|
1279
|
-
{
|
|
1280
|
-
tool: 'brainlink_dedupe',
|
|
1281
|
-
reason: 'Detect and resolve duplicate durable notes to keep memory quality high.',
|
|
1282
|
-
args: {
|
|
1283
|
-
vault: context.vault,
|
|
1284
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1285
|
-
limit: 10,
|
|
1286
|
-
minScore: 0.92,
|
|
1287
|
-
semantic: true
|
|
1288
|
-
}
|
|
1289
|
-
},
|
|
1290
|
-
{
|
|
1291
|
-
tool: 'brainlink_add_note',
|
|
1292
|
-
reason: 'Persist durable outcomes after task completion (write responses include connectivity metadata).',
|
|
1293
|
-
args: {
|
|
1294
|
-
vault: context.vault,
|
|
1295
|
-
...(context.agent ? { agent: context.agent } : {}),
|
|
1296
|
-
title: 'Task Update',
|
|
1297
|
-
content: 'Durable findings connected to [[existing notes]].'
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
];
|
|
1301
|
-
return jsonResult({
|
|
1302
|
-
vault: context.vault,
|
|
1303
|
-
agent: context.agent,
|
|
1304
|
-
defaults: {
|
|
1305
|
-
mode,
|
|
1306
|
-
strategy,
|
|
1307
|
-
limit,
|
|
1308
|
-
tokens
|
|
1309
|
-
},
|
|
1310
|
-
contextStrategies: [
|
|
1311
|
-
{
|
|
1312
|
-
strategy: 'rag',
|
|
1313
|
-
useWhen: 'Use for fresh retrieval and context assembly from the current index.'
|
|
1314
|
-
},
|
|
1315
|
-
{
|
|
1316
|
-
strategy: 'cag',
|
|
1317
|
-
useWhen: 'Use for repeated or stable task context so Brainlink can reuse a fresh persisted context pack.'
|
|
1318
|
-
},
|
|
1319
|
-
{
|
|
1320
|
-
strategy: 'auto',
|
|
1321
|
-
useWhen: 'Use when the agent wants Brainlink to choose CAG on fresh pack hits and RAG otherwise.'
|
|
1322
|
-
}
|
|
1323
|
-
],
|
|
1324
|
-
policy,
|
|
1325
|
-
bootstrapStatus,
|
|
1326
|
-
contextStatus,
|
|
1327
|
-
stats,
|
|
1328
|
-
recommendations
|
|
1329
|
-
});
|
|
1330
|
-
};
|
|
1331
|
-
export const dedupeTool = async (input) => {
|
|
1332
|
-
const context = await resolveExecutionContext(input);
|
|
1333
|
-
const duplicates = await scanDuplicateNotes(context.vault, {
|
|
1334
|
-
agentId: context.agent,
|
|
1335
|
-
limit: input.limit ?? 25,
|
|
1336
|
-
minSemanticScore: input.minScore ?? 0.92,
|
|
1337
|
-
includeSemantic: input.semantic !== false
|
|
1338
|
-
});
|
|
1339
|
-
return jsonResult({
|
|
1340
|
-
vault: context.vault,
|
|
1341
|
-
agent: context.agent,
|
|
1342
|
-
duplicates
|
|
1343
|
-
});
|
|
1344
|
-
};
|
|
1345
|
-
export const dedupeResolveTool = async (input) => {
|
|
1346
|
-
const context = await resolveExecutionContext(input);
|
|
1347
|
-
const result = await resolveDuplicateNotes(context.vault, {
|
|
1348
|
-
leftPath: input.leftPath,
|
|
1349
|
-
rightPath: input.rightPath,
|
|
1350
|
-
action: input.action,
|
|
1351
|
-
autoIndex: isTruthy(input.autoIndex)
|
|
1352
|
-
});
|
|
1353
|
-
return jsonResult({
|
|
1354
|
-
vault: context.vault,
|
|
1355
|
-
...result
|
|
1356
|
-
});
|
|
1357
|
-
};
|
|
1
|
+
export { brokenLinksInputSchema, brokenLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, explainInputSchema, explainTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, orphansInputSchema, orphansTool, recommendationsInputSchema, recommendationsTool, searchInputSchema, searchTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, validateInputSchema, validateTool, versionInputSchema, versionTool } from './tools/read-tools.js';
|
|
2
|
+
export { addFileInputSchema, addFileTool, addNoteInputSchema, addNoteTool, deleteNoteInputSchema, deleteNoteTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, rememberInputSchema, rememberTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool } from './tools/write-tools.js';
|
|
3
|
+
export { bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, indexInputSchema, indexTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, repairLinksInputSchema, repairLinksTool, sessionCloseInputSchema, sessionCloseTool, syncInputSchema, syncTool } from './tools/maintenance-tools.js';
|