@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.
Files changed (195) hide show
  1. package/README.md +46 -20
  2. package/assets/skill/SKILL.md +59 -1
  3. package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip +0 -0
  4. package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip.sha256 +1 -0
  5. package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
  6. package/browser-extension/dist/manifest.json +1 -1
  7. package/browser-extension/dist/preview.html +1 -1
  8. package/browser-extension/dist/service-worker.js +6 -6
  9. package/package.json +2 -2
  10. package/spec/cli.md +82 -5
  11. package/spec/db/schema.sql +31 -0
  12. package/spec/mcp.md +71 -0
  13. package/spec/output-schemas/ask.schema.json +156 -1
  14. package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
  15. package/spec/output-schemas/collection-egress-check.schema.json +91 -0
  16. package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
  17. package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
  18. package/spec/output-schemas/context-capsule-v1.schema.json +183 -3
  19. package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
  20. package/spec/output-schemas/egress-audit-management.schema.json +88 -0
  21. package/spec/output-schemas/get.schema.json +94 -0
  22. package/spec/output-schemas/mcp-http-error.schema.json +113 -2
  23. package/spec/output-schemas/mcp-job-status.schema.json +28 -0
  24. package/spec/output-schemas/multi-get.schema.json +128 -0
  25. package/spec/output-schemas/publish-artifact.schema.json +32 -0
  26. package/spec/output-schemas/record-import.schema.json +223 -0
  27. package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
  28. package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
  29. package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
  30. package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
  31. package/spec/output-schemas/search-result.schema.json +94 -0
  32. package/spec/output-schemas/search-results.schema.json +155 -0
  33. package/spec/project-profile.schema.json +66 -0
  34. package/src/app/context-format.ts +1 -1
  35. package/src/app/context-runtime-contract.ts +16 -7
  36. package/src/cli/commands/ask.ts +7 -0
  37. package/src/cli/commands/collection/index.ts +5 -0
  38. package/src/cli/commands/collection/policy.ts +126 -0
  39. package/src/cli/commands/context-build.ts +5 -0
  40. package/src/cli/commands/daemon.ts +45 -3
  41. package/src/cli/commands/egress-audit.ts +68 -0
  42. package/src/cli/commands/embed.ts +2 -0
  43. package/src/cli/commands/get.ts +12 -2
  44. package/src/cli/commands/index-cmd.ts +13 -0
  45. package/src/cli/commands/multi-get.ts +9 -2
  46. package/src/cli/commands/query.ts +12 -0
  47. package/src/cli/commands/replay.ts +13 -3
  48. package/src/cli/commands/shared.ts +28 -0
  49. package/src/cli/commands/update.ts +5 -0
  50. package/src/cli/commands/vsearch.ts +3 -1
  51. package/src/cli/program.ts +127 -0
  52. package/src/config/index.ts +9 -0
  53. package/src/config/project-profile.ts +2 -0
  54. package/src/config/types.ts +66 -0
  55. package/src/converters/adapters/browser-export/adapter.ts +199 -0
  56. package/src/converters/adapters/browser-export/formats.ts +358 -0
  57. package/src/converters/adapters/email/adapter.ts +429 -0
  58. package/src/converters/adapters/email/html.ts +162 -0
  59. package/src/converters/adapters/email/mime.ts +454 -0
  60. package/src/converters/adapters/email/parameters.ts +77 -0
  61. package/src/converters/adapters/ical/adapter.ts +475 -0
  62. package/src/converters/adapters/ical/recurrence.ts +186 -0
  63. package/src/converters/adapters/jsonl/adapter.ts +238 -0
  64. package/src/converters/adapters/jsonl/config.ts +105 -0
  65. package/src/converters/adapters/shared/html-text.ts +165 -0
  66. package/src/converters/adapters/shared/record-utils.ts +79 -0
  67. package/src/converters/adapters/shared/utf8-lines.ts +141 -0
  68. package/src/converters/adapters/transcript/adapter.ts +295 -0
  69. package/src/converters/adapters/transcript/json.ts +184 -0
  70. package/src/converters/adapters/transcript/model.ts +171 -0
  71. package/src/converters/adapters/transcript/text.ts +58 -0
  72. package/src/converters/adapters/transcript/timed.ts +152 -0
  73. package/src/converters/index.ts +11 -1
  74. package/src/converters/mime.ts +8 -0
  75. package/src/converters/pipeline.ts +15 -1
  76. package/src/converters/registry.ts +37 -1
  77. package/src/converters/types.ts +136 -0
  78. package/src/core/browser-clip.ts +16 -1
  79. package/src/core/collection-egress-policy-projection.ts +28 -0
  80. package/src/core/collection-egress-policy-service.ts +443 -0
  81. package/src/core/collection-egress-policy-validation.ts +242 -0
  82. package/src/core/config-mutation.ts +31 -19
  83. package/src/core/context-capsule-schema.ts +198 -1
  84. package/src/core/context-capsule-validation.ts +4 -4
  85. package/src/core/context-capsule-verification.ts +5 -1
  86. package/src/core/context-capsule.ts +177 -112
  87. package/src/core/context-evidence.ts +93 -15
  88. package/src/core/destination-classifier.ts +402 -0
  89. package/src/core/document-capabilities.ts +12 -0
  90. package/src/core/egress-audit.ts +239 -0
  91. package/src/core/egress-authorization.ts +50 -0
  92. package/src/core/egress-enforcement.ts +264 -0
  93. package/src/core/egress-policy.ts +440 -0
  94. package/src/core/egress-provenance.ts +336 -0
  95. package/src/core/job-manager.ts +37 -0
  96. package/src/core/network-boundary-inventory.ts +261 -0
  97. package/src/core/project-profile-apply-state.ts +5 -0
  98. package/src/core/project-profile.ts +4 -0
  99. package/src/core/record-metadata.ts +49 -0
  100. package/src/core/retrieval-qrels.ts +6 -0
  101. package/src/core/retrieval-replay.ts +18 -4
  102. package/src/core/retrieval-trace-export.ts +23 -4
  103. package/src/core/retrieval-trace-management-helpers.ts +1 -0
  104. package/src/core/retrieval-trace-management-types.ts +3 -0
  105. package/src/core/retrieval-trace-management.ts +9 -1
  106. package/src/core/retrieval-trace-session.ts +94 -0
  107. package/src/core/retrieval-trace.ts +22 -0
  108. package/src/ingestion/record-adapter-canonical.ts +433 -0
  109. package/src/ingestion/record-adapter.ts +448 -0
  110. package/src/ingestion/record-container.ts +704 -0
  111. package/src/ingestion/record-path.ts +20 -0
  112. package/src/ingestion/record-sync.ts +70 -0
  113. package/src/ingestion/sync.ts +243 -36
  114. package/src/ingestion/types.ts +71 -1
  115. package/src/ingestion/walker.ts +31 -11
  116. package/src/llm/errors.ts +10 -0
  117. package/src/llm/http-inference.ts +175 -0
  118. package/src/llm/http-policy.ts +537 -0
  119. package/src/llm/httpEmbedding.ts +47 -28
  120. package/src/llm/httpGeneration.ts +31 -18
  121. package/src/llm/httpRerank.ts +30 -18
  122. package/src/llm/index.ts +1 -0
  123. package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
  124. package/src/llm/pinned-http-connection.ts +177 -0
  125. package/src/mcp/context.ts +53 -1
  126. package/src/mcp/http-egress.ts +220 -0
  127. package/src/mcp/http-security.ts +32 -21
  128. package/src/mcp/http-session.ts +13 -2
  129. package/src/mcp/http-transport.ts +96 -6
  130. package/src/mcp/sync-egress.ts +24 -0
  131. package/src/mcp/tools/add-collection.ts +4 -0
  132. package/src/mcp/tools/ask.ts +1 -1
  133. package/src/mcp/tools/context.ts +9 -2
  134. package/src/mcp/tools/egress.ts +247 -0
  135. package/src/mcp/tools/embed.ts +1 -0
  136. package/src/mcp/tools/get.ts +10 -2
  137. package/src/mcp/tools/index-cmd.ts +7 -0
  138. package/src/mcp/tools/index.ts +98 -0
  139. package/src/mcp/tools/multi-get.ts +9 -2
  140. package/src/mcp/tools/query.ts +10 -0
  141. package/src/mcp/tools/remove-collection.ts +4 -0
  142. package/src/mcp/tools/sync.ts +6 -0
  143. package/src/mcp/tools/trace.ts +7 -1
  144. package/src/mcp/tools/vsearch.ts +1 -0
  145. package/src/mcp/tools/workspace-write.ts +2 -0
  146. package/src/pipeline/egress-lineage.ts +124 -0
  147. package/src/pipeline/filters.ts +1 -1
  148. package/src/pipeline/graph-retrieval.ts +7 -4
  149. package/src/pipeline/hybrid.ts +21 -4
  150. package/src/pipeline/result-context.ts +12 -4
  151. package/src/pipeline/search.ts +23 -4
  152. package/src/pipeline/types.ts +6 -0
  153. package/src/pipeline/vsearch.ts +67 -28
  154. package/src/publish/artifact.ts +31 -3
  155. package/src/publish/export-service.ts +25 -0
  156. package/src/sdk/client.ts +119 -2
  157. package/src/sdk/documents.ts +13 -5
  158. package/src/sdk/embed.ts +1 -0
  159. package/src/sdk/types.ts +33 -0
  160. package/src/serve/browse-tree.ts +4 -2
  161. package/src/serve/clipper-capture.ts +5 -1
  162. package/src/serve/closed-json.ts +61 -0
  163. package/src/serve/config-sync.ts +4 -1
  164. package/src/serve/context.ts +1 -0
  165. package/src/serve/doc-events.ts +110 -39
  166. package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
  167. package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
  168. package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
  169. package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
  170. package/src/serve/public/globals.built.css +1 -1
  171. package/src/serve/public/pages/Collections.tsx +3 -0
  172. package/src/serve/resident-request.ts +80 -3
  173. package/src/serve/resident-runtime.ts +63 -1
  174. package/src/serve/routes/api.ts +237 -65
  175. package/src/serve/routes/clipper.ts +64 -1
  176. package/src/serve/routes/mcp.ts +6 -0
  177. package/src/serve/routes/traces.ts +27 -4
  178. package/src/serve/server.ts +118 -7
  179. package/src/store/migrations/022-record-export-lineage.ts +42 -0
  180. package/src/store/migrations/023-collection-egress-policy.ts +61 -0
  181. package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
  182. package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
  183. package/src/store/migrations/index.ts +8 -0
  184. package/src/store/retrieval-trace-codec.ts +15 -0
  185. package/src/store/sqlite/adapter.ts +284 -14
  186. package/src/store/sqlite/change-journal-store.ts +41 -2
  187. package/src/store/sqlite/egress-audit-store.ts +485 -0
  188. package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
  189. package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
  190. package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
  191. package/src/store/sqlite/retrieval-trace-store.ts +104 -5
  192. package/src/store/types.ts +166 -1
  193. package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip +0 -0
  194. package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip.sha256 +0 -1
  195. package/browser-extension/dist/chunk-vn5f663b.js +0 -50
@@ -21,6 +21,7 @@ import type { SkippedEntry, WalkConfig, WalkEntry, WalkerPort } from "./types";
21
21
 
22
22
  import { SUPPORTED_EXTENSIONS } from "../converters/mime";
23
23
  import { matchesCollectionExclusion } from "../core/path-rules";
24
+ import { isRecordVirtualPath } from "./record-path";
24
25
 
25
26
  /**
26
27
  * Regex to detect dangerous patterns with parent directory traversal.
@@ -124,7 +125,7 @@ function scanPatterns(pattern: string): string[] {
124
125
  async function safeRelPath(
125
126
  rootReal: string,
126
127
  absPath: string
127
- ): Promise<string | null> {
128
+ ): Promise<{ absPath: string; relPath: string } | null> {
128
129
  try {
129
130
  const fileReal = await realpath(absPath);
130
131
  const rel = relative(rootReal, fileReal);
@@ -135,7 +136,7 @@ async function safeRelPath(
135
136
  return null;
136
137
  }
137
138
 
138
- return toPosixPath(rel);
139
+ return { absPath: fileReal, relPath: toPosixPath(rel) };
139
140
  } catch {
140
141
  // Can't resolve path (e.g., broken symlink)
141
142
  return null;
@@ -145,18 +146,25 @@ async function safeRelPath(
145
146
  /**
146
147
  * Check if a file extension matches the include list.
147
148
  * Include list contains extensions like ".md" or "md" (normalized).
148
- * When include is empty, falls back to SUPPORTED_EXTENSIONS to avoid
149
- * walking files that can't be converted.
149
+ * When include is empty, falls back to SUPPORTED_EXTENSIONS plus extensions
150
+ * made convertible by explicit adapter configuration.
150
151
  */
151
- function matchesInclude(relPath: string, include: string[]): boolean {
152
+ function matchesInclude(
153
+ relPath: string,
154
+ include: string[],
155
+ additionalDefaultExtensions: string[]
156
+ ): boolean {
152
157
  const ext = extname(relPath).toLowerCase();
153
158
  if (!ext) {
154
159
  return false;
155
160
  }
156
161
 
157
- // Fallback to supported extensions when no explicit include list
162
+ if (include.length === 0 && SUPPORTED_EXTENSIONS.includes(ext)) {
163
+ return true;
164
+ }
165
+
158
166
  const effectiveInclude =
159
- include.length === 0 ? SUPPORTED_EXTENSIONS : include;
167
+ include.length === 0 ? additionalDefaultExtensions : include;
160
168
 
161
169
  return effectiveInclude.some((inc) => {
162
170
  const normalizedInc = inc.startsWith(".")
@@ -211,13 +219,19 @@ export class FileWalker implements WalkerPort {
211
219
  }
212
220
  }
213
221
 
214
- for (const absPath of [...matches].sort()) {
222
+ for (const matchedPath of [...matches].sort()) {
215
223
  // Security: Compute safe relative path (validates file is within root)
216
- const relPath = await safeRelPath(rootReal, absPath);
217
- if (relPath === null) {
224
+ const safePath = await safeRelPath(rootReal, matchedPath);
225
+ if (safePath === null) {
218
226
  // File outside root or unresolvable - silently skip (security)
219
227
  continue;
220
228
  }
229
+ const { absPath, relPath } = safePath;
230
+
231
+ if (isRecordVirtualPath(relPath)) {
232
+ skipped.push({ absPath, relPath, reason: "EXCLUDED" });
233
+ continue;
234
+ }
221
235
 
222
236
  // Check exclude patterns
223
237
  if (matchesCollectionExclusion(relPath, config.exclude)) {
@@ -230,7 +244,13 @@ export class FileWalker implements WalkerPort {
230
244
  }
231
245
 
232
246
  // Check include extensions
233
- if (!matchesInclude(relPath, config.include)) {
247
+ if (
248
+ !matchesInclude(
249
+ relPath,
250
+ config.include,
251
+ config.additionalDefaultExtensions ?? []
252
+ )
253
+ ) {
234
254
  skipped.push({
235
255
  absPath,
236
256
  relPath,
package/src/llm/errors.ts CHANGED
@@ -18,6 +18,7 @@ export type LlmErrorCode =
18
18
  | "INVALID_MODEL_FILE"
19
19
  | "MODEL_DOWNLOAD_INTERCEPTED"
20
20
  | "INFERENCE_FAILED"
21
+ | "EGRESS_DENIED"
21
22
  | "TIMEOUT"
22
23
  | "OUT_OF_MEMORY"
23
24
  | "INVALID_URI"
@@ -202,6 +203,15 @@ export function inferenceFailedError(uri: string, cause?: unknown): LlmError {
202
203
  });
203
204
  }
204
205
 
206
+ export function egressDeniedInferenceError(cause?: unknown): LlmError {
207
+ return llmError("EGRESS_DENIED", {
208
+ message: "Operation blocked by collection egress policy",
209
+ retryable: false,
210
+ cause,
211
+ suggestion: "Review the collection egress policy and model destination.",
212
+ });
213
+ }
214
+
205
215
  export function timeoutError(
206
216
  uri: string,
207
217
  operation: "load" | "inference",
@@ -0,0 +1,175 @@
1
+ /** Policy-gated, DNS-pinned HTTP transport shared by inference adapters. */
2
+
3
+ import type { Collection } from "../config/types";
4
+ import type { CollectionEgressState } from "../core/egress-policy";
5
+ import type { EgressDestinationZone } from "../core/egress-policy";
6
+ import type {
7
+ HttpDestinationPolicyOptions,
8
+ HttpDestinationResolver,
9
+ PinnedHttpFetch,
10
+ } from "./http-policy";
11
+
12
+ import {
13
+ collectionEgressStates,
14
+ EgressDeniedError,
15
+ maximumDestinationZoneForCollections,
16
+ } from "../core/egress-enforcement";
17
+ import { evaluateEgressPolicy } from "../core/egress-policy";
18
+ import { EgressProvenanceError } from "../core/egress-provenance";
19
+ import { classifyHttpDestination, prepareHttpDestination } from "./http-policy";
20
+
21
+ const REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
22
+
23
+ export interface HttpInferenceOptions {
24
+ collections: readonly Collection[];
25
+ collectionNames: readonly string[];
26
+ authenticated?: boolean;
27
+ operationAuthorized?: boolean;
28
+ resolver?: HttpDestinationResolver;
29
+ fetchFn?: PinnedHttpFetch;
30
+ env?: HttpDestinationPolicyOptions["env"];
31
+ }
32
+
33
+ const scopedStates = (
34
+ options: HttpInferenceOptions
35
+ ): readonly CollectionEgressState[] => {
36
+ try {
37
+ return collectionEgressStates(options.collections, options.collectionNames);
38
+ } catch (error) {
39
+ if (error instanceof EgressProvenanceError) return [];
40
+ throw error;
41
+ }
42
+ };
43
+
44
+ const enforce = (
45
+ states: readonly CollectionEgressState[],
46
+ zone: EgressDestinationZone,
47
+ options: HttpInferenceOptions
48
+ ): void => {
49
+ const decision = evaluateEgressPolicy({
50
+ collections: states,
51
+ action: "remote_inference",
52
+ destination: { zone },
53
+ caller: {
54
+ authenticated: options.authenticated ?? true,
55
+ operationAuthorized: options.operationAuthorized ?? true,
56
+ },
57
+ contentClass: "source",
58
+ });
59
+ if (!decision.allowed) throw new EgressDeniedError(decision);
60
+ };
61
+
62
+ export const requestHttpInference = async (
63
+ rawUrl: string,
64
+ init: BunFetchRequestInit,
65
+ options: HttpInferenceOptions
66
+ ): Promise<Response> => {
67
+ const states = scopedStates(options);
68
+ if (states.length === 0) {
69
+ enforce(states, "remote", options);
70
+ }
71
+ const maximumZone = maximumDestinationZoneForCollections(
72
+ options.collections,
73
+ options.collectionNames
74
+ );
75
+
76
+ // DNS-only classification carries no headers, body, credentials, or model
77
+ // metadata. Policy evaluates the proven zone before transport preparation.
78
+ const classification = await classifyHttpDestination(rawUrl, {
79
+ resolver: options.resolver,
80
+ });
81
+ if (!classification.ok) {
82
+ throw new EgressDeniedError(
83
+ evaluateEgressPolicy({
84
+ collections: states,
85
+ action: "remote_inference",
86
+ destination: { zone: classification.classification.zone },
87
+ caller: {
88
+ authenticated: options.authenticated ?? true,
89
+ operationAuthorized: false,
90
+ },
91
+ contentClass: "source",
92
+ })
93
+ );
94
+ }
95
+ enforce(states, classification.classification.zone, options);
96
+ const url = new URL(rawUrl);
97
+
98
+ let prepared = await prepareHttpDestination(url.href, {
99
+ maximumZone,
100
+ resolver: options.resolver,
101
+ remoteProvider: classification.classification.zone === "remote",
102
+ env: options.env,
103
+ });
104
+ if (!prepared.ok) {
105
+ throw new EgressDeniedError(
106
+ evaluateEgressPolicy({
107
+ collections: states,
108
+ action: "remote_inference",
109
+ destination: { zone: prepared.classification.zone },
110
+ caller: {
111
+ authenticated: options.authenticated ?? true,
112
+ operationAuthorized: false,
113
+ },
114
+ contentClass: "source",
115
+ })
116
+ );
117
+ }
118
+
119
+ let currentUrl = url;
120
+ for (;;) {
121
+ enforce(states, prepared.value.classification.zone, options);
122
+ const connection = await prepared.value.acquireConnection();
123
+ if (!connection.ok) {
124
+ throw new EgressDeniedError(
125
+ evaluateEgressPolicy({
126
+ collections: states,
127
+ action: "remote_inference",
128
+ destination: { zone: connection.classification.zone },
129
+ caller: {
130
+ authenticated: options.authenticated ?? true,
131
+ operationAuthorized: false,
132
+ },
133
+ contentClass: "source",
134
+ })
135
+ );
136
+ }
137
+ const response = await connection.value.request(init, options.fetchFn);
138
+ if (!REDIRECT_STATUSES.has(response.status)) return response;
139
+
140
+ const location = response.headers.get("location");
141
+ if (!location) return response;
142
+ const nextUrl = new URL(location, currentUrl);
143
+ if (nextUrl.origin.toLowerCase() !== currentUrl.origin.toLowerCase()) {
144
+ throw new EgressDeniedError(
145
+ evaluateEgressPolicy({
146
+ collections: states,
147
+ action: "remote_inference",
148
+ destination: { zone: prepared.value.classification.zone },
149
+ caller: {
150
+ authenticated: options.authenticated ?? true,
151
+ operationAuthorized: false,
152
+ },
153
+ contentClass: "source",
154
+ })
155
+ );
156
+ }
157
+ const next = await prepared.value.followRedirect(nextUrl.href);
158
+ if (!next.ok) {
159
+ throw new EgressDeniedError(
160
+ evaluateEgressPolicy({
161
+ collections: states,
162
+ action: "remote_inference",
163
+ destination: { zone: next.classification.zone },
164
+ caller: {
165
+ authenticated: options.authenticated ?? true,
166
+ operationAuthorized: false,
167
+ },
168
+ contentClass: "source",
169
+ })
170
+ );
171
+ }
172
+ currentUrl = nextUrl;
173
+ prepared = next;
174
+ }
175
+ };