@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
|
@@ -6,6 +6,35 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["results", "meta"],
|
|
8
8
|
"$defs": {
|
|
9
|
+
"egressLineage": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"required": ["effectivePolicy", "digest", "sources"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"effectivePolicy": { "enum": ["local_only", "lan", "remote"] },
|
|
15
|
+
"digest": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
16
|
+
"sources": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"minItems": 1,
|
|
19
|
+
"maxItems": 128,
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["collection", "policy", "source"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"collection": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
|
|
28
|
+
},
|
|
29
|
+
"policy": { "enum": ["local_only", "lan", "remote"] },
|
|
30
|
+
"source": {
|
|
31
|
+
"enum": ["explicit", "config_default", "legacy_default"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
9
38
|
"searchResult": {
|
|
10
39
|
"type": "object",
|
|
11
40
|
"required": ["docid", "score", "uri", "snippet", "source"],
|
|
@@ -54,10 +83,136 @@
|
|
|
54
83
|
"type": "string",
|
|
55
84
|
"description": "Resolved user-configured retrieval guidance, ordered from global to collection to matching path prefixes"
|
|
56
85
|
},
|
|
86
|
+
"egressLineage": { "$ref": "#/$defs/egressLineage" },
|
|
57
87
|
"snippet": {
|
|
58
88
|
"type": "string",
|
|
59
89
|
"description": "Matching text snippet from document mirror"
|
|
60
90
|
},
|
|
91
|
+
"record": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"description": "Bounded logical-record provenance for a file/export source",
|
|
95
|
+
"required": ["recordKey", "sourceLocator", "anchors", "adapter"],
|
|
96
|
+
"properties": {
|
|
97
|
+
"recordKey": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
98
|
+
"sourceLocator": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"minLength": 1,
|
|
101
|
+
"maxLength": 512
|
|
102
|
+
},
|
|
103
|
+
"anchors": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"maxItems": 256,
|
|
106
|
+
"items": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": false,
|
|
109
|
+
"required": ["kind", "value"],
|
|
110
|
+
"properties": {
|
|
111
|
+
"kind": {
|
|
112
|
+
"enum": [
|
|
113
|
+
"line",
|
|
114
|
+
"cue",
|
|
115
|
+
"timestamp",
|
|
116
|
+
"message",
|
|
117
|
+
"event",
|
|
118
|
+
"record"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"value": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"minLength": 1,
|
|
124
|
+
"maxLength": 512
|
|
125
|
+
},
|
|
126
|
+
"endValue": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"minLength": 1,
|
|
129
|
+
"maxLength": 512
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"adapter": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["id", "version", "fingerprint"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"id": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
140
|
+
"version": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"minLength": 1,
|
|
143
|
+
"maxLength": 64
|
|
144
|
+
},
|
|
145
|
+
"fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"author": { "type": "string", "maxLength": 2048 },
|
|
149
|
+
"participants": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"maxItems": 256,
|
|
152
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 2048 }
|
|
153
|
+
},
|
|
154
|
+
"categories": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"maxItems": 256,
|
|
157
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
158
|
+
},
|
|
159
|
+
"dateFields": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"maxProperties": 256,
|
|
162
|
+
"propertyNames": { "type": "string", "maxLength": 128 },
|
|
163
|
+
"additionalProperties": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"minLength": 1,
|
|
166
|
+
"maxLength": 256
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"messageId": { "type": "string", "maxLength": 2048 },
|
|
170
|
+
"inReplyTo": { "type": "string", "maxLength": 2048 },
|
|
171
|
+
"references": {
|
|
172
|
+
"type": "array",
|
|
173
|
+
"maxItems": 256,
|
|
174
|
+
"items": {
|
|
175
|
+
"type": "string",
|
|
176
|
+
"minLength": 1,
|
|
177
|
+
"maxLength": 2048
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"threadId": { "type": "string", "maxLength": 2048 },
|
|
181
|
+
"eventId": { "type": "string", "maxLength": 2048 },
|
|
182
|
+
"sessionId": { "type": "string", "maxLength": 2048 },
|
|
183
|
+
"attachments": {
|
|
184
|
+
"type": "array",
|
|
185
|
+
"maxItems": 256,
|
|
186
|
+
"items": {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"additionalProperties": false,
|
|
189
|
+
"required": ["name"],
|
|
190
|
+
"properties": {
|
|
191
|
+
"name": {
|
|
192
|
+
"type": "string",
|
|
193
|
+
"minLength": 1,
|
|
194
|
+
"maxLength": 512
|
|
195
|
+
},
|
|
196
|
+
"mime": {
|
|
197
|
+
"type": "string",
|
|
198
|
+
"minLength": 1,
|
|
199
|
+
"maxLength": 256
|
|
200
|
+
},
|
|
201
|
+
"bytes": {
|
|
202
|
+
"type": "integer",
|
|
203
|
+
"minimum": 0,
|
|
204
|
+
"maximum": 9007199254740991
|
|
205
|
+
},
|
|
206
|
+
"disposition": { "enum": ["inline", "attachment"] },
|
|
207
|
+
"sha256": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"pattern": "^[a-f0-9]{64}$"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
61
216
|
"snippetRange": {
|
|
62
217
|
"type": "object",
|
|
63
218
|
"description": "Line range of snippet in mirror content",
|
|
@@ -186,6 +186,72 @@
|
|
|
186
186
|
"modelPreset": {
|
|
187
187
|
"type": "string",
|
|
188
188
|
"pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
|
|
189
|
+
},
|
|
190
|
+
"recordAdapters": {
|
|
191
|
+
"$ref": "#/definitions/recordAdapters"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"jsonPointer": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"maxLength": 512,
|
|
198
|
+
"pattern": "^(?!.*(?:^|/)(?:__proto__|constructor|prototype)(?:/|$))(?:/(?:[^~/]|~[01])*){0,32}$"
|
|
199
|
+
},
|
|
200
|
+
"fieldSelector": {
|
|
201
|
+
"oneOf": [
|
|
202
|
+
{ "$ref": "#/definitions/jsonPointer" },
|
|
203
|
+
{
|
|
204
|
+
"type": "array",
|
|
205
|
+
"minItems": 1,
|
|
206
|
+
"maxItems": 8,
|
|
207
|
+
"items": { "$ref": "#/definitions/jsonPointer" }
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"jsonlFieldMapping": {
|
|
212
|
+
"type": "object",
|
|
213
|
+
"additionalProperties": false,
|
|
214
|
+
"properties": {
|
|
215
|
+
"id": { "$ref": "#/definitions/fieldSelector" },
|
|
216
|
+
"body": { "$ref": "#/definitions/fieldSelector" },
|
|
217
|
+
"title": { "$ref": "#/definitions/fieldSelector" },
|
|
218
|
+
"author": { "$ref": "#/definitions/fieldSelector" },
|
|
219
|
+
"participants": { "$ref": "#/definitions/fieldSelector" },
|
|
220
|
+
"categories": { "$ref": "#/definitions/fieldSelector" },
|
|
221
|
+
"sessionId": { "$ref": "#/definitions/fieldSelector" },
|
|
222
|
+
"threadId": { "$ref": "#/definitions/fieldSelector" },
|
|
223
|
+
"dateFields": {
|
|
224
|
+
"type": "object",
|
|
225
|
+
"maxProperties": 16,
|
|
226
|
+
"propertyNames": {
|
|
227
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
228
|
+
},
|
|
229
|
+
"additionalProperties": {
|
|
230
|
+
"$ref": "#/definitions/fieldSelector"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"recordAdapters": {
|
|
236
|
+
"type": "object",
|
|
237
|
+
"additionalProperties": false,
|
|
238
|
+
"properties": {
|
|
239
|
+
"jsonl": {
|
|
240
|
+
"type": "object",
|
|
241
|
+
"additionalProperties": false,
|
|
242
|
+
"properties": {
|
|
243
|
+
"fieldMapping": {
|
|
244
|
+
"$ref": "#/definitions/jsonlFieldMapping"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"transcript": {
|
|
249
|
+
"type": "object",
|
|
250
|
+
"additionalProperties": false,
|
|
251
|
+
"required": ["format"],
|
|
252
|
+
"properties": {
|
|
253
|
+
"format": { "enum": ["json", "srt", "text", "vtt"] }
|
|
254
|
+
}
|
|
189
255
|
}
|
|
190
256
|
}
|
|
191
257
|
},
|
|
@@ -80,7 +80,7 @@ const evidenceBlock = (
|
|
|
80
80
|
item: ContextCapsuleV1["evidence"][number]
|
|
81
81
|
): string[] => {
|
|
82
82
|
const metadata = [
|
|
83
|
-
`{"title":${json(item.title)},"heading":${json(item.heading)}}`,
|
|
83
|
+
`{"title":${json(item.title)},"heading":${json(item.heading)},"record":${json(item.record ?? null)}}`,
|
|
84
84
|
"configuredContexts:",
|
|
85
85
|
...configuredContextLines(capsule, item.contextIds).map((line) =>
|
|
86
86
|
line.startsWith(" ") ? line.slice(4) : line
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { ContextCanonicalProjection } from "../core/context-budget";
|
|
4
4
|
import type { ContextCapsuleV1 } from "../core/context-capsule";
|
|
5
5
|
import type { ContextCapabilityState } from "../core/context-capsule-retrieval-schema";
|
|
6
|
-
import type {
|
|
6
|
+
import type { ContextCapsulePayloadV1_1 } from "../core/context-capsule-schema";
|
|
7
7
|
import type { ContextCanonicalPlanDraft } from "../core/context-compiler";
|
|
8
8
|
import type { ContextEvidenceValue } from "../core/context-evidence";
|
|
9
9
|
import type { NormalizedContextBuildInput } from "./context-runtime-input";
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
toContextCapsuleEvidence,
|
|
20
20
|
} from "../core/context-evidence";
|
|
21
21
|
import { canonicalVerifierJson } from "../core/context-verifier-canonical";
|
|
22
|
+
import { mergeEgressLineages } from "../core/egress-provenance";
|
|
22
23
|
import { resolveModelUri } from "../llm/registry";
|
|
23
24
|
|
|
24
25
|
const fingerprint = (value: unknown): string =>
|
|
@@ -104,13 +105,13 @@ const capsuleCapabilities = (
|
|
|
104
105
|
graphExpansion: states.graphExpansion.outcome === "used",
|
|
105
106
|
exactTokenCount: exactTokens,
|
|
106
107
|
configuredContext,
|
|
107
|
-
egressPolicy:
|
|
108
|
+
egressPolicy: true,
|
|
108
109
|
});
|
|
109
110
|
|
|
110
111
|
const capsuleFallbacks = (
|
|
111
112
|
capabilities: ReturnType<typeof capsuleCapabilities>,
|
|
112
113
|
states: ReturnType<typeof capsuleCapabilityStates>
|
|
113
|
-
):
|
|
114
|
+
): ContextCapsulePayloadV1_1["fallbacks"] => [
|
|
114
115
|
...(states.semanticSearch.outcome === "unavailable"
|
|
115
116
|
? [
|
|
116
117
|
{
|
|
@@ -143,12 +144,15 @@ const capsuleFallbacks = (
|
|
|
143
144
|
capability: "token_count" as const,
|
|
144
145
|
},
|
|
145
146
|
]),
|
|
146
|
-
{ code: "egress_policy_unavailable", capability: "egress_policy" },
|
|
147
147
|
];
|
|
148
148
|
|
|
149
149
|
export const projectContextCapsule = (
|
|
150
150
|
draft: ContextCanonicalPlanDraft<ContextEvidenceValue>,
|
|
151
|
-
snapshots: {
|
|
151
|
+
snapshots: {
|
|
152
|
+
indexFingerprint: string;
|
|
153
|
+
contextFingerprint: string;
|
|
154
|
+
egressLineage: ContextCapsulePayloadV1_1["egressLineage"];
|
|
155
|
+
},
|
|
152
156
|
input: NormalizedContextBuildInput,
|
|
153
157
|
deps: ContextCapsuleRuntimeDeps
|
|
154
158
|
): ContextCanonicalProjection<ContextCapsuleV1> | null => {
|
|
@@ -156,6 +160,10 @@ export const projectContextCapsule = (
|
|
|
156
160
|
const evidence = draft.selection.selected.map((candidate, index) =>
|
|
157
161
|
toContextCapsuleEvidence(candidate, index + 1)
|
|
158
162
|
);
|
|
163
|
+
const egressLineage = mergeEgressLineages([
|
|
164
|
+
snapshots.egressLineage,
|
|
165
|
+
...evidence.map((item) => item.egressLineage),
|
|
166
|
+
]);
|
|
159
167
|
const evidenceIdsByFacet = new Map<string, string[]>();
|
|
160
168
|
for (const item of evidence) {
|
|
161
169
|
for (const facet of item.facets) {
|
|
@@ -173,7 +181,7 @@ export const projectContextCapsule = (
|
|
|
173
181
|
draft.configuredContexts.length > 0
|
|
174
182
|
);
|
|
175
183
|
const base = {
|
|
176
|
-
schemaVersion: "1.
|
|
184
|
+
schemaVersion: "1.1" as const,
|
|
177
185
|
coordinateSpace: "canonical_mirror" as const,
|
|
178
186
|
goal: draft.goal,
|
|
179
187
|
query: draft.query,
|
|
@@ -213,7 +221,7 @@ export const projectContextCapsule = (
|
|
|
213
221
|
},
|
|
214
222
|
capabilities,
|
|
215
223
|
};
|
|
216
|
-
const payload:
|
|
224
|
+
const payload: ContextCapsulePayloadV1_1 = {
|
|
217
225
|
...base,
|
|
218
226
|
budget: {
|
|
219
227
|
authority: "canonical_json",
|
|
@@ -246,6 +254,7 @@ export const projectContextCapsule = (
|
|
|
246
254
|
instructionBoundary: "hard_delimited",
|
|
247
255
|
configuredContexts: draft.configuredContexts,
|
|
248
256
|
},
|
|
257
|
+
egressLineage,
|
|
249
258
|
evidence,
|
|
250
259
|
coverage: {
|
|
251
260
|
complete: draft.selection.coverage.unresolvedFacets.length === 0,
|
package/src/cli/commands/ask.ts
CHANGED
|
@@ -165,6 +165,9 @@ export async function ask(
|
|
|
165
165
|
}
|
|
166
166
|
traceSession = traceStart.value ?? undefined;
|
|
167
167
|
const llm = new LlmAdapter(config);
|
|
168
|
+
const egressCollections = options.collection
|
|
169
|
+
? [options.collection]
|
|
170
|
+
: ("all" as const);
|
|
168
171
|
|
|
169
172
|
// Resolve download policy from env/flags
|
|
170
173
|
const policy = resolveDownloadPolicy(process.env, {
|
|
@@ -179,6 +182,7 @@ export async function ask(
|
|
|
179
182
|
|
|
180
183
|
// Create embedding port
|
|
181
184
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
185
|
+
egressCollections,
|
|
182
186
|
policy,
|
|
183
187
|
onProgress: downloadProgress
|
|
184
188
|
? (progress) => downloadProgress("embed", progress)
|
|
@@ -191,6 +195,7 @@ export async function ask(
|
|
|
191
195
|
// Create expansion port when expansion is enabled.
|
|
192
196
|
if (expandUri) {
|
|
193
197
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
198
|
+
egressCollections,
|
|
194
199
|
policy,
|
|
195
200
|
onProgress: downloadProgress
|
|
196
201
|
? (progress) => downloadProgress("expand", progress)
|
|
@@ -204,6 +209,7 @@ export async function ask(
|
|
|
204
209
|
// Create answer generation port when answers are requested.
|
|
205
210
|
if (answerUri) {
|
|
206
211
|
const genResult = await llm.createGenerationPort(answerUri, {
|
|
212
|
+
egressCollections,
|
|
207
213
|
policy,
|
|
208
214
|
onProgress: downloadProgress
|
|
209
215
|
? (progress) => downloadProgress("gen", progress)
|
|
@@ -217,6 +223,7 @@ export async function ask(
|
|
|
217
223
|
// Create rerank port (unless --fast or --no-rerank)
|
|
218
224
|
if (rerankUri) {
|
|
219
225
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
226
|
+
egressCollections,
|
|
220
227
|
policy,
|
|
221
228
|
onProgress: downloadProgress
|
|
222
229
|
? (progress) => downloadProgress("rerank", progress)
|
|
@@ -7,5 +7,10 @@
|
|
|
7
7
|
export { collectionAdd } from "./add";
|
|
8
8
|
export { collectionClearEmbeddings } from "./clear-embeddings";
|
|
9
9
|
export { collectionList } from "./list";
|
|
10
|
+
export {
|
|
11
|
+
collectionPolicyCheck,
|
|
12
|
+
collectionPolicyGet,
|
|
13
|
+
collectionPolicySet,
|
|
14
|
+
} from "./policy";
|
|
10
15
|
export { collectionRemove } from "./remove";
|
|
11
16
|
export { collectionRename } from "./rename";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/** Collection egress policy management commands. */
|
|
2
|
+
|
|
3
|
+
import type { EgressPolicy } from "../../../config/types";
|
|
4
|
+
import type {
|
|
5
|
+
EgressAction,
|
|
6
|
+
EgressContentClass,
|
|
7
|
+
EgressDestinationZone,
|
|
8
|
+
} from "../../../core/egress-policy";
|
|
9
|
+
|
|
10
|
+
import { loadConfig } from "../../../config";
|
|
11
|
+
import { projectCollectionEgressPolicy } from "../../../core/collection-egress-policy-projection";
|
|
12
|
+
import { CollectionEgressPolicyService } from "../../../core/collection-egress-policy-service";
|
|
13
|
+
import { applyConfigChange } from "../../../core/config-mutation";
|
|
14
|
+
import { CliError } from "../../errors";
|
|
15
|
+
import { initStore } from "../shared";
|
|
16
|
+
|
|
17
|
+
interface PolicyOptions {
|
|
18
|
+
configPath?: string;
|
|
19
|
+
indexName?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const writeJson = (value: unknown): void => {
|
|
23
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const collectionPolicyGet = async (
|
|
27
|
+
name: string,
|
|
28
|
+
options: PolicyOptions = {}
|
|
29
|
+
): Promise<void> => {
|
|
30
|
+
const loaded = await loadConfig(options.configPath);
|
|
31
|
+
if (!loaded.ok) throw new CliError("RUNTIME", loaded.error.message);
|
|
32
|
+
const state = new CollectionEgressPolicyService({
|
|
33
|
+
getConfig: () => loaded.value,
|
|
34
|
+
}).get(name);
|
|
35
|
+
if (!state.ok) throw new CliError("VALIDATION", state.error);
|
|
36
|
+
writeJson(state.value);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const collectionPolicySet = async (
|
|
40
|
+
name: string,
|
|
41
|
+
policy: EgressPolicy,
|
|
42
|
+
options: PolicyOptions & { confirmRelaxation?: string } = {}
|
|
43
|
+
): Promise<void> => {
|
|
44
|
+
const initialized = await initStore({
|
|
45
|
+
configPath: options.configPath,
|
|
46
|
+
indexName: options.indexName,
|
|
47
|
+
});
|
|
48
|
+
if (!initialized.ok) throw new CliError("RUNTIME", initialized.error);
|
|
49
|
+
let config = initialized.config;
|
|
50
|
+
try {
|
|
51
|
+
const currentResult = new CollectionEgressPolicyService({
|
|
52
|
+
getConfig: () => config,
|
|
53
|
+
}).get(name);
|
|
54
|
+
const service = new CollectionEgressPolicyService({
|
|
55
|
+
getConfig: () => config,
|
|
56
|
+
mutateConfig: async (mutate) => {
|
|
57
|
+
const result = await applyConfigChange(
|
|
58
|
+
{
|
|
59
|
+
store: initialized.store,
|
|
60
|
+
configPath: initialized.actualConfigPath,
|
|
61
|
+
onConfigUpdated: (next) => {
|
|
62
|
+
config = next;
|
|
63
|
+
},
|
|
64
|
+
projectStore: (store, next) =>
|
|
65
|
+
projectCollectionEgressPolicy(store, next, name),
|
|
66
|
+
},
|
|
67
|
+
mutate
|
|
68
|
+
);
|
|
69
|
+
return result;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
const result = await service.set({
|
|
73
|
+
collection: name,
|
|
74
|
+
policy,
|
|
75
|
+
confirmation:
|
|
76
|
+
currentResult.ok && options.confirmRelaxation
|
|
77
|
+
? {
|
|
78
|
+
collection: currentResult.value.collection,
|
|
79
|
+
currentPolicy: currentResult.value.effectivePolicy,
|
|
80
|
+
currentRevision: Number(options.confirmRelaxation),
|
|
81
|
+
targetPolicy: policy,
|
|
82
|
+
acknowledged: true,
|
|
83
|
+
}
|
|
84
|
+
: undefined,
|
|
85
|
+
});
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
throw new CliError("VALIDATION", result.error, {
|
|
88
|
+
details: { policyCode: result.code },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
writeJson(result.value);
|
|
92
|
+
} finally {
|
|
93
|
+
await initialized.store.close();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const collectionPolicyCheck = async (
|
|
98
|
+
input: {
|
|
99
|
+
collections?: string[];
|
|
100
|
+
action: EgressAction;
|
|
101
|
+
destinationZone: EgressDestinationZone;
|
|
102
|
+
contentClass: EgressContentClass;
|
|
103
|
+
authenticated: boolean;
|
|
104
|
+
authorized: boolean;
|
|
105
|
+
partial?: boolean;
|
|
106
|
+
},
|
|
107
|
+
options: PolicyOptions = {}
|
|
108
|
+
): Promise<void> => {
|
|
109
|
+
const loaded = await loadConfig(options.configPath);
|
|
110
|
+
if (!loaded.ok) throw new CliError("RUNTIME", loaded.error.message);
|
|
111
|
+
const result = new CollectionEgressPolicyService({
|
|
112
|
+
getConfig: () => loaded.value,
|
|
113
|
+
}).explain({
|
|
114
|
+
collections: input.collections,
|
|
115
|
+
action: input.action,
|
|
116
|
+
destinationZone: input.destinationZone,
|
|
117
|
+
caller: {
|
|
118
|
+
authenticated: input.authenticated,
|
|
119
|
+
operationAuthorized: input.authorized,
|
|
120
|
+
},
|
|
121
|
+
contentClass: input.contentClass,
|
|
122
|
+
partialResults: input.partial ? "explicit" : "deny",
|
|
123
|
+
});
|
|
124
|
+
if (!result.ok) throw new CliError("VALIDATION", result.error);
|
|
125
|
+
writeJson(result.value);
|
|
126
|
+
};
|
|
@@ -149,7 +149,11 @@ export const contextBuild = async (
|
|
|
149
149
|
const progress = showProgress
|
|
150
150
|
? createThrottledProgressRenderer(createProgressRenderer())
|
|
151
151
|
: undefined;
|
|
152
|
+
const egressCollections = options.collections?.length
|
|
153
|
+
? options.collections
|
|
154
|
+
: ("all" as const);
|
|
152
155
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
156
|
+
egressCollections,
|
|
153
157
|
policy,
|
|
154
158
|
onProgress: progress ? (value) => progress("embed", value) : undefined,
|
|
155
159
|
});
|
|
@@ -165,6 +169,7 @@ export const contextBuild = async (
|
|
|
165
169
|
}
|
|
166
170
|
}
|
|
167
171
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
172
|
+
egressCollections,
|
|
168
173
|
policy,
|
|
169
174
|
onProgress: progress ? (value) => progress("rerank", value) : undefined,
|
|
170
175
|
});
|
|
@@ -3,6 +3,11 @@ import type { HttpGatewayOverrides } from "../../mcp/http-security";
|
|
|
3
3
|
import type { BackgroundRuntimeResult } from "../../serve/background-runtime";
|
|
4
4
|
import type { ResidentRuntime } from "../../serve/resident-runtime";
|
|
5
5
|
|
|
6
|
+
import {
|
|
7
|
+
enforceCollectionEgress,
|
|
8
|
+
EGRESS_DENIED_MESSAGE,
|
|
9
|
+
EgressDeniedError,
|
|
10
|
+
} from "../../core/egress-enforcement";
|
|
6
11
|
import {
|
|
7
12
|
DEFAULT_HTTP_GATEWAY_PORT,
|
|
8
13
|
isHttpGatewayLoopbackBind,
|
|
@@ -42,6 +47,40 @@ function formatCollectionSyncSummary(result: CollectionSyncResult): string {
|
|
|
42
47
|
return `${result.collection}: ${result.filesAdded} added, ${result.filesUpdated} updated, ${result.filesUnchanged} unchanged, ${result.filesErrored} errors`;
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
export const authorizeDaemonStatus = async (
|
|
51
|
+
runtime: ResidentRuntime,
|
|
52
|
+
gateway: Awaited<ReturnType<typeof createMcpHttpGateway>>,
|
|
53
|
+
request: Request,
|
|
54
|
+
server: Parameters<typeof gateway.route>[1]
|
|
55
|
+
): Promise<Response> => {
|
|
56
|
+
const authorization = await gateway.security.authorize(request, server);
|
|
57
|
+
if (!authorization.ok) return authorization.response;
|
|
58
|
+
try {
|
|
59
|
+
enforceCollectionEgress({
|
|
60
|
+
collections: runtime.config.collections,
|
|
61
|
+
action: "serve",
|
|
62
|
+
destinationZone: authorization.value.peerClassification.zone,
|
|
63
|
+
caller: {
|
|
64
|
+
authenticated: authorization.value.authenticated,
|
|
65
|
+
operationAuthorized: true,
|
|
66
|
+
},
|
|
67
|
+
contentClass: "metadata",
|
|
68
|
+
});
|
|
69
|
+
return handleResidentStatus(() => runtime.getStatus());
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (!(error instanceof EgressDeniedError)) throw error;
|
|
72
|
+
return Response.json(
|
|
73
|
+
{
|
|
74
|
+
error: "EGRESS_DENIED",
|
|
75
|
+
message: EGRESS_DENIED_MESSAGE,
|
|
76
|
+
reason: error.decision.reason,
|
|
77
|
+
audit: error.decision.audit,
|
|
78
|
+
},
|
|
79
|
+
{ status: 403 }
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
45
84
|
export function handleDaemonAppStatus(
|
|
46
85
|
runtime: ResidentRuntime,
|
|
47
86
|
host: string
|
|
@@ -161,9 +200,12 @@ export async function daemon(
|
|
|
161
200
|
),
|
|
162
201
|
},
|
|
163
202
|
"/api/resident/status": {
|
|
164
|
-
GET: () =>
|
|
165
|
-
|
|
166
|
-
|
|
203
|
+
GET: (request, peerServer) =>
|
|
204
|
+
authorizeDaemonStatus(
|
|
205
|
+
runtime as ResidentRuntime,
|
|
206
|
+
gateway as Awaited<ReturnType<typeof createMcpHttpGateway>>,
|
|
207
|
+
request,
|
|
208
|
+
peerServer
|
|
167
209
|
),
|
|
168
210
|
},
|
|
169
211
|
},
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Local, content-free egress audit management commands. */
|
|
2
|
+
|
|
3
|
+
import { EgressAuditService } from "../../core/egress-audit";
|
|
4
|
+
import { CliError } from "../errors";
|
|
5
|
+
import { initStore } from "./shared";
|
|
6
|
+
|
|
7
|
+
interface AuditOptions {
|
|
8
|
+
configPath?: string;
|
|
9
|
+
indexName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const run = async (
|
|
13
|
+
options: AuditOptions,
|
|
14
|
+
operation: (service: EgressAuditService) => Promise<unknown>
|
|
15
|
+
): Promise<void> => {
|
|
16
|
+
const initialized = await initStore({
|
|
17
|
+
configPath: options.configPath,
|
|
18
|
+
indexName: options.indexName,
|
|
19
|
+
syncConfig: false,
|
|
20
|
+
allowEmptyCollections: true,
|
|
21
|
+
});
|
|
22
|
+
if (!initialized.ok) throw new CliError("RUNTIME", initialized.error);
|
|
23
|
+
try {
|
|
24
|
+
const result = await operation(new EgressAuditService(initialized.store));
|
|
25
|
+
if (
|
|
26
|
+
typeof result === "object" &&
|
|
27
|
+
result !== null &&
|
|
28
|
+
"ok" in result &&
|
|
29
|
+
!(result as { ok: boolean }).ok
|
|
30
|
+
) {
|
|
31
|
+
const failure = result as {
|
|
32
|
+
ok: false;
|
|
33
|
+
error: { code: string; message: string };
|
|
34
|
+
};
|
|
35
|
+
throw new CliError("RUNTIME", failure.error.message, {
|
|
36
|
+
details: { auditCode: failure.error.code },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const value =
|
|
40
|
+
typeof result === "object" && result !== null && "value" in result
|
|
41
|
+
? (result as { value: unknown }).value
|
|
42
|
+
: result;
|
|
43
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
44
|
+
} finally {
|
|
45
|
+
await initialized.store.close();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const egressAuditList = (
|
|
50
|
+
input: { limit?: number; cursor?: string },
|
|
51
|
+
options: AuditOptions = {}
|
|
52
|
+
): Promise<void> => run(options, (service) => service.list(input));
|
|
53
|
+
|
|
54
|
+
export const egressAuditShow = (
|
|
55
|
+
auditId: string,
|
|
56
|
+
options: AuditOptions = {}
|
|
57
|
+
): Promise<void> => run(options, (service) => service.show(auditId));
|
|
58
|
+
|
|
59
|
+
export const egressAuditStatus = (options: AuditOptions = {}): Promise<void> =>
|
|
60
|
+
run(options, (service) => service.status());
|
|
61
|
+
|
|
62
|
+
export const egressAuditDelete = (
|
|
63
|
+
auditId: string,
|
|
64
|
+
options: AuditOptions = {}
|
|
65
|
+
): Promise<void> => run(options, (service) => service.delete(auditId));
|
|
66
|
+
|
|
67
|
+
export const egressAuditPurge = (options: AuditOptions = {}): Promise<void> =>
|
|
68
|
+
run(options, (service) => service.purge());
|