@gmickel/gno 1.16.0 → 1.18.0
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 +34 -18
- package/assets/skill/SKILL.md +25 -6
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +2 -2
- package/src/app/context-agent-projection.ts +303 -0
- package/src/app/context-format.ts +249 -0
- package/src/app/context-runtime-contract.ts +325 -0
- package/src/app/context-runtime-input.ts +362 -0
- package/src/app/context-runtime-types.ts +65 -0
- package/src/app/context-runtime.ts +170 -0
- package/src/app/context-surface.ts +145 -0
- package/src/cli/commands/context-build.ts +149 -0
- package/src/cli/commands/context-verify.ts +90 -0
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/models/pull.ts +13 -3
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/detach.ts +37 -20
- package/src/cli/options.ts +4 -0
- package/src/cli/program.ts +252 -27
- package/src/config/index.ts +3 -0
- package/src/config/types.ts +37 -0
- package/src/core/context-budget.ts +461 -0
- package/src/core/context-capsule-index-schema.ts +15 -0
- package/src/core/context-capsule-retrieval-schema.ts +81 -0
- package/src/core/context-capsule-schema.ts +473 -0
- package/src/core/context-capsule-validation.ts +416 -0
- package/src/core/context-capsule-verification.ts +218 -0
- package/src/core/context-capsule.ts +439 -0
- package/src/core/context-compiler.ts +513 -0
- package/src/core/context-evidence-metadata.ts +33 -0
- package/src/core/context-evidence.ts +495 -0
- package/src/core/context-facets.ts +163 -0
- package/src/core/context-guidance.ts +69 -0
- package/src/core/context-scope.ts +32 -0
- package/src/core/context-verifier-canonical.ts +90 -0
- package/src/core/context-verifier-input.ts +66 -0
- package/src/core/context-verifier.ts +447 -0
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -0
- package/src/core/sections.ts +63 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +28 -82
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +230 -0
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +49 -2
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/pipeline/chunk-lookup.ts +33 -0
- package/src/pipeline/hybrid.ts +79 -57
- package/src/pipeline/types.ts +14 -0
- package/src/sdk/client.ts +68 -6
- package/src/sdk/index.ts +21 -0
- package/src/sdk/types.ts +24 -0
- package/src/serve/background-runtime.ts +12 -211
- package/src/serve/context-capsule.ts +136 -0
- package/src/serve/context.ts +10 -1
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Dashboard.tsx +1 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/routes/api.ts +265 -167
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/server.ts +212 -35
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- package/src/store/sqlite/adapter.ts +64 -29
|
@@ -92,6 +92,9 @@ function formatResourceContent(
|
|
|
92
92
|
* Register gno:// resources with the MCP server.
|
|
93
93
|
*/
|
|
94
94
|
export function registerResources(server: McpServer, ctx: ToolContext): void {
|
|
95
|
+
const withSnapshot = <T>(operation: () => Promise<T>): Promise<T> =>
|
|
96
|
+
ctx.runWithSnapshot?.(operation) ?? operation();
|
|
97
|
+
|
|
95
98
|
// Resource template for gno://{collection}/{path} URIs
|
|
96
99
|
const template = new ResourceTemplate(`${URI_PREFIX}{collection}/{+path}`, {
|
|
97
100
|
list: async () => {
|
|
@@ -113,101 +116,103 @@ export function registerResources(server: McpServer, ctx: ToolContext): void {
|
|
|
113
116
|
});
|
|
114
117
|
|
|
115
118
|
// Register the template-based resource handler
|
|
116
|
-
server.resource("gno-document", template, {},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Serialize resource reads same as tools (prevent concurrent DB access + shutdown race)
|
|
123
|
-
const release = await ctx.toolMutex.acquire();
|
|
124
|
-
try {
|
|
125
|
-
// Use parseUri for proper URL decoding (handles %20, etc.)
|
|
126
|
-
const parsed = parseUri(uri.href);
|
|
127
|
-
if (!parsed) {
|
|
128
|
-
throw new Error(`Invalid gno:// URI: ${uri.href}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const resolution = resolveEffectiveIndex([uri.href], ctx.indexName);
|
|
132
|
-
if (!resolution.ok) {
|
|
133
|
-
throw new Error(resolution.error);
|
|
119
|
+
server.resource("gno-document", template, {}, (uri, _variables) =>
|
|
120
|
+
withSnapshot(async () => {
|
|
121
|
+
// Check shutdown before acquiring mutex
|
|
122
|
+
if (ctx.isShuttingDown()) {
|
|
123
|
+
throw new Error("Server is shutting down");
|
|
134
124
|
}
|
|
135
|
-
const scoped = await openScopedIndexStore({
|
|
136
|
-
activeStore: ctx.store,
|
|
137
|
-
activeIndexName: ctx.indexName,
|
|
138
|
-
requestedIndexName: resolution.value.indexName,
|
|
139
|
-
config: ctx.config,
|
|
140
|
-
configPath: ctx.actualConfigPath,
|
|
141
|
-
});
|
|
142
125
|
|
|
126
|
+
// Serialize resource reads same as tools (prevent concurrent DB access + shutdown race)
|
|
127
|
+
const release = await ctx.toolMutex.acquire();
|
|
143
128
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
(c) => c.name === collection
|
|
149
|
-
);
|
|
150
|
-
if (!collectionExists) {
|
|
151
|
-
throw new Error(`Collection not found: ${collection}`);
|
|
129
|
+
// Use parseUri for proper URL decoding (handles %20, etc.)
|
|
130
|
+
const parsed = parseUri(uri.href);
|
|
131
|
+
if (!parsed) {
|
|
132
|
+
throw new Error(`Invalid gno:// URI: ${uri.href}`);
|
|
152
133
|
}
|
|
153
134
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
throw new Error(
|
|
158
|
-
`Failed to lookup document: ${docResult.error.message}`
|
|
159
|
-
);
|
|
135
|
+
const resolution = resolveEffectiveIndex([uri.href], ctx.indexName);
|
|
136
|
+
if (!resolution.ok) {
|
|
137
|
+
throw new Error(resolution.error);
|
|
160
138
|
}
|
|
139
|
+
const scoped = await openScopedIndexStore({
|
|
140
|
+
activeStore: ctx.store,
|
|
141
|
+
activeIndexName: ctx.indexName,
|
|
142
|
+
requestedIndexName: resolution.value.indexName,
|
|
143
|
+
config: ctx.config,
|
|
144
|
+
configPath: ctx.actualConfigPath,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const { collection, path } = parsed;
|
|
149
|
+
|
|
150
|
+
// Validate collection exists
|
|
151
|
+
const collectionExists = ctx.collections.some(
|
|
152
|
+
(c) => c.name === collection
|
|
153
|
+
);
|
|
154
|
+
if (!collectionExists) {
|
|
155
|
+
throw new Error(`Collection not found: ${collection}`);
|
|
156
|
+
}
|
|
161
157
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
// Look up document (path is properly decoded by parseUri)
|
|
159
|
+
const docResult = await scoped.store.getDocument(collection, path);
|
|
160
|
+
if (!docResult.ok) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Failed to lookup document: ${docResult.error.message}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
166
165
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
const doc = docResult.value;
|
|
167
|
+
if (!doc) {
|
|
168
|
+
throw new Error(`Document not found: ${uri.href}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Get content
|
|
172
|
+
if (!doc.mirrorHash) {
|
|
173
|
+
throw new Error(`Document has no indexed content: ${uri.href}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const contentResult = await scoped.store.getContent(doc.mirrorHash);
|
|
177
|
+
if (!contentResult.ok) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Failed to read content: ${contentResult.error.message}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const content = contentResult.value ?? "";
|
|
171
184
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
185
|
+
// Format with header and line numbers
|
|
186
|
+
const formattedContent = formatResourceContent(
|
|
187
|
+
doc,
|
|
188
|
+
content,
|
|
189
|
+
ctx,
|
|
190
|
+
scoped.indexName
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Build canonical URI
|
|
194
|
+
const canonicalUri = decorateUriForIndex(
|
|
195
|
+
buildUri(collection, path),
|
|
196
|
+
scoped.indexName
|
|
176
197
|
);
|
|
177
|
-
}
|
|
178
198
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
buildUri(collection, path),
|
|
192
|
-
scoped.indexName
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
contents: [
|
|
197
|
-
{
|
|
198
|
-
uri: canonicalUri,
|
|
199
|
-
mimeType: "text/markdown",
|
|
200
|
-
text: formattedContent,
|
|
201
|
-
},
|
|
202
|
-
],
|
|
203
|
-
};
|
|
199
|
+
return {
|
|
200
|
+
contents: [
|
|
201
|
+
{
|
|
202
|
+
uri: canonicalUri,
|
|
203
|
+
mimeType: "text/markdown",
|
|
204
|
+
text: formattedContent,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
} finally {
|
|
209
|
+
await scoped.close();
|
|
210
|
+
}
|
|
204
211
|
} finally {
|
|
205
|
-
|
|
212
|
+
release();
|
|
206
213
|
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
});
|
|
214
|
+
})
|
|
215
|
+
);
|
|
211
216
|
|
|
212
217
|
// Register gno://tags resource for listing tags
|
|
213
218
|
// Use ResourceTemplate with RFC6570 query expansion for proper routing
|
|
@@ -231,65 +236,67 @@ export function registerResources(server: McpServer, ctx: ToolContext): void {
|
|
|
231
236
|
"gno-tags",
|
|
232
237
|
tagsTemplate,
|
|
233
238
|
{ mimeType: "application/json" },
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const release = await ctx.toolMutex.acquire();
|
|
241
|
-
try {
|
|
242
|
-
// Parse query params from URI
|
|
243
|
-
const url = new URL(uri.href);
|
|
244
|
-
const collectionParam = url.searchParams.get("collection") || undefined;
|
|
245
|
-
const prefixParam = url.searchParams.get("prefix") || undefined;
|
|
246
|
-
|
|
247
|
-
// Normalize and validate collection (case-insensitive)
|
|
248
|
-
let collection: string | undefined;
|
|
249
|
-
if (collectionParam) {
|
|
250
|
-
collection = normalizeCollectionName(collectionParam);
|
|
251
|
-
const exists = ctx.collections.some(
|
|
252
|
-
(c) => c.name.toLowerCase() === collection
|
|
253
|
-
);
|
|
254
|
-
if (!exists) {
|
|
255
|
-
throw new Error(
|
|
256
|
-
`${MCP_ERRORS.NOT_FOUND.code}: Collection not found: ${collectionParam}`
|
|
257
|
-
);
|
|
258
|
-
}
|
|
239
|
+
(uri) =>
|
|
240
|
+
withSnapshot(async () => {
|
|
241
|
+
// Check shutdown before acquiring mutex
|
|
242
|
+
if (ctx.isShuttingDown()) {
|
|
243
|
+
throw new Error("Server is shutting down");
|
|
259
244
|
}
|
|
260
245
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
246
|
+
const release = await ctx.toolMutex.acquire();
|
|
247
|
+
try {
|
|
248
|
+
// Parse query params from URI
|
|
249
|
+
const url = new URL(uri.href);
|
|
250
|
+
const collectionParam =
|
|
251
|
+
url.searchParams.get("collection") || undefined;
|
|
252
|
+
const prefixParam = url.searchParams.get("prefix") || undefined;
|
|
253
|
+
|
|
254
|
+
// Normalize and validate collection (case-insensitive)
|
|
255
|
+
let collection: string | undefined;
|
|
256
|
+
if (collectionParam) {
|
|
257
|
+
collection = normalizeCollectionName(collectionParam);
|
|
258
|
+
const exists = ctx.collections.some(
|
|
259
|
+
(c) => c.name.toLowerCase() === collection
|
|
260
|
+
);
|
|
261
|
+
if (!exists) {
|
|
268
262
|
throw new Error(
|
|
269
|
-
`${MCP_ERRORS.
|
|
263
|
+
`${MCP_ERRORS.NOT_FOUND.code}: Collection not found: ${collectionParam}`
|
|
270
264
|
);
|
|
271
265
|
}
|
|
272
266
|
}
|
|
273
|
-
}
|
|
274
267
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
268
|
+
// Normalize and validate prefix
|
|
269
|
+
let prefix: string | undefined;
|
|
270
|
+
if (prefixParam) {
|
|
271
|
+
const trimmed = prefixParam.trim().replace(/\/+$/, "");
|
|
272
|
+
if (trimmed.length > 0) {
|
|
273
|
+
prefix = normalizeTag(trimmed);
|
|
274
|
+
if (!validateTag(prefix)) {
|
|
275
|
+
throw new Error(
|
|
276
|
+
`${MCP_ERRORS.INVALID_INPUT.code}: Invalid tag prefix "${prefixParam}"`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
280
281
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
282
|
+
// Get tag counts
|
|
283
|
+
const result = await ctx.store.getTagCounts({ collection, prefix });
|
|
284
|
+
if (!result.ok) {
|
|
285
|
+
throw new Error(`Failed to get tags: ${result.error.message}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
contents: [
|
|
290
|
+
{
|
|
291
|
+
uri: uri.href,
|
|
292
|
+
mimeType: "application/json",
|
|
293
|
+
text: formatTagsContent(result.value, collection, prefix),
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
} finally {
|
|
298
|
+
release();
|
|
299
|
+
}
|
|
300
|
+
})
|
|
294
301
|
);
|
|
295
302
|
}
|
package/src/mcp/server.ts
CHANGED
|
@@ -5,67 +5,28 @@
|
|
|
5
5
|
* @module src/mcp/server
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
9
|
// node:path for join/dirname (no Bun path utils)
|
|
11
10
|
import { dirname, join } from "node:path";
|
|
12
11
|
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_INDEX_NAME,
|
|
14
|
+
MCP_SERVER_NAME,
|
|
15
|
+
VERSION,
|
|
16
|
+
getIndexDbPath,
|
|
17
|
+
} from "../app/constants";
|
|
18
|
+
import { canonicalizeIndexName } from "../app/index-name";
|
|
17
19
|
import { JobManager } from "../core/job-manager";
|
|
18
20
|
import { envIsSet } from "../llm/policy";
|
|
19
21
|
import { MCP_ACTIVATION_VERIFICATION_ENV } from "./activation-verification-mode";
|
|
22
|
+
import {
|
|
23
|
+
createMcpServerSurface,
|
|
24
|
+
createToolContext,
|
|
25
|
+
Mutex,
|
|
26
|
+
type ToolContext,
|
|
27
|
+
} from "./context";
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
// Simple Promise Mutex (avoids async-mutex dependency)
|
|
23
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
class Mutex {
|
|
26
|
-
#locked = false;
|
|
27
|
-
readonly #queue: Array<() => void> = [];
|
|
28
|
-
|
|
29
|
-
acquire(): Promise<() => void> {
|
|
30
|
-
return new Promise((resolve) => {
|
|
31
|
-
const tryAcquire = () => {
|
|
32
|
-
if (this.#locked) {
|
|
33
|
-
this.#queue.push(tryAcquire);
|
|
34
|
-
} else {
|
|
35
|
-
this.#locked = true;
|
|
36
|
-
resolve(() => this.#release());
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
tryAcquire();
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#release(): void {
|
|
44
|
-
this.#locked = false;
|
|
45
|
-
const next = this.#queue.shift();
|
|
46
|
-
if (next) {
|
|
47
|
-
next();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
-
// Tool Context
|
|
54
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
export interface ToolContext {
|
|
57
|
-
store: SqliteAdapter;
|
|
58
|
-
config: Config;
|
|
59
|
-
collections: Collection[];
|
|
60
|
-
actualConfigPath: string;
|
|
61
|
-
indexName?: string;
|
|
62
|
-
toolMutex: Mutex;
|
|
63
|
-
jobManager: JobManager;
|
|
64
|
-
serverInstanceId: string;
|
|
65
|
-
writeLockPath: string;
|
|
66
|
-
enableWrite: boolean;
|
|
67
|
-
isShuttingDown: () => boolean;
|
|
68
|
-
}
|
|
29
|
+
export type { ToolContext } from "./context";
|
|
69
30
|
|
|
70
31
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
71
32
|
// Server Options
|
|
@@ -120,7 +81,7 @@ export async function startMcpServer(options: McpServerOptions): Promise<void> {
|
|
|
120
81
|
MCP_ACTIVATION_VERIFICATION_ENV
|
|
121
82
|
);
|
|
122
83
|
const init = await initStore({
|
|
123
|
-
indexName: options.indexName,
|
|
84
|
+
indexName: canonicalizeIndexName(options.indexName ?? DEFAULT_INDEX_NAME),
|
|
124
85
|
configPath: options.configPath,
|
|
125
86
|
syncConfig: !activationVerification,
|
|
126
87
|
});
|
|
@@ -130,21 +91,7 @@ export async function startMcpServer(options: McpServerOptions): Promise<void> {
|
|
|
130
91
|
process.exit(1);
|
|
131
92
|
}
|
|
132
93
|
|
|
133
|
-
const { store, config,
|
|
134
|
-
|
|
135
|
-
// Create MCP server
|
|
136
|
-
const server = new McpServer(
|
|
137
|
-
{
|
|
138
|
-
name: MCP_SERVER_NAME,
|
|
139
|
-
version: VERSION,
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
capabilities: {
|
|
143
|
-
tools: { listChanged: false },
|
|
144
|
-
resources: { subscribe: false, listChanged: false },
|
|
145
|
-
},
|
|
146
|
-
}
|
|
147
|
-
);
|
|
94
|
+
const { store, config, actualConfigPath } = init;
|
|
148
95
|
|
|
149
96
|
// Sequential execution mutex
|
|
150
97
|
const toolMutex = new Mutex();
|
|
@@ -167,27 +114,26 @@ export async function startMcpServer(options: McpServerOptions): Promise<void> {
|
|
|
167
114
|
let shuttingDown = false;
|
|
168
115
|
|
|
169
116
|
// Tool context (passed to all handlers)
|
|
170
|
-
|
|
117
|
+
let currentConfig = config;
|
|
118
|
+
const ctx: ToolContext = createToolContext({
|
|
171
119
|
store,
|
|
172
|
-
|
|
173
|
-
|
|
120
|
+
getConfig: () => currentConfig,
|
|
121
|
+
setConfig: (nextConfig) => {
|
|
122
|
+
currentConfig = nextConfig;
|
|
123
|
+
},
|
|
174
124
|
actualConfigPath,
|
|
175
|
-
indexName: options.indexName,
|
|
125
|
+
indexName: canonicalizeIndexName(options.indexName ?? DEFAULT_INDEX_NAME),
|
|
176
126
|
toolMutex,
|
|
177
127
|
jobManager,
|
|
178
128
|
serverInstanceId,
|
|
179
129
|
writeLockPath,
|
|
180
130
|
enableWrite,
|
|
181
131
|
isShuttingDown: () => shuttingDown,
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// Register resources (T10.3)
|
|
189
|
-
const { registerResources } = await import("./resources/index.js");
|
|
190
|
-
registerResources(server, ctx);
|
|
132
|
+
});
|
|
133
|
+
const server = createMcpServerSurface(ctx, {
|
|
134
|
+
name: MCP_SERVER_NAME,
|
|
135
|
+
version: VERSION,
|
|
136
|
+
});
|
|
191
137
|
|
|
192
138
|
if (options.verbose) {
|
|
193
139
|
console.error(
|
|
@@ -14,6 +14,7 @@ import { applyConfigChange } from "../../core/config-mutation";
|
|
|
14
14
|
import { MCP_ERRORS } from "../../core/errors";
|
|
15
15
|
import { acquireWriteLock, type WriteLockHandle } from "../../core/file-lock";
|
|
16
16
|
import { JobError } from "../../core/job-manager";
|
|
17
|
+
import { recordContentMutation } from "../../core/mutation-generations";
|
|
17
18
|
import {
|
|
18
19
|
normalizeCollectionName,
|
|
19
20
|
validateCollectionRoot,
|
|
@@ -152,9 +153,10 @@ export function handleAddCollection(
|
|
|
152
153
|
gitPull: args.gitPull ?? false,
|
|
153
154
|
runUpdateCmd: false,
|
|
154
155
|
},
|
|
155
|
-
|
|
156
|
+
mutationResult.config
|
|
156
157
|
)
|
|
157
158
|
);
|
|
159
|
+
recordContentMutation(result, ctx.markContentMutation);
|
|
158
160
|
|
|
159
161
|
return {
|
|
160
162
|
collections: [result],
|
package/src/mcp/tools/capture.ts
CHANGED
|
@@ -210,6 +210,9 @@ export function handleCapture(
|
|
|
210
210
|
serverInstanceId: ctx.serverInstanceId,
|
|
211
211
|
}) as McpCaptureResult;
|
|
212
212
|
}
|
|
213
|
+
if (syncResult.status === "added" || syncResult.status === "updated") {
|
|
214
|
+
ctx.markContentMutation?.();
|
|
215
|
+
}
|
|
213
216
|
|
|
214
217
|
let docid = syncResult.docid;
|
|
215
218
|
let documentId: number | undefined;
|
|
@@ -8,6 +8,7 @@ import type { ToolContext } from "../server";
|
|
|
8
8
|
|
|
9
9
|
import { MCP_ERRORS } from "../../core/errors";
|
|
10
10
|
import { withWriteLock } from "../../core/file-lock";
|
|
11
|
+
import { recordIndexMutation } from "../../core/mutation-generations";
|
|
11
12
|
import { resolveModelUri } from "../../llm/registry";
|
|
12
13
|
import { runTool, type ToolResult } from "./index";
|
|
13
14
|
|
|
@@ -81,6 +82,7 @@ export function handleClearCollectionEmbeddings(
|
|
|
81
82
|
if (!result.ok) {
|
|
82
83
|
throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
83
84
|
}
|
|
85
|
+
recordIndexMutation(result.value.deletedVectors, ctx.markIndexMutation);
|
|
84
86
|
|
|
85
87
|
return {
|
|
86
88
|
...result.value,
|