@gmickel/gno 1.27.1 → 1.28.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 (83) hide show
  1. package/README.md +2 -2
  2. package/assets/skill/SKILL.md +26 -1
  3. package/browser-extension/artifacts/{gno-browser-clipper-v1.27.1.zip → gno-browser-clipper-v1.28.0.zip} +0 -0
  4. package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip.sha256 +1 -0
  5. package/browser-extension/dist/manifest.json +1 -1
  6. package/package.json +2 -2
  7. package/spec/cli.md +41 -4
  8. package/spec/db/schema.sql +12 -0
  9. package/spec/mcp.md +5 -0
  10. package/spec/output-schemas/ask.schema.json +125 -0
  11. package/spec/output-schemas/context-capsule-v1.schema.json +94 -1
  12. package/spec/output-schemas/get.schema.json +94 -0
  13. package/spec/output-schemas/mcp-job-status.schema.json +28 -0
  14. package/spec/output-schemas/multi-get.schema.json +128 -0
  15. package/spec/output-schemas/record-import.schema.json +193 -0
  16. package/spec/output-schemas/search-result.schema.json +94 -0
  17. package/spec/output-schemas/search-results.schema.json +125 -0
  18. package/spec/project-profile.schema.json +66 -0
  19. package/src/app/context-format.ts +1 -1
  20. package/src/cli/commands/get.ts +12 -2
  21. package/src/cli/commands/index-cmd.ts +13 -0
  22. package/src/cli/commands/multi-get.ts +9 -2
  23. package/src/cli/commands/shared.ts +28 -0
  24. package/src/cli/commands/update.ts +5 -0
  25. package/src/cli/program.ts +4 -0
  26. package/src/config/project-profile.ts +2 -0
  27. package/src/config/types.ts +16 -0
  28. package/src/converters/adapters/browser-export/adapter.ts +199 -0
  29. package/src/converters/adapters/browser-export/formats.ts +358 -0
  30. package/src/converters/adapters/email/adapter.ts +429 -0
  31. package/src/converters/adapters/email/html.ts +162 -0
  32. package/src/converters/adapters/email/mime.ts +454 -0
  33. package/src/converters/adapters/email/parameters.ts +77 -0
  34. package/src/converters/adapters/ical/adapter.ts +475 -0
  35. package/src/converters/adapters/ical/recurrence.ts +186 -0
  36. package/src/converters/adapters/jsonl/adapter.ts +238 -0
  37. package/src/converters/adapters/jsonl/config.ts +105 -0
  38. package/src/converters/adapters/shared/html-text.ts +165 -0
  39. package/src/converters/adapters/shared/record-utils.ts +79 -0
  40. package/src/converters/adapters/shared/utf8-lines.ts +141 -0
  41. package/src/converters/adapters/transcript/adapter.ts +295 -0
  42. package/src/converters/adapters/transcript/json.ts +184 -0
  43. package/src/converters/adapters/transcript/model.ts +171 -0
  44. package/src/converters/adapters/transcript/text.ts +58 -0
  45. package/src/converters/adapters/transcript/timed.ts +152 -0
  46. package/src/converters/index.ts +11 -1
  47. package/src/converters/mime.ts +8 -0
  48. package/src/converters/pipeline.ts +15 -1
  49. package/src/converters/registry.ts +37 -1
  50. package/src/converters/types.ts +136 -0
  51. package/src/core/context-capsule-schema.ts +87 -0
  52. package/src/core/context-capsule.ts +20 -0
  53. package/src/core/context-evidence.ts +7 -1
  54. package/src/core/document-capabilities.ts +12 -0
  55. package/src/core/project-profile-apply-state.ts +5 -0
  56. package/src/core/project-profile.ts +4 -0
  57. package/src/core/record-metadata.ts +49 -0
  58. package/src/ingestion/record-adapter-canonical.ts +433 -0
  59. package/src/ingestion/record-adapter.ts +437 -0
  60. package/src/ingestion/record-container.ts +688 -0
  61. package/src/ingestion/record-path.ts +20 -0
  62. package/src/ingestion/record-sync.ts +70 -0
  63. package/src/ingestion/sync.ts +228 -36
  64. package/src/ingestion/types.ts +69 -1
  65. package/src/ingestion/walker.ts +31 -11
  66. package/src/mcp/tools/get.ts +10 -2
  67. package/src/mcp/tools/multi-get.ts +9 -2
  68. package/src/mcp/tools/workspace-write.ts +2 -0
  69. package/src/pipeline/filters.ts +1 -1
  70. package/src/pipeline/graph-retrieval.ts +7 -4
  71. package/src/pipeline/hybrid.ts +7 -4
  72. package/src/pipeline/result-context.ts +12 -4
  73. package/src/pipeline/search.ts +11 -4
  74. package/src/pipeline/types.ts +3 -0
  75. package/src/pipeline/vsearch.ts +26 -8
  76. package/src/sdk/documents.ts +13 -5
  77. package/src/serve/browse-tree.ts +4 -2
  78. package/src/serve/routes/api.ts +63 -65
  79. package/src/store/migrations/022-record-export-lineage.ts +42 -0
  80. package/src/store/migrations/index.ts +2 -0
  81. package/src/store/sqlite/adapter.ts +114 -7
  82. package/src/store/types.ts +40 -0
  83. package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip.sha256 +0 -1
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
 
3
3
  import { buildUri, deriveDocid, parseUri } from "../app/constants";
4
4
  import { isValidIndexName } from "../app/index-name";
5
+ import { RECORD_METADATA_LIMITS } from "../converters/types";
5
6
  import { contextCapsuleIndexSnapshotSchema } from "./context-capsule-index-schema";
6
7
  import { contextCapsuleRetrievalSchema } from "./context-capsule-retrieval-schema";
7
8
  import {
@@ -232,6 +233,91 @@ const guidanceSchema = z
232
233
  })
233
234
  .strict();
234
235
 
236
+ const recordAnchorSchema = z
237
+ .object({
238
+ kind: z.enum(["line", "cue", "timestamp", "message", "event", "record"]),
239
+ value: nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxAnchorChars),
240
+ endValue: nonEmptyTextSchema
241
+ .max(RECORD_METADATA_LIMITS.maxAnchorChars)
242
+ .optional(),
243
+ })
244
+ .strict();
245
+
246
+ const recordAttachmentSchema = z
247
+ .object({
248
+ name: nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxAttachmentNameChars),
249
+ mime: nonEmptyTextSchema
250
+ .max(RECORD_METADATA_LIMITS.maxAttachmentMimeChars)
251
+ .optional(),
252
+ bytes: nonNegativeIntegerSchema.optional(),
253
+ disposition: z.enum(["inline", "attachment"]).optional(),
254
+ sha256: sha256Schema.optional(),
255
+ })
256
+ .strict();
257
+
258
+ const recordEvidenceMetadataSchema = z
259
+ .object({
260
+ recordKey: sha256Schema,
261
+ sourceLocator: nonEmptyTextSchema.max(
262
+ RECORD_METADATA_LIMITS.maxAnchorChars
263
+ ),
264
+ anchors: z.array(recordAnchorSchema).max(RECORD_METADATA_LIMITS.maxItems),
265
+ adapter: z
266
+ .object({
267
+ id: nonEmptyTextSchema.max(128),
268
+ version: nonEmptyTextSchema.max(64),
269
+ fingerprint: sha256Schema,
270
+ })
271
+ .strict(),
272
+ author: textSchema.max(RECORD_METADATA_LIMITS.maxPersonChars).optional(),
273
+ participants: z
274
+ .array(nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxPersonChars))
275
+ .max(RECORD_METADATA_LIMITS.maxItems)
276
+ .optional(),
277
+ categories: z
278
+ .array(nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxCategoryChars))
279
+ .max(RECORD_METADATA_LIMITS.maxItems)
280
+ .optional(),
281
+ dateFields: z
282
+ .record(
283
+ z.string().max(RECORD_METADATA_LIMITS.maxDateFieldKeyChars),
284
+ nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxDateFieldValueChars)
285
+ )
286
+ .superRefine((value, context) => {
287
+ if (Object.keys(value).length > RECORD_METADATA_LIMITS.maxItems) {
288
+ context.addIssue({
289
+ code: "custom",
290
+ message: "too many record date fields",
291
+ });
292
+ }
293
+ })
294
+ .optional(),
295
+ messageId: textSchema
296
+ .max(RECORD_METADATA_LIMITS.maxIdentifierChars)
297
+ .optional(),
298
+ inReplyTo: textSchema
299
+ .max(RECORD_METADATA_LIMITS.maxIdentifierChars)
300
+ .optional(),
301
+ references: z
302
+ .array(nonEmptyTextSchema.max(RECORD_METADATA_LIMITS.maxIdentifierChars))
303
+ .max(RECORD_METADATA_LIMITS.maxItems)
304
+ .optional(),
305
+ threadId: textSchema
306
+ .max(RECORD_METADATA_LIMITS.maxIdentifierChars)
307
+ .optional(),
308
+ eventId: textSchema
309
+ .max(RECORD_METADATA_LIMITS.maxIdentifierChars)
310
+ .optional(),
311
+ sessionId: textSchema
312
+ .max(RECORD_METADATA_LIMITS.maxIdentifierChars)
313
+ .optional(),
314
+ attachments: z
315
+ .array(recordAttachmentSchema)
316
+ .max(RECORD_METADATA_LIMITS.maxItems)
317
+ .optional(),
318
+ })
319
+ .strict();
320
+
235
321
  export const contextCapsuleEvidenceSchema = z
236
322
  .object({
237
323
  evidenceId: sha256Schema,
@@ -270,6 +356,7 @@ export const contextCapsuleEvidenceSchema = z
270
356
  "unclassified",
271
357
  "unavailable",
272
358
  ]),
359
+ record: recordEvidenceMetadataSchema.optional(),
273
360
  })
274
361
  .strict()
275
362
  .superRefine((value, context) => {
@@ -129,6 +129,26 @@ const normalizePayload = (
129
129
  ),
130
130
  }),
131
131
  facets: normalizeSet(item.facets),
132
+ ...(item.record === undefined
133
+ ? {}
134
+ : {
135
+ record: {
136
+ ...item.record,
137
+ anchors: item.record.anchors.map((anchor) => ({
138
+ ...anchor,
139
+ value: normalizeText(anchor.value),
140
+ ...(anchor.endValue === undefined
141
+ ? {}
142
+ : { endValue: normalizeText(anchor.endValue) }),
143
+ })),
144
+ ...(item.record.participants === undefined
145
+ ? {}
146
+ : { participants: normalizeSet(item.record.participants) }),
147
+ ...(item.record.categories === undefined
148
+ ? {}
149
+ : { categories: normalizeSet(item.record.categories) }),
150
+ },
151
+ }),
132
152
  })),
133
153
  guidance: {
134
154
  ...value.guidance,
@@ -21,6 +21,7 @@ import type {
21
21
  ContextRetrievalCandidate,
22
22
  ContextRetrievalRequest,
23
23
  } from "./context-compiler";
24
+ import type { RecordEvidenceMetadata } from "./record-metadata";
24
25
 
25
26
  import { decorateUriForIndex, deriveDocid, parseUri } from "../app/constants";
26
27
  import { canonicalizeIndexName } from "../app/index-name";
@@ -35,6 +36,7 @@ import {
35
36
  } from "./context-capsule-validation";
36
37
  import { planContextEvidence } from "./context-compiler";
37
38
  import { projectContextEvidenceMetadata } from "./context-evidence-metadata";
39
+ import { projectRecordEvidenceMetadata } from "./record-metadata";
38
40
  import {
39
41
  extractInclusiveLines,
40
42
  extractSections,
@@ -104,6 +106,7 @@ export interface ContextEvidenceValue {
104
106
  contextIds: string[];
105
107
  trust: "untrusted";
106
108
  egress: "unavailable";
109
+ record?: RecordEvidenceMetadata;
107
110
  }
108
111
 
109
112
  export type ContextEvidenceCompilerInput = Omit<
@@ -283,7 +286,7 @@ const referenceDocument = (
283
286
  !document.active ||
284
287
  !document.mirrorHash ||
285
288
  parsedUri?.collection !== document.collection ||
286
- result.source.relPath !== document.relPath ||
289
+ result.source.relPath !== (document.recordSourcePath ?? document.relPath) ||
287
290
  sourceHash !== document.sourceHash ||
288
291
  mirrorHash !== document.mirrorHash ||
289
292
  deriveDocid(document.sourceHash) !== document.docid
@@ -416,6 +419,9 @@ export const materializeContextEvidenceCandidates = async (
416
419
  contextIds: [...candidate.contextIds],
417
420
  trust: "untrusted",
418
421
  egress: "unavailable",
422
+ ...(projectRecordEvidenceMetadata(document)
423
+ ? { record: projectRecordEvidenceMetadata(document) }
424
+ : {}),
419
425
  },
420
426
  },
421
427
  };
@@ -28,8 +28,20 @@ export function getDocumentCapabilities(input: {
28
28
  sourceExt: string;
29
29
  sourceMime: string;
30
30
  contentAvailable: boolean;
31
+ recordKey?: string | null;
31
32
  }): DocumentCapabilities {
32
33
  const ext = input.sourceExt.toLowerCase();
34
+ if (input.recordKey) {
35
+ return {
36
+ editable: false,
37
+ tagsEditable: true,
38
+ tagsWriteback: false,
39
+ canCreateEditableCopy: input.contentAvailable,
40
+ mode: "read_only",
41
+ reason:
42
+ "This document is a logical record derived from a file/export container and cannot be written back in place.",
43
+ };
44
+ }
33
45
  const editable =
34
46
  EDITABLE_EXTENSIONS.has(ext) || isTextLikeMime(input.sourceMime);
35
47
  const tagsWriteback = ext === ".md" || ext === ".markdown" || ext === ".mdx";
@@ -88,6 +88,11 @@ export function applyProjectProfileDesiredState(
88
88
  : existing?.models
89
89
  ? { models: existing.models }
90
90
  : {}),
91
+ ...(desired.collection.recordAdapters
92
+ ? { recordAdapters: desired.collection.recordAdapters }
93
+ : existing?.recordAdapters
94
+ ? { recordAdapters: existing.recordAdapters }
95
+ : {}),
91
96
  };
92
97
  const collections = [...config.collections];
93
98
  if (existingIndex >= 0) collections[existingIndex] = nextCollection;
@@ -77,6 +77,7 @@ export interface ProjectProfileDesiredState {
77
77
  exclude: string[];
78
78
  languageHint?: string;
79
79
  modelPreset?: string;
80
+ recordAdapters?: Config["collections"][number]["recordAdapters"];
80
81
  };
81
82
  contexts: ProjectProfileContextState[];
82
83
  contentTypes: Array<{
@@ -456,6 +457,9 @@ export async function compileProjectProfileYaml(
456
457
  ...(profile.collection.modelPreset
457
458
  ? { modelPreset: profile.collection.modelPreset }
458
459
  : {}),
460
+ ...(profile.collection.recordAdapters
461
+ ? { recordAdapters: profile.collection.recordAdapters }
462
+ : {}),
459
463
  },
460
464
  contexts: contexts.sort((left, right) =>
461
465
  compareCodeUnits(
@@ -0,0 +1,49 @@
1
+ import type { RecordAnchor, RecordMetadata } from "../converters/types";
2
+
3
+ export interface RecordEvidenceMetadata extends RecordMetadata {
4
+ recordKey: string;
5
+ sourceLocator: string;
6
+ anchors: RecordAnchor[];
7
+ adapter: {
8
+ id: string;
9
+ version: string;
10
+ fingerprint: string;
11
+ };
12
+ }
13
+
14
+ interface RecordMetadataSource {
15
+ recordKey?: string | null;
16
+ recordSourceLocator?: string | null;
17
+ recordMetadata?: RecordMetadata | null;
18
+ recordAnchors?: RecordAnchor[] | null;
19
+ converterId?: string | null;
20
+ converterVersion?: string | null;
21
+ recordAdapterFingerprint?: string | null;
22
+ }
23
+
24
+ /** Project only bounded, collection-relative logical-record provenance. */
25
+ export const projectRecordEvidenceMetadata = (
26
+ source: RecordMetadataSource
27
+ ): RecordEvidenceMetadata | undefined => {
28
+ if (
29
+ !(
30
+ source.recordKey &&
31
+ source.recordSourceLocator &&
32
+ source.converterId &&
33
+ source.converterVersion &&
34
+ source.recordAdapterFingerprint
35
+ )
36
+ )
37
+ return undefined;
38
+ return {
39
+ recordKey: source.recordKey,
40
+ sourceLocator: source.recordSourceLocator,
41
+ anchors: source.recordAnchors ?? [],
42
+ adapter: {
43
+ id: source.converterId,
44
+ version: source.converterVersion,
45
+ fingerprint: source.recordAdapterFingerprint,
46
+ },
47
+ ...source.recordMetadata,
48
+ };
49
+ };