@gmickel/gno 1.27.1 → 1.29.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 +46 -20
- package/assets/skill/SKILL.md +59 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +2 -2
- package/spec/cli.md +82 -5
- package/spec/db/schema.sql +31 -0
- package/spec/mcp.md +71 -0
- package/spec/output-schemas/ask.schema.json +156 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +183 -3
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/get.schema.json +94 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/mcp-job-status.schema.json +28 -0
- package/spec/output-schemas/multi-get.schema.json +128 -0
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +223 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-result.schema.json +94 -0
- package/spec/output-schemas/search-results.schema.json +155 -0
- package/spec/project-profile.schema.json +66 -0
- package/src/app/context-format.ts +1 -1
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/get.ts +12 -2
- package/src/cli/commands/index-cmd.ts +13 -0
- package/src/cli/commands/multi-get.ts +9 -2
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/shared.ts +28 -0
- package/src/cli/commands/update.ts +5 -0
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +127 -0
- package/src/config/index.ts +9 -0
- package/src/config/project-profile.ts +2 -0
- package/src/config/types.ts +66 -0
- package/src/converters/adapters/browser-export/adapter.ts +199 -0
- package/src/converters/adapters/browser-export/formats.ts +358 -0
- package/src/converters/adapters/email/adapter.ts +429 -0
- package/src/converters/adapters/email/html.ts +162 -0
- package/src/converters/adapters/email/mime.ts +454 -0
- package/src/converters/adapters/email/parameters.ts +77 -0
- package/src/converters/adapters/ical/adapter.ts +475 -0
- package/src/converters/adapters/ical/recurrence.ts +186 -0
- package/src/converters/adapters/jsonl/adapter.ts +238 -0
- package/src/converters/adapters/jsonl/config.ts +105 -0
- package/src/converters/adapters/shared/html-text.ts +165 -0
- package/src/converters/adapters/shared/record-utils.ts +79 -0
- package/src/converters/adapters/shared/utf8-lines.ts +141 -0
- package/src/converters/adapters/transcript/adapter.ts +295 -0
- package/src/converters/adapters/transcript/json.ts +184 -0
- package/src/converters/adapters/transcript/model.ts +171 -0
- package/src/converters/adapters/transcript/text.ts +58 -0
- package/src/converters/adapters/transcript/timed.ts +152 -0
- package/src/converters/index.ts +11 -1
- package/src/converters/mime.ts +8 -0
- package/src/converters/pipeline.ts +15 -1
- package/src/converters/registry.ts +37 -1
- package/src/converters/types.ts +136 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +198 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -112
- package/src/core/context-evidence.ts +93 -15
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/document-capabilities.ts +12 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/project-profile-apply-state.ts +5 -0
- package/src/core/project-profile.ts +4 -0
- package/src/core/record-metadata.ts +49 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter-canonical.ts +433 -0
- package/src/ingestion/record-adapter.ts +448 -0
- package/src/ingestion/record-container.ts +704 -0
- package/src/ingestion/record-path.ts +20 -0
- package/src/ingestion/record-sync.ts +70 -0
- package/src/ingestion/sync.ts +243 -36
- package/src/ingestion/types.ts +71 -1
- package/src/ingestion/walker.ts +31 -11
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/get.ts +10 -2
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/multi-get.ts +9 -2
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/mcp/tools/workspace-write.ts +2 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/filters.ts +1 -1
- package/src/pipeline/graph-retrieval.ts +7 -4
- package/src/pipeline/hybrid.ts +21 -4
- package/src/pipeline/result-context.ts +12 -4
- package/src/pipeline/search.ts +23 -4
- package/src/pipeline/types.ts +6 -0
- package/src/pipeline/vsearch.ts +67 -28
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/documents.ts +13 -5
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/browse-tree.ts +4 -2
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +237 -65
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/022-record-export-lineage.ts +42 -0
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +8 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +284 -14
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +166 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/** MCP collection egress policy and content-free audit management tools. */
|
|
2
|
+
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import type { ToolContext } from "../server";
|
|
6
|
+
|
|
7
|
+
import { projectCollectionEgressPolicy } from "../../core/collection-egress-policy-projection";
|
|
8
|
+
import { CollectionEgressPolicyService } from "../../core/collection-egress-policy-service";
|
|
9
|
+
import { applyConfigChange } from "../../core/config-mutation";
|
|
10
|
+
import { EgressAuditService } from "../../core/egress-audit";
|
|
11
|
+
import { runTool, type ToolResult } from "./index";
|
|
12
|
+
|
|
13
|
+
const policy = z.enum(["local_only", "lan", "remote"]);
|
|
14
|
+
|
|
15
|
+
export const egressPolicyGetInputSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
collection: z.string().min(1).max(64),
|
|
18
|
+
})
|
|
19
|
+
.strict();
|
|
20
|
+
|
|
21
|
+
export const egressPolicySetInputSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
collection: z.string().min(1).max(64),
|
|
24
|
+
policy,
|
|
25
|
+
confirmation: z
|
|
26
|
+
.object({
|
|
27
|
+
collection: z.string().min(1).max(64),
|
|
28
|
+
currentPolicy: policy,
|
|
29
|
+
currentRevision: z.number().int().nonnegative(),
|
|
30
|
+
targetPolicy: policy,
|
|
31
|
+
acknowledged: z.literal(true),
|
|
32
|
+
})
|
|
33
|
+
.strict()
|
|
34
|
+
.optional(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
|
|
38
|
+
export const egressCheckInputSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
collections: z.array(z.string().min(1).max(64)).min(1).max(64).optional(),
|
|
41
|
+
action: z.enum([
|
|
42
|
+
"retrieve",
|
|
43
|
+
"serve",
|
|
44
|
+
"publish",
|
|
45
|
+
"remote_inference",
|
|
46
|
+
"export",
|
|
47
|
+
"clip_write",
|
|
48
|
+
]),
|
|
49
|
+
destinationZone: z.enum(["local_process", "loopback", "lan", "remote"]),
|
|
50
|
+
caller: z
|
|
51
|
+
.object({
|
|
52
|
+
authenticated: z.boolean(),
|
|
53
|
+
operationAuthorized: z.boolean(),
|
|
54
|
+
})
|
|
55
|
+
.strict(),
|
|
56
|
+
contentClass: z.enum([
|
|
57
|
+
"source",
|
|
58
|
+
"snippet",
|
|
59
|
+
"metadata",
|
|
60
|
+
"attachment",
|
|
61
|
+
"embedding",
|
|
62
|
+
"capsule",
|
|
63
|
+
"audit_log",
|
|
64
|
+
"retrieval_trace",
|
|
65
|
+
]),
|
|
66
|
+
partialResults: z.enum(["deny", "explicit"]).default("deny"),
|
|
67
|
+
})
|
|
68
|
+
.strict();
|
|
69
|
+
|
|
70
|
+
export const egressAuditListInputSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
limit: z.number().int().min(1).max(1000).default(100),
|
|
73
|
+
cursor: z.string().min(1).max(512).optional(),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
|
|
77
|
+
export const egressAuditIdInputSchema = z
|
|
78
|
+
.object({
|
|
79
|
+
auditId: z.string().min(1).max(128),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
82
|
+
|
|
83
|
+
export const egressAuditStatusInputSchema = z.object({}).strict();
|
|
84
|
+
|
|
85
|
+
export const egressAuditPurgeInputSchema = z
|
|
86
|
+
.object({
|
|
87
|
+
confirm: z.literal(true),
|
|
88
|
+
})
|
|
89
|
+
.strict();
|
|
90
|
+
|
|
91
|
+
const json = (value: unknown): string => JSON.stringify(value, null, 2);
|
|
92
|
+
|
|
93
|
+
const unwrap = <T>(
|
|
94
|
+
result:
|
|
95
|
+
| { ok: true; value: T }
|
|
96
|
+
| { ok: false; error: { code: string; message: string } }
|
|
97
|
+
): T => {
|
|
98
|
+
if (result.ok) return result.value;
|
|
99
|
+
throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const requireWrite = (ctx: ToolContext): void => {
|
|
103
|
+
if (!ctx.enableWrite) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"WRITE_DISABLED: Egress policy and audit mutations require gateway.enableWrite or --mcp-enable-write"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const handleEgressPolicyGet = (
|
|
111
|
+
args: z.infer<typeof egressPolicyGetInputSchema>,
|
|
112
|
+
ctx: ToolContext
|
|
113
|
+
): Promise<ToolResult> =>
|
|
114
|
+
runTool(
|
|
115
|
+
ctx,
|
|
116
|
+
"gno_egress_policy_get",
|
|
117
|
+
async () => {
|
|
118
|
+
const state = new CollectionEgressPolicyService({
|
|
119
|
+
getConfig: () => ctx.config,
|
|
120
|
+
}).get(args.collection);
|
|
121
|
+
if (!state.ok) throw new Error(`${state.code}: ${state.error}`);
|
|
122
|
+
return state.value;
|
|
123
|
+
},
|
|
124
|
+
json
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
export const handleEgressPolicySet = (
|
|
128
|
+
args: z.infer<typeof egressPolicySetInputSchema>,
|
|
129
|
+
ctx: ToolContext
|
|
130
|
+
): Promise<ToolResult> =>
|
|
131
|
+
runTool(
|
|
132
|
+
ctx,
|
|
133
|
+
"gno_egress_policy_set",
|
|
134
|
+
async () => {
|
|
135
|
+
requireWrite(ctx);
|
|
136
|
+
const service = new CollectionEgressPolicyService({
|
|
137
|
+
getConfig: () => ctx.config,
|
|
138
|
+
mutateConfig: (mutate) =>
|
|
139
|
+
applyConfigChange(
|
|
140
|
+
{
|
|
141
|
+
store: ctx.store,
|
|
142
|
+
configPath: ctx.actualConfigPath,
|
|
143
|
+
onConfigUpdated: (config) => {
|
|
144
|
+
ctx.config = config;
|
|
145
|
+
},
|
|
146
|
+
projectStore: (store, config) =>
|
|
147
|
+
projectCollectionEgressPolicy(store, config, args.collection),
|
|
148
|
+
},
|
|
149
|
+
mutate
|
|
150
|
+
),
|
|
151
|
+
onPolicyChanged: async () =>
|
|
152
|
+
(await ctx.invalidateEgressPolicy?.()) ?? {
|
|
153
|
+
policyEpoch: "egress-epoch-standalone",
|
|
154
|
+
queuedJobsInvalidated: 0,
|
|
155
|
+
sessionsInvalidated: 0,
|
|
156
|
+
staleWorkMustRetry: true,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
const result = await service.set(args);
|
|
160
|
+
if (!result.ok) throw new Error(`${result.code}: ${result.error}`);
|
|
161
|
+
const epoch = result.value.invalidation?.policyEpoch;
|
|
162
|
+
if (epoch) ctx.advanceRequestAuthorizationEpoch?.(epoch);
|
|
163
|
+
return result.value;
|
|
164
|
+
},
|
|
165
|
+
json
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
export const handleEgressCheck = (
|
|
169
|
+
args: z.infer<typeof egressCheckInputSchema>,
|
|
170
|
+
ctx: ToolContext
|
|
171
|
+
): Promise<ToolResult> =>
|
|
172
|
+
runTool(
|
|
173
|
+
ctx,
|
|
174
|
+
"gno_egress_check",
|
|
175
|
+
async () => {
|
|
176
|
+
const result = new CollectionEgressPolicyService({
|
|
177
|
+
getConfig: () => ctx.config,
|
|
178
|
+
}).explain(args);
|
|
179
|
+
if (!result.ok) throw new Error(`${result.code}: ${result.error}`);
|
|
180
|
+
return result.value;
|
|
181
|
+
},
|
|
182
|
+
json
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
export const handleEgressAuditList = (
|
|
186
|
+
args: z.infer<typeof egressAuditListInputSchema>,
|
|
187
|
+
ctx: ToolContext
|
|
188
|
+
): Promise<ToolResult> =>
|
|
189
|
+
runTool(
|
|
190
|
+
ctx,
|
|
191
|
+
"gno_egress_audit_list",
|
|
192
|
+
async () => unwrap(await new EgressAuditService(ctx.store).list(args)),
|
|
193
|
+
json
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
export const handleEgressAuditShow = (
|
|
197
|
+
args: z.infer<typeof egressAuditIdInputSchema>,
|
|
198
|
+
ctx: ToolContext
|
|
199
|
+
): Promise<ToolResult> =>
|
|
200
|
+
runTool(
|
|
201
|
+
ctx,
|
|
202
|
+
"gno_egress_audit_show",
|
|
203
|
+
async () =>
|
|
204
|
+
unwrap(await new EgressAuditService(ctx.store).show(args.auditId)),
|
|
205
|
+
json
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
export const handleEgressAuditStatus = (
|
|
209
|
+
_args: z.infer<typeof egressAuditStatusInputSchema>,
|
|
210
|
+
ctx: ToolContext
|
|
211
|
+
): Promise<ToolResult> =>
|
|
212
|
+
runTool(
|
|
213
|
+
ctx,
|
|
214
|
+
"gno_egress_audit_status",
|
|
215
|
+
async () => unwrap(await new EgressAuditService(ctx.store).status()),
|
|
216
|
+
json
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
export const handleEgressAuditDelete = (
|
|
220
|
+
args: z.infer<typeof egressAuditIdInputSchema>,
|
|
221
|
+
ctx: ToolContext
|
|
222
|
+
): Promise<ToolResult> =>
|
|
223
|
+
runTool(
|
|
224
|
+
ctx,
|
|
225
|
+
"gno_egress_audit_delete",
|
|
226
|
+
async () => {
|
|
227
|
+
requireWrite(ctx);
|
|
228
|
+
return unwrap(
|
|
229
|
+
await new EgressAuditService(ctx.store).delete(args.auditId)
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
json
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
export const handleEgressAuditPurge = (
|
|
236
|
+
_args: z.infer<typeof egressAuditPurgeInputSchema>,
|
|
237
|
+
ctx: ToolContext
|
|
238
|
+
): Promise<ToolResult> =>
|
|
239
|
+
runTool(
|
|
240
|
+
ctx,
|
|
241
|
+
"gno_egress_audit_purge",
|
|
242
|
+
async () => {
|
|
243
|
+
requireWrite(ctx);
|
|
244
|
+
return unwrap(await new EgressAuditService(ctx.store).purge());
|
|
245
|
+
},
|
|
246
|
+
json
|
|
247
|
+
);
|
package/src/mcp/tools/embed.ts
CHANGED
|
@@ -87,6 +87,7 @@ export function handleEmbed(
|
|
|
87
87
|
// Create LLM adapter with offline policy (fail-fast, no download)
|
|
88
88
|
const llm = new LlmAdapter(ctx.config);
|
|
89
89
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
90
|
+
egressCollections: collection ? [collection.name] : "all",
|
|
90
91
|
policy: { offline: true, allowDownload: false },
|
|
91
92
|
});
|
|
92
93
|
|
package/src/mcp/tools/get.ts
CHANGED
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
type DocumentCapabilities,
|
|
16
16
|
} from "../../core/document-capabilities";
|
|
17
17
|
import { resolveEffectiveIndex } from "../../core/indexed-reference";
|
|
18
|
+
import {
|
|
19
|
+
projectRecordEvidenceMetadata,
|
|
20
|
+
type RecordEvidenceMetadata,
|
|
21
|
+
} from "../../core/record-metadata";
|
|
18
22
|
import { parseRef } from "../../core/ref-parser";
|
|
19
23
|
import {
|
|
20
24
|
attachRetrievalTraceMetadata,
|
|
@@ -54,6 +58,7 @@ interface GetResponse {
|
|
|
54
58
|
converterVersion?: string;
|
|
55
59
|
mirrorHash?: string;
|
|
56
60
|
};
|
|
61
|
+
record?: RecordEvidenceMetadata;
|
|
57
62
|
capabilities: DocumentCapabilities;
|
|
58
63
|
}
|
|
59
64
|
|
|
@@ -210,13 +215,14 @@ export function handleGet(
|
|
|
210
215
|
|
|
211
216
|
// Build absPath
|
|
212
217
|
const uriParsed = parseUri(doc.uri);
|
|
218
|
+
const sourceRelPath = doc.recordSourcePath ?? doc.relPath;
|
|
213
219
|
let absPath: string | undefined;
|
|
214
220
|
if (uriParsed) {
|
|
215
221
|
const collection = ctx.collections.find(
|
|
216
222
|
(c) => c.name === uriParsed.collection
|
|
217
223
|
);
|
|
218
224
|
if (collection) {
|
|
219
|
-
absPath = pathJoin(collection.path,
|
|
225
|
+
absPath = pathJoin(collection.path, sourceRelPath);
|
|
220
226
|
}
|
|
221
227
|
}
|
|
222
228
|
|
|
@@ -230,7 +236,7 @@ export function handleGet(
|
|
|
230
236
|
language: doc.languageHint ?? undefined,
|
|
231
237
|
source: {
|
|
232
238
|
absPath,
|
|
233
|
-
relPath:
|
|
239
|
+
relPath: sourceRelPath,
|
|
234
240
|
mime: doc.sourceMime,
|
|
235
241
|
ext: doc.sourceExt,
|
|
236
242
|
modifiedAt: doc.sourceMtime,
|
|
@@ -244,10 +250,12 @@ export function handleGet(
|
|
|
244
250
|
mirrorHash: doc.mirrorHash,
|
|
245
251
|
}
|
|
246
252
|
: undefined,
|
|
253
|
+
record: projectRecordEvidenceMetadata(doc),
|
|
247
254
|
capabilities: getDocumentCapabilities({
|
|
248
255
|
sourceExt: doc.sourceExt,
|
|
249
256
|
sourceMime: doc.sourceMime,
|
|
250
257
|
contentAvailable: doc.mirrorHash !== null,
|
|
258
|
+
recordKey: doc.recordKey,
|
|
251
259
|
}),
|
|
252
260
|
};
|
|
253
261
|
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
createVectorIndexPort,
|
|
24
24
|
createVectorStatsPort,
|
|
25
25
|
} from "../../store/vector";
|
|
26
|
+
import { enforceSyncCommandEgress } from "../sync-egress";
|
|
26
27
|
import { runTool, type ToolResult } from "./index";
|
|
27
28
|
|
|
28
29
|
interface IndexInput {
|
|
@@ -107,6 +108,11 @@ export function handleIndex(
|
|
|
107
108
|
},
|
|
108
109
|
ctx.config
|
|
109
110
|
);
|
|
111
|
+
enforceSyncCommandEgress(ctx, {
|
|
112
|
+
collectionNames: collections,
|
|
113
|
+
gitPull: options.gitPull,
|
|
114
|
+
runUpdateCmd: options.runUpdateCmd,
|
|
115
|
+
});
|
|
110
116
|
|
|
111
117
|
const modelUri = resolveModelUri(
|
|
112
118
|
ctx.config,
|
|
@@ -144,6 +150,7 @@ export function handleIndex(
|
|
|
144
150
|
// Phase 2: Embed
|
|
145
151
|
const llm = new LlmAdapter(ctx.config);
|
|
146
152
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
153
|
+
egressCollections: collections,
|
|
147
154
|
policy: { offline: true, allowDownload: false },
|
|
148
155
|
});
|
|
149
156
|
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -31,6 +31,23 @@ import {
|
|
|
31
31
|
} from "./changes";
|
|
32
32
|
import { handleClearCollectionEmbeddings } from "./clear-collection-embeddings";
|
|
33
33
|
import { handleContext, handleContextVerify } from "./context";
|
|
34
|
+
import {
|
|
35
|
+
egressAuditIdInputSchema,
|
|
36
|
+
egressAuditListInputSchema,
|
|
37
|
+
egressAuditPurgeInputSchema,
|
|
38
|
+
egressAuditStatusInputSchema,
|
|
39
|
+
egressCheckInputSchema,
|
|
40
|
+
egressPolicyGetInputSchema,
|
|
41
|
+
egressPolicySetInputSchema,
|
|
42
|
+
handleEgressAuditDelete,
|
|
43
|
+
handleEgressAuditList,
|
|
44
|
+
handleEgressAuditPurge,
|
|
45
|
+
handleEgressAuditShow,
|
|
46
|
+
handleEgressAuditStatus,
|
|
47
|
+
handleEgressCheck,
|
|
48
|
+
handleEgressPolicyGet,
|
|
49
|
+
handleEgressPolicySet,
|
|
50
|
+
} from "./egress";
|
|
34
51
|
import { handleEmbed } from "./embed";
|
|
35
52
|
import { handleGet } from "./get";
|
|
36
53
|
import { handleIndex } from "./index-cmd";
|
|
@@ -125,6 +142,9 @@ export const MCP_WRITE_TOOL_NAMES = new Set([
|
|
|
125
142
|
"gno_trace_export",
|
|
126
143
|
"gno_trace_delete",
|
|
127
144
|
"gno_trace_purge",
|
|
145
|
+
"gno_egress_policy_set",
|
|
146
|
+
"gno_egress_audit_delete",
|
|
147
|
+
"gno_egress_audit_purge",
|
|
128
148
|
]);
|
|
129
149
|
|
|
130
150
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1059,6 +1079,54 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
1059
1079
|
(args) => handleStatus(args, ctx)
|
|
1060
1080
|
);
|
|
1061
1081
|
|
|
1082
|
+
server.registerTool(
|
|
1083
|
+
"gno_egress_policy_get",
|
|
1084
|
+
{
|
|
1085
|
+
description:
|
|
1086
|
+
"Show one collection's configured and effective egress policy, provenance source, and confirmation-bound version.",
|
|
1087
|
+
inputSchema: egressPolicyGetInputSchema,
|
|
1088
|
+
},
|
|
1089
|
+
(args) => handleEgressPolicyGet(args, ctx)
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
server.registerTool(
|
|
1093
|
+
"gno_egress_check",
|
|
1094
|
+
{
|
|
1095
|
+
description:
|
|
1096
|
+
"Check or explain an exact action, destination, caller, content class, and collection scope without performing the action.",
|
|
1097
|
+
inputSchema: egressCheckInputSchema,
|
|
1098
|
+
},
|
|
1099
|
+
(args) => handleEgressCheck(args, ctx)
|
|
1100
|
+
);
|
|
1101
|
+
|
|
1102
|
+
server.registerTool(
|
|
1103
|
+
"gno_egress_audit_list",
|
|
1104
|
+
{
|
|
1105
|
+
description:
|
|
1106
|
+
"List content-free local egress decisions newest-first through an opaque cursor.",
|
|
1107
|
+
inputSchema: egressAuditListInputSchema,
|
|
1108
|
+
},
|
|
1109
|
+
(args) => handleEgressAuditList(args, ctx)
|
|
1110
|
+
);
|
|
1111
|
+
|
|
1112
|
+
server.registerTool(
|
|
1113
|
+
"gno_egress_audit_show",
|
|
1114
|
+
{
|
|
1115
|
+
description: "Inspect one content-free local egress decision receipt.",
|
|
1116
|
+
inputSchema: egressAuditIdInputSchema,
|
|
1117
|
+
},
|
|
1118
|
+
(args) => handleEgressAuditShow(args, ctx)
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
server.registerTool(
|
|
1122
|
+
"gno_egress_audit_status",
|
|
1123
|
+
{
|
|
1124
|
+
description: "Show local egress audit retention and storage status.",
|
|
1125
|
+
inputSchema: egressAuditStatusInputSchema,
|
|
1126
|
+
},
|
|
1127
|
+
(args) => handleEgressAuditStatus(args, ctx)
|
|
1128
|
+
);
|
|
1129
|
+
|
|
1062
1130
|
server.tool(
|
|
1063
1131
|
"gno_changes",
|
|
1064
1132
|
"List retained metadata-only document changes with opaque cursor pagination and retention disclosure.",
|
|
@@ -1151,6 +1219,36 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
1151
1219
|
);
|
|
1152
1220
|
|
|
1153
1221
|
if (ctx.enableWrite) {
|
|
1222
|
+
server.registerTool(
|
|
1223
|
+
"gno_egress_policy_set",
|
|
1224
|
+
{
|
|
1225
|
+
description:
|
|
1226
|
+
"Set one collection policy. Relaxation requires confirmation bound to the current policy and version.",
|
|
1227
|
+
inputSchema: egressPolicySetInputSchema,
|
|
1228
|
+
},
|
|
1229
|
+
(args) => handleEgressPolicySet(args, ctx)
|
|
1230
|
+
);
|
|
1231
|
+
|
|
1232
|
+
server.registerTool(
|
|
1233
|
+
"gno_egress_audit_delete",
|
|
1234
|
+
{
|
|
1235
|
+
description:
|
|
1236
|
+
"Delete exactly one local egress audit receipt with physical cleanup status.",
|
|
1237
|
+
inputSchema: egressAuditIdInputSchema,
|
|
1238
|
+
},
|
|
1239
|
+
(args) => handleEgressAuditDelete(args, ctx)
|
|
1240
|
+
);
|
|
1241
|
+
|
|
1242
|
+
server.registerTool(
|
|
1243
|
+
"gno_egress_audit_purge",
|
|
1244
|
+
{
|
|
1245
|
+
description:
|
|
1246
|
+
"Purge local egress audit receipts only. Requires confirm=true.",
|
|
1247
|
+
inputSchema: egressAuditPurgeInputSchema,
|
|
1248
|
+
},
|
|
1249
|
+
(args) => handleEgressAuditPurge(args, ctx)
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1154
1252
|
server.tool(
|
|
1155
1253
|
"gno_trace_label",
|
|
1156
1254
|
"Append an explicit relevant, irrelevant, or missing_expected judgment to a local retrieval trace.",
|
|
@@ -11,6 +11,10 @@ import type { ToolContext } from "../server";
|
|
|
11
11
|
|
|
12
12
|
import { decorateUriForIndex, parseUri } from "../../app/constants";
|
|
13
13
|
import { resolveEffectiveIndex } from "../../core/indexed-reference";
|
|
14
|
+
import {
|
|
15
|
+
projectRecordEvidenceMetadata,
|
|
16
|
+
type RecordEvidenceMetadata,
|
|
17
|
+
} from "../../core/record-metadata";
|
|
14
18
|
import { parseRef } from "../../core/ref-parser";
|
|
15
19
|
import { openScopedIndexStore } from "../../store/sqlite/scoped-index";
|
|
16
20
|
import { runTool, type ToolResult } from "./index";
|
|
@@ -37,6 +41,7 @@ interface DocumentResult {
|
|
|
37
41
|
modifiedAt?: string;
|
|
38
42
|
sizeBytes?: number;
|
|
39
43
|
};
|
|
44
|
+
record?: RecordEvidenceMetadata;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
interface MultiGetResponse {
|
|
@@ -234,13 +239,14 @@ export function handleMultiGet(
|
|
|
234
239
|
|
|
235
240
|
// Build absPath
|
|
236
241
|
const uriParsed = parseUri(doc.uri);
|
|
242
|
+
const sourceRelPath = doc.recordSourcePath ?? doc.relPath;
|
|
237
243
|
let absPath: string | undefined;
|
|
238
244
|
if (uriParsed) {
|
|
239
245
|
const collection = ctx.collections.find(
|
|
240
246
|
(c) => c.name === uriParsed.collection
|
|
241
247
|
);
|
|
242
248
|
if (collection) {
|
|
243
|
-
absPath = pathJoin(collection.path,
|
|
249
|
+
absPath = pathJoin(collection.path, sourceRelPath);
|
|
244
250
|
}
|
|
245
251
|
}
|
|
246
252
|
|
|
@@ -253,12 +259,13 @@ export function handleMultiGet(
|
|
|
253
259
|
truncated,
|
|
254
260
|
source: {
|
|
255
261
|
absPath,
|
|
256
|
-
relPath:
|
|
262
|
+
relPath: sourceRelPath,
|
|
257
263
|
mime: doc.sourceMime,
|
|
258
264
|
ext: doc.sourceExt,
|
|
259
265
|
modifiedAt: doc.sourceMtime,
|
|
260
266
|
sizeBytes: doc.sourceSize,
|
|
261
267
|
},
|
|
268
|
+
record: projectRecordEvidenceMetadata(doc),
|
|
262
269
|
});
|
|
263
270
|
}
|
|
264
271
|
|
package/src/mcp/tools/query.ts
CHANGED
|
@@ -279,6 +279,9 @@ export function handleQuery(
|
|
|
279
279
|
if (!traceStart.ok) throw new Error(traceStart.error.message);
|
|
280
280
|
traceSession = traceStart.value ?? undefined;
|
|
281
281
|
const llm = new LlmAdapter(ctx.config);
|
|
282
|
+
const egressCollections = args.collection
|
|
283
|
+
? [args.collection]
|
|
284
|
+
: ("all" as const);
|
|
282
285
|
|
|
283
286
|
// Resolve download policy from env (MCP has no CLI flags)
|
|
284
287
|
const policy = resolveDownloadPolicy(process.env, {});
|
|
@@ -288,6 +291,7 @@ export function handleQuery(
|
|
|
288
291
|
|
|
289
292
|
// Create embedding port (for vector search) - optional
|
|
290
293
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
294
|
+
egressCollections,
|
|
291
295
|
policy,
|
|
292
296
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
293
297
|
});
|
|
@@ -298,6 +302,7 @@ export function handleQuery(
|
|
|
298
302
|
// Create expansion port - optional
|
|
299
303
|
if (expandUri) {
|
|
300
304
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
305
|
+
egressCollections,
|
|
301
306
|
policy,
|
|
302
307
|
onProgress: (progress) => downloadProgress("expand", progress),
|
|
303
308
|
});
|
|
@@ -309,6 +314,7 @@ export function handleQuery(
|
|
|
309
314
|
// Create rerank port - optional
|
|
310
315
|
if (rerankUri) {
|
|
311
316
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
317
|
+
egressCollections,
|
|
312
318
|
policy,
|
|
313
319
|
onProgress: (progress) => downloadProgress("rerank", progress),
|
|
314
320
|
});
|
|
@@ -425,6 +431,7 @@ export function handleQueryDiagnose(
|
|
|
425
431
|
const llm = new LlmAdapter(ctx.config);
|
|
426
432
|
const policy = resolveDownloadPolicy(process.env, {});
|
|
427
433
|
const downloadProgress = createNonTtyProgressRenderer();
|
|
434
|
+
const egressCollections = collection ? [collection] : ("all" as const);
|
|
428
435
|
|
|
429
436
|
let embedPort: EmbeddingPort | null = null;
|
|
430
437
|
let expandPort: GenerationPort | null = null;
|
|
@@ -456,6 +463,7 @@ export function handleQueryDiagnose(
|
|
|
456
463
|
|
|
457
464
|
if (!args.fast) {
|
|
458
465
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
466
|
+
egressCollections,
|
|
459
467
|
policy,
|
|
460
468
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
461
469
|
});
|
|
@@ -468,6 +476,7 @@ export function handleQueryDiagnose(
|
|
|
468
476
|
const genResult = await llm.createExpansionPort(
|
|
469
477
|
resolveModelUri(ctx.config, "expand", undefined, collection),
|
|
470
478
|
{
|
|
479
|
+
egressCollections,
|
|
471
480
|
policy,
|
|
472
481
|
onProgress: (progress) => downloadProgress("expand", progress),
|
|
473
482
|
}
|
|
@@ -481,6 +490,7 @@ export function handleQueryDiagnose(
|
|
|
481
490
|
const rerankResult = await llm.createRerankPort(
|
|
482
491
|
resolveModelUri(ctx.config, "rerank", undefined, collection),
|
|
483
492
|
{
|
|
493
|
+
egressCollections,
|
|
484
494
|
policy,
|
|
485
495
|
onProgress: (progress) => downloadProgress("rerank", progress),
|
|
486
496
|
}
|
|
@@ -89,6 +89,10 @@ export function handleRemoveCollection(
|
|
|
89
89
|
if (!mutationResult.ok) {
|
|
90
90
|
throw mapConfigError(mutationResult.code, mutationResult.error);
|
|
91
91
|
}
|
|
92
|
+
const invalidation = await ctx.invalidateEgressPolicy?.();
|
|
93
|
+
if (invalidation) {
|
|
94
|
+
ctx.advanceRequestAuthorizationEpoch?.(invalidation.policyEpoch);
|
|
95
|
+
}
|
|
92
96
|
ctx.markContentMutation?.();
|
|
93
97
|
ctx.markIndexMutation?.();
|
|
94
98
|
|
package/src/mcp/tools/sync.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { JobError } from "../../core/job-manager";
|
|
|
14
14
|
import { recordContentMutation } from "../../core/mutation-generations";
|
|
15
15
|
import { normalizeCollectionName } from "../../core/validation";
|
|
16
16
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
17
|
+
import { enforceSyncCommandEgress } from "../sync-egress";
|
|
17
18
|
import { runTool, type ToolResult } from "./index";
|
|
18
19
|
|
|
19
20
|
interface SyncInput {
|
|
@@ -109,6 +110,11 @@ export function handleSync(
|
|
|
109
110
|
},
|
|
110
111
|
ctx.config
|
|
111
112
|
);
|
|
113
|
+
enforceSyncCommandEgress(ctx, {
|
|
114
|
+
collectionNames: collections,
|
|
115
|
+
gitPull: options.gitPull,
|
|
116
|
+
runUpdateCmd: options.runUpdateCmd,
|
|
117
|
+
});
|
|
112
118
|
|
|
113
119
|
const jobId = await ctx.jobManager.startJobWithLock(
|
|
114
120
|
"sync",
|
package/src/mcp/tools/trace.ts
CHANGED
|
@@ -106,7 +106,13 @@ const runTraceWrite = <T>(
|
|
|
106
106
|
async () => {
|
|
107
107
|
if (!ctx.enableWrite) return writeDisabled();
|
|
108
108
|
return withWriteLock(ctx.writeLockPath, async () =>
|
|
109
|
-
unwrap(
|
|
109
|
+
unwrap(
|
|
110
|
+
await operation(
|
|
111
|
+
new RetrievalTraceManagementService(ctx.store, {
|
|
112
|
+
authorizeExport: ctx.authorizeTraceExport,
|
|
113
|
+
})
|
|
114
|
+
)
|
|
115
|
+
)
|
|
110
116
|
);
|
|
111
117
|
},
|
|
112
118
|
jsonText
|
package/src/mcp/tools/vsearch.ts
CHANGED
|
@@ -180,6 +180,7 @@ export function handleVsearch(
|
|
|
180
180
|
// Create LLM adapter for embeddings
|
|
181
181
|
const llm = new LlmAdapter(ctx.config);
|
|
182
182
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
183
|
+
egressCollections: args.collection ? [args.collection] : "all",
|
|
183
184
|
policy,
|
|
184
185
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
185
186
|
});
|
|
@@ -141,11 +141,13 @@ function ensureEditable(doc: {
|
|
|
141
141
|
sourceExt: string;
|
|
142
142
|
sourceMime: string;
|
|
143
143
|
mirrorHash: string | null;
|
|
144
|
+
recordKey?: string | null;
|
|
144
145
|
}) {
|
|
145
146
|
const capabilities = getDocumentCapabilities({
|
|
146
147
|
sourceExt: doc.sourceExt,
|
|
147
148
|
sourceMime: doc.sourceMime,
|
|
148
149
|
contentAvailable: doc.mirrorHash !== null,
|
|
150
|
+
recordKey: doc.recordKey,
|
|
149
151
|
});
|
|
150
152
|
if (!capabilities.editable) {
|
|
151
153
|
throw new Error(
|