@fortemi/core 2026.7.4 → 2026.7.5

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/dist/index.js CHANGED
@@ -9844,893 +9844,176 @@ function clearPrefetchedShard(url) {
9844
9844
  warmStore.delete(url);
9845
9845
  }
9846
9846
 
9847
- // schemas/aiwg-fortemi-index-export.schema.json
9848
- var aiwg_fortemi_index_export_schema_default = {
9849
- $schema: "https://json-schema.org/draft/2020-12/schema",
9850
- $id: "https://aiwg.io/schemas/aiwg-fortemi-index-export.json",
9851
- title: "AIWG Fortemi Index Export",
9852
- type: "object",
9853
- additionalProperties: false,
9854
- required: ["schema_version", "generated_at", "source", "items"],
9855
- properties: {
9856
- schema_version: {
9857
- enum: ["aiwg.fortemi.index.export.v1", "aiwg.fortemi.index.export.v2"]
9858
- },
9859
- generated_at: {
9860
- type: "string",
9861
- format: "date-time"
9862
- },
9863
- source: {
9864
- type: "object",
9865
- additionalProperties: false,
9866
- required: ["repo", "privacy"],
9867
- properties: {
9868
- repo: {
9869
- type: "string",
9870
- minLength: 1
9871
- },
9872
- privacy: {
9873
- $ref: "#/$defs/privacy"
9874
- },
9875
- graph: {
9876
- type: "string",
9877
- minLength: 1
9847
+ // src/aiwg-index.ts
9848
+ var AIWG_SCAN_REQUIRED_FIELDS = [
9849
+ "schema_version",
9850
+ "id",
9851
+ "type",
9852
+ "title",
9853
+ "text",
9854
+ "facets",
9855
+ "tags",
9856
+ "concepts",
9857
+ "privacy"
9858
+ ];
9859
+ function isPrivacyExcluded(record, options) {
9860
+ const privacy = record.privacy;
9861
+ if (!privacy || !isPrivacyClassification(privacy.classification) || typeof privacy.pii !== "boolean") return true;
9862
+ if (privacy.classification === "private" && !options?.includePrivate) return true;
9863
+ if (privacy.pii && !options?.includePii) return true;
9864
+ return false;
9865
+ }
9866
+ function filterAiwgRecordsByPrivacy(records, options) {
9867
+ return records.filter((record) => !isPrivacyExcluded(record, options));
9868
+ }
9869
+ var REQUIRED_RECORD_FIELDS = [
9870
+ "schema_version",
9871
+ "id",
9872
+ "type",
9873
+ "source",
9874
+ "facets",
9875
+ "tags",
9876
+ "concepts",
9877
+ "relationships",
9878
+ "provenance",
9879
+ "privacy",
9880
+ "updated_at"
9881
+ ];
9882
+ var DEFAULT_QUERY_WEIGHTS = {
9883
+ title: 4,
9884
+ tag: 3,
9885
+ concept: 2,
9886
+ text: 1,
9887
+ facet: 2,
9888
+ id: 1,
9889
+ source: 0.25
9890
+ };
9891
+ function hasString(value) {
9892
+ return typeof value === "string" && value.length > 0;
9893
+ }
9894
+ function pushFacet(counts, name, value) {
9895
+ let bucket = counts[name];
9896
+ if (bucket === void 0) {
9897
+ bucket = /* @__PURE__ */ Object.create(null);
9898
+ counts[name] = bucket;
9899
+ }
9900
+ bucket[value] = (bucket[value] ?? 0) + 1;
9901
+ }
9902
+ function hasNonNegativeInteger(value) {
9903
+ return Number.isInteger(value) && typeof value === "number" && value >= 0;
9904
+ }
9905
+ function hasPositiveInteger(value) {
9906
+ return Number.isInteger(value) && typeof value === "number" && value > 0;
9907
+ }
9908
+ function isFacetCounts(value) {
9909
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
9910
+ return Object.values(value).every((counts) => !!counts && typeof counts === "object" && !Array.isArray(counts) && Object.values(counts).every((count) => hasNonNegativeInteger(count)));
9911
+ }
9912
+ function isPlainRecord(value) {
9913
+ return !!value && typeof value === "object" && !Array.isArray(value);
9914
+ }
9915
+ function isOptionalStringArray(value) {
9916
+ return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
9917
+ }
9918
+ function isSupportedIndexSchemaVersion(value) {
9919
+ return value === "aiwg.fortemi.index.export.v1" || value === "aiwg.fortemi.index.export.v2";
9920
+ }
9921
+ function isSupportedRecordSchemaVersion(value) {
9922
+ return value === "aiwg.fortemi.index.record.v1" || value === "aiwg.fortemi.index.record.v2";
9923
+ }
9924
+ function validateOptionalRichMetadata(item, index, errors) {
9925
+ if (item.skos_concepts !== void 0) {
9926
+ if (!Array.isArray(item.skos_concepts)) {
9927
+ errors.push("items[" + index + "].skos_concepts must be an array when present");
9928
+ } else {
9929
+ for (const [conceptIndex, concept] of item.skos_concepts.entries()) {
9930
+ if (!isPlainRecord(concept)) {
9931
+ errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "] must be an object");
9932
+ continue;
9878
9933
  }
9879
- }
9880
- },
9881
- compatibility: {
9882
- type: "object",
9883
- additionalProperties: false,
9884
- required: ["previous_schema_version", "strategy"],
9885
- properties: {
9886
- previous_schema_version: {
9887
- const: "aiwg.fortemi.index.export.v1"
9888
- },
9889
- strategy: {
9890
- const: "supported"
9934
+ if (!hasString(concept.id)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].id is required");
9935
+ if (!hasString(concept.prefLabel)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].prefLabel is required");
9936
+ if (!isOptionalStringArray(concept.altLabels)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].altLabels must be a string array");
9937
+ if (concept.metadata !== void 0 && !isPlainRecord(concept.metadata)) {
9938
+ errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].metadata must be an object");
9891
9939
  }
9892
9940
  }
9893
- },
9894
- items: {
9895
- type: "array",
9896
- items: {
9897
- $ref: "#/$defs/record"
9898
- }
9899
9941
  }
9900
- },
9901
- allOf: [
9902
- {
9903
- if: {
9904
- properties: {
9905
- schema_version: {
9906
- const: "aiwg.fortemi.index.export.v1"
9907
- }
9942
+ }
9943
+ if (item.skos_relations !== void 0) {
9944
+ if (!Array.isArray(item.skos_relations)) {
9945
+ errors.push("items[" + index + "].skos_relations must be an array when present");
9946
+ } else {
9947
+ for (const [relationIndex, relation] of item.skos_relations.entries()) {
9948
+ if (!isPlainRecord(relation)) {
9949
+ errors.push("items[" + index + "].skos_relations[" + relationIndex + "] must be an object");
9950
+ continue;
9908
9951
  }
9909
- },
9910
- then: {
9911
- not: {
9912
- required: ["compatibility"]
9913
- },
9914
- properties: {
9915
- source: {
9916
- not: {
9917
- required: ["graph"]
9918
- }
9919
- },
9920
- items: {
9921
- items: {
9922
- allOf: [
9923
- {
9924
- properties: {
9925
- schema_version: {
9926
- const: "aiwg.fortemi.index.record.v1"
9927
- }
9928
- }
9929
- },
9930
- {
9931
- $ref: "#/$defs/v1RecordCompatibility"
9932
- }
9933
- ]
9934
- }
9935
- }
9952
+ if (!hasString(relation.type)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].type is required");
9953
+ if (!hasString(relation.source_id)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].source_id is required");
9954
+ if (!hasString(relation.target_id)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].target_id is required");
9955
+ if (relation.metadata !== void 0 && !isPlainRecord(relation.metadata)) {
9956
+ errors.push("items[" + index + "].skos_relations[" + relationIndex + "].metadata must be an object");
9936
9957
  }
9937
9958
  }
9938
- },
9939
- {
9940
- if: {
9941
- properties: {
9942
- schema_version: {
9943
- const: "aiwg.fortemi.index.export.v2"
9944
- }
9959
+ }
9960
+ }
9961
+ if (item.provenance_events !== void 0) {
9962
+ if (!Array.isArray(item.provenance_events)) {
9963
+ errors.push("items[" + index + "].provenance_events must be an array when present");
9964
+ } else {
9965
+ for (const [eventIndex, event] of item.provenance_events.entries()) {
9966
+ if (!isPlainRecord(event)) {
9967
+ errors.push("items[" + index + "].provenance_events[" + eventIndex + "] must be an object");
9968
+ continue;
9945
9969
  }
9946
- },
9947
- then: {
9948
- required: ["compatibility"],
9949
- properties: {
9950
- source: {
9951
- required: ["graph"]
9952
- },
9953
- items: {
9954
- items: {
9955
- properties: {
9956
- schema_version: {
9957
- const: "aiwg.fortemi.index.record.v2"
9958
- }
9959
- }
9960
- }
9961
- }
9970
+ if (!hasString(event.activity)) errors.push("items[" + index + "].provenance_events[" + eventIndex + "].activity is required");
9971
+ if (event.attributes !== void 0 && !isPlainRecord(event.attributes)) {
9972
+ errors.push("items[" + index + "].provenance_events[" + eventIndex + "].attributes must be an object");
9962
9973
  }
9963
9974
  }
9964
9975
  }
9965
- ],
9966
- $defs: {
9967
- privacy: {
9968
- enum: ["private", "sanitized", "public"]
9969
- },
9970
- recordType: {
9971
- type: "string",
9972
- minLength: 1
9973
- },
9974
- stringArray: {
9975
- type: "array",
9976
- items: {
9977
- type: "string"
9976
+ }
9977
+ if (Array.isArray(item.relationships)) {
9978
+ for (const [relationshipIndex, relationship] of item.relationships.entries()) {
9979
+ if (!isPlainRecord(relationship)) {
9980
+ errors.push("items[" + index + "].relationships[" + relationshipIndex + "] must be an object");
9981
+ continue;
9978
9982
  }
9979
- },
9980
- numberArray: {
9981
- type: "array",
9982
- items: {
9983
- type: "number"
9983
+ if (relationship.metadata !== void 0 && !isPlainRecord(relationship.metadata)) {
9984
+ errors.push("items[" + index + "].relationships[" + relationshipIndex + "].metadata must be an object");
9984
9985
  }
9985
- },
9986
- v1RecordCompatibility: {
9987
- type: "object",
9988
- not: {
9989
- anyOf: [
9990
- {
9991
- required: ["name"]
9992
- },
9993
- {
9994
- required: ["summary"]
9995
- },
9996
- {
9997
- required: ["search"]
9998
- },
9999
- {
10000
- required: ["chunks"]
10001
- },
10002
- {
10003
- required: ["embeddings"]
10004
- },
10005
- {
10006
- required: ["compatibility"]
10007
- },
10008
- {
10009
- required: ["skos_concepts"]
10010
- },
10011
- {
10012
- required: ["skos_relations"]
10013
- },
10014
- {
10015
- required: ["provenance_events"]
10016
- }
10017
- ]
10018
- },
10019
- properties: {
10020
- source: {
10021
- not: {
10022
- anyOf: [
10023
- {
10024
- required: ["origin"]
10025
- },
10026
- {
10027
- required: ["generated"]
10028
- },
10029
- {
10030
- required: ["checksum"]
10031
- },
10032
- {
10033
- required: ["updated_at"]
10034
- }
10035
- ]
10036
- }
10037
- },
10038
- relationships: {
10039
- items: {
10040
- not: {
10041
- anyOf: [
10042
- {
10043
- required: ["target_path"]
10044
- },
10045
- {
10046
- required: ["direction"]
10047
- },
10048
- {
10049
- required: ["label"]
10050
- },
10051
- {
10052
- required: ["confidence"]
10053
- },
10054
- {
10055
- required: ["privacy"]
10056
- },
10057
- {
10058
- required: ["metadata"]
10059
- }
10060
- ]
10061
- }
10062
- }
10063
- },
10064
- privacy: {
10065
- not: {
10066
- required: ["locality"]
10067
- }
10068
- }
10069
- }
10070
- },
10071
- record: {
10072
- type: "object",
10073
- additionalProperties: false,
10074
- required: [
10075
- "schema_version",
10076
- "id",
10077
- "type",
10078
- "source",
10079
- "title",
10080
- "text",
10081
- "facets",
10082
- "tags",
10083
- "concepts",
10084
- "relationships",
10085
- "provenance",
10086
- "privacy",
10087
- "updated_at"
10088
- ],
10089
- properties: {
10090
- schema_version: {
10091
- enum: [
10092
- "aiwg.fortemi.index.record.v1",
10093
- "aiwg.fortemi.index.record.v2"
10094
- ]
10095
- },
10096
- id: {
10097
- type: "string",
10098
- minLength: 1
10099
- },
10100
- type: {
10101
- $ref: "#/$defs/recordType"
10102
- },
10103
- source: {
10104
- type: "object",
10105
- additionalProperties: false,
10106
- required: ["path", "repo_relative_path", "locator"],
10107
- properties: {
10108
- path: {
10109
- type: "string",
10110
- minLength: 1
10111
- },
10112
- repo_relative_path: {
10113
- type: "string",
10114
- minLength: 1
10115
- },
10116
- locator: {
10117
- type: "string",
10118
- minLength: 1
10119
- },
10120
- origin: {
10121
- type: "string",
10122
- minLength: 1
10123
- },
10124
- generated: {
10125
- type: "boolean"
10126
- },
10127
- checksum: {
10128
- type: "string"
10129
- },
10130
- updated_at: {
10131
- type: "string",
10132
- format: "date-time"
10133
- }
10134
- }
10135
- },
10136
- title: {
10137
- type: "string"
10138
- },
10139
- name: {
10140
- type: "string"
10141
- },
10142
- summary: {
10143
- type: "string"
10144
- },
10145
- text: {
10146
- type: "string"
10147
- },
10148
- search: {
10149
- type: "object",
10150
- additionalProperties: false,
10151
- required: [
10152
- "title",
10153
- "body",
10154
- "triggers",
10155
- "aliases",
10156
- "tags",
10157
- "frontmatter"
10158
- ],
10159
- properties: {
10160
- title: {
10161
- type: "string"
10162
- },
10163
- name: {
10164
- type: "string"
10165
- },
10166
- summary: {
10167
- type: "string"
10168
- },
10169
- body: {
10170
- type: "string"
10171
- },
10172
- triggers: {
10173
- $ref: "#/$defs/stringArray"
10174
- },
10175
- aliases: {
10176
- $ref: "#/$defs/stringArray"
10177
- },
10178
- capability: {
10179
- type: "string"
10180
- },
10181
- tags: {
10182
- $ref: "#/$defs/stringArray"
10183
- },
10184
- phase: {
10185
- type: "string"
10186
- },
10187
- type: {
10188
- type: "string"
10189
- },
10190
- frontmatter: {
10191
- type: "object"
10192
- }
10193
- }
10194
- },
10195
- facets: {
10196
- type: "object",
10197
- additionalProperties: {
10198
- $ref: "#/$defs/stringArray"
10199
- }
10200
- },
10201
- tags: {
10202
- $ref: "#/$defs/stringArray"
10203
- },
10204
- concepts: {
10205
- $ref: "#/$defs/stringArray"
10206
- },
10207
- relationships: {
10208
- type: "array",
10209
- items: {
10210
- type: "object",
10211
- additionalProperties: false,
10212
- required: ["type", "target_id"],
10213
- properties: {
10214
- type: {
10215
- type: "string",
10216
- minLength: 1
10217
- },
10218
- target_id: {
10219
- type: "string",
10220
- minLength: 1
10221
- },
10222
- source_path: {
10223
- type: "string"
10224
- },
10225
- target_path: {
10226
- type: "string"
10227
- },
10228
- direction: {
10229
- enum: ["upstream", "downstream", "related"]
10230
- },
10231
- label: {
10232
- type: "string"
10233
- },
10234
- confidence: {
10235
- type: "number"
10236
- },
10237
- privacy: {
10238
- $ref: "#/$defs/privacy"
10239
- },
10240
- metadata: {
10241
- type: "object"
10242
- }
10243
- }
10244
- }
10245
- },
10246
- provenance: {
10247
- type: "array",
10248
- minItems: 1,
10249
- items: {
10250
- type: "object",
10251
- additionalProperties: false,
10252
- required: ["field", "source", "path", "confidence", "privacy"],
10253
- properties: {
10254
- field: {
10255
- type: "string",
10256
- minLength: 1
10257
- },
10258
- source: {
10259
- type: "string",
10260
- minLength: 1
10261
- },
10262
- path: {
10263
- type: "string",
10264
- minLength: 1
10265
- },
10266
- confidence: {
10267
- enum: ["source", "candidate", "reviewed", "rejected"]
10268
- },
10269
- privacy: {
10270
- $ref: "#/$defs/privacy"
10271
- }
10272
- }
10273
- }
10274
- },
10275
- privacy: {
10276
- type: "object",
10277
- additionalProperties: false,
10278
- required: ["classification", "pii"],
10279
- properties: {
10280
- classification: {
10281
- $ref: "#/$defs/privacy"
10282
- },
10283
- pii: {
10284
- type: "boolean"
10285
- },
10286
- locality: {
10287
- enum: ["project", "framework", "external"]
10288
- }
10289
- }
10290
- },
10291
- chunks: {
10292
- type: "array",
10293
- items: {
10294
- type: "object",
10295
- additionalProperties: false,
10296
- properties: {
10297
- id: {
10298
- type: "string",
10299
- minLength: 1
10300
- },
10301
- text: {
10302
- type: "string"
10303
- },
10304
- body: {
10305
- type: "string"
10306
- },
10307
- summary: {
10308
- type: "string"
10309
- },
10310
- source_path: {
10311
- type: "string"
10312
- },
10313
- metadata: {
10314
- type: "object"
10315
- },
10316
- checksum: {
10317
- type: "string"
10318
- }
10319
- }
10320
- }
10321
- },
10322
- embeddings: {
10323
- type: "array",
10324
- items: {
10325
- type: "object",
10326
- additionalProperties: false,
10327
- properties: {
10328
- id: {
10329
- type: "string"
10330
- },
10331
- model: {
10332
- type: "string"
10333
- },
10334
- embedding: {
10335
- $ref: "#/$defs/numberArray"
10336
- },
10337
- vector: {
10338
- $ref: "#/$defs/numberArray"
10339
- },
10340
- granularity: {
10341
- type: "string"
10342
- },
10343
- source_path: {
10344
- type: "string"
10345
- },
10346
- metadata: {
10347
- type: "object"
10348
- },
10349
- chunk_id: {
10350
- type: "string"
10351
- },
10352
- vector_ref: {
10353
- type: "string"
10354
- },
10355
- input_hash: {
10356
- type: "string"
10357
- }
10358
- }
10359
- }
10360
- },
10361
- compatibility: {
10362
- type: "object"
10363
- },
10364
- skos_concepts: {
10365
- type: "array",
10366
- items: {
10367
- type: "object",
10368
- additionalProperties: false,
10369
- required: ["id", "prefLabel"],
10370
- properties: {
10371
- id: {
10372
- type: "string",
10373
- minLength: 1
10374
- },
10375
- prefLabel: {
10376
- type: "string",
10377
- minLength: 1
10378
- },
10379
- definition: {
10380
- type: "string"
10381
- },
10382
- scheme: {
10383
- type: "string"
10384
- },
10385
- notation: {
10386
- type: "string"
10387
- },
10388
- uri: {
10389
- type: "string"
10390
- },
10391
- altLabels: {
10392
- $ref: "#/$defs/stringArray"
10393
- },
10394
- metadata: {
10395
- type: "object"
10396
- }
10397
- }
10398
- }
10399
- },
10400
- skos_relations: {
10401
- type: "array",
10402
- items: {
10403
- type: "object",
10404
- additionalProperties: false,
10405
- required: ["type", "source_id", "target_id"],
10406
- properties: {
10407
- type: {
10408
- type: "string",
10409
- minLength: 1
10410
- },
10411
- source_id: {
10412
- type: "string",
10413
- minLength: 1
10414
- },
10415
- target_id: {
10416
- type: "string",
10417
- minLength: 1
10418
- },
10419
- source_path: {
10420
- type: "string"
10421
- },
10422
- metadata: {
10423
- type: "object"
10424
- }
10425
- }
10426
- }
10427
- },
10428
- provenance_events: {
10429
- type: "array",
10430
- items: {
10431
- type: "object",
10432
- additionalProperties: false,
10433
- required: ["activity"],
10434
- properties: {
10435
- id: {
10436
- type: "string"
10437
- },
10438
- activity: {
10439
- type: "string",
10440
- minLength: 1
10441
- },
10442
- agent: {
10443
- type: "string"
10444
- },
10445
- started_at: {
10446
- type: "string",
10447
- format: "date-time"
10448
- },
10449
- ended_at: {
10450
- type: "string",
10451
- format: "date-time"
10452
- },
10453
- source: {
10454
- type: "string"
10455
- },
10456
- path: {
10457
- type: "string"
10458
- },
10459
- confidence: {
10460
- enum: ["source", "candidate", "reviewed", "rejected"]
10461
- },
10462
- privacy: {
10463
- $ref: "#/$defs/privacy"
10464
- },
10465
- attributes: {
10466
- type: "object"
10467
- }
10468
- }
10469
- }
10470
- },
10471
- updated_at: {
10472
- type: "string",
10473
- format: "date-time"
10474
- }
10475
- }
10476
- }
10477
- }
10478
- };
10479
-
10480
- // src/aiwg-index-schema.ts
10481
- var PROJECTED_FIELDS = [
10482
- "schema_version",
10483
- "id",
10484
- "type",
10485
- "title",
10486
- "text",
10487
- "facets",
10488
- "tags",
10489
- "concepts",
10490
- "privacy"
10491
- ];
10492
- var ajvInstance2;
10493
- var exportValidator;
10494
- var projectedRecordValidator;
10495
- function getAiwgFortemiIndexExportSchema() {
10496
- return aiwg_fortemi_index_export_schema_default;
10497
- }
10498
- function getAjv2() {
10499
- if (!ajvInstance2) {
10500
- ajvInstance2 = new Ajv2020({
10501
- allErrors: true,
10502
- strict: false,
10503
- validateFormats: false
10504
- });
10505
- ajvInstance2.addSchema(aiwg_fortemi_index_export_schema_default);
10506
- }
10507
- return ajvInstance2;
10508
- }
10509
- function formatErrors2(errors) {
10510
- return (errors ?? []).map((error) => {
10511
- const path = error.instancePath || "(root)";
10512
- return `${path} ${error.message ?? "is invalid"}`;
10513
- });
10514
- }
10515
- function getExportValidator() {
10516
- exportValidator ??= getAjv2().getSchema(aiwg_fortemi_index_export_schema_default.$id) ?? getAjv2().compile(aiwg_fortemi_index_export_schema_default);
10517
- return exportValidator;
10518
- }
10519
- function getProjectedRecordValidator() {
10520
- if (!projectedRecordValidator) {
10521
- const properties = Object.fromEntries(Object.keys(aiwg_fortemi_index_export_schema_default.$defs.record.properties).map((field) => [
10522
- field,
10523
- { $ref: `${aiwg_fortemi_index_export_schema_default.$id}#/$defs/record/properties/${field}` }
10524
- ]));
10525
- projectedRecordValidator = getAjv2().compile({
10526
- type: "object",
10527
- required: PROJECTED_FIELDS,
10528
- properties,
10529
- additionalProperties: true,
10530
- allOf: [
10531
- {
10532
- if: {
10533
- properties: {
10534
- schema_version: { const: "aiwg.fortemi.index.record.v1" }
10535
- }
10536
- },
10537
- then: { $ref: `${aiwg_fortemi_index_export_schema_default.$id}#/$defs/v1RecordCompatibility` }
10538
- }
10539
- ]
10540
- });
10541
- }
10542
- return projectedRecordValidator;
10543
- }
10544
- function validateAiwgFortemiIndexExportSchema(value) {
10545
- const validate = getExportValidator();
10546
- const schemaValue = value && typeof value === "object" && Array.isArray(value.items) ? {
10547
- ...value,
10548
- items: value.items.map((item) => {
10549
- if (!item || typeof item !== "object" || Array.isArray(item)) return item;
10550
- const schemaRecord = { ...item };
10551
- Reflect.deleteProperty(schemaRecord, "binary_sources");
10552
- return schemaRecord;
10553
- })
10554
- } : value;
10555
- const valid = validate(schemaValue);
10556
- return { valid, errors: formatErrors2(validate.errors) };
10557
- }
10558
- function validateAiwgFortemiProjectedRecordSchema(value) {
10559
- const validate = getProjectedRecordValidator();
10560
- const valid = validate(value);
10561
- return { valid, errors: formatErrors2(validate.errors) };
10562
- }
10563
-
10564
- // src/aiwg-index.ts
10565
- var AIWG_SCAN_REQUIRED_FIELDS = [
10566
- "schema_version",
10567
- "id",
10568
- "type",
10569
- "title",
10570
- "text",
10571
- "facets",
10572
- "tags",
10573
- "concepts",
10574
- "privacy"
10575
- ];
10576
- function isPrivacyExcluded(record, options) {
10577
- const privacy = record.privacy;
10578
- if (!privacy || !isPrivacyClassification(privacy.classification) || typeof privacy.pii !== "boolean") return true;
10579
- if (privacy.classification === "private" && !options?.includePrivate) return true;
10580
- if (privacy.pii && !options?.includePii) return true;
10581
- return false;
10582
- }
10583
- function filterAiwgRecordsByPrivacy(records, options) {
10584
- return records.filter((record) => !isPrivacyExcluded(record, options));
10585
- }
10586
- var REQUIRED_RECORD_FIELDS = [
10587
- "schema_version",
10588
- "id",
10589
- "type",
10590
- "source",
10591
- "facets",
10592
- "tags",
10593
- "concepts",
10594
- "relationships",
10595
- "provenance",
10596
- "privacy",
10597
- "updated_at"
10598
- ];
10599
- var DEFAULT_QUERY_WEIGHTS = {
10600
- title: 4,
10601
- tag: 3,
10602
- concept: 2,
10603
- text: 1,
10604
- facet: 2,
10605
- id: 1,
10606
- source: 0.25
10607
- };
10608
- function hasString(value) {
10609
- return typeof value === "string" && value.length > 0;
10610
- }
10611
- function pushFacet(counts, name, value) {
10612
- let bucket = counts[name];
10613
- if (bucket === void 0) {
10614
- bucket = /* @__PURE__ */ Object.create(null);
10615
- counts[name] = bucket;
10616
- }
10617
- bucket[value] = (bucket[value] ?? 0) + 1;
10618
- }
10619
- function hasNonNegativeInteger(value) {
10620
- return Number.isInteger(value) && typeof value === "number" && value >= 0;
10621
- }
10622
- function hasPositiveInteger(value) {
10623
- return Number.isInteger(value) && typeof value === "number" && value > 0;
10624
- }
10625
- function isFacetCounts(value) {
10626
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
10627
- return Object.values(value).every((counts) => !!counts && typeof counts === "object" && !Array.isArray(counts) && Object.values(counts).every((count) => hasNonNegativeInteger(count)));
10628
- }
10629
- function isPlainRecord(value) {
10630
- return !!value && typeof value === "object" && !Array.isArray(value);
10631
- }
10632
- function isOptionalStringArray(value) {
10633
- return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
10634
- }
10635
- function isSupportedIndexSchemaVersion(value) {
10636
- return value === "aiwg.fortemi.index.export.v1" || value === "aiwg.fortemi.index.export.v2";
10637
- }
10638
- function isSupportedRecordSchemaVersion(value) {
10639
- return value === "aiwg.fortemi.index.record.v1" || value === "aiwg.fortemi.index.record.v2";
10640
- }
10641
- function validateOptionalRichMetadata(item, index, errors) {
10642
- if (item.skos_concepts !== void 0) {
10643
- if (!Array.isArray(item.skos_concepts)) {
10644
- errors.push("items[" + index + "].skos_concepts must be an array when present");
10645
- } else {
10646
- for (const [conceptIndex, concept] of item.skos_concepts.entries()) {
10647
- if (!isPlainRecord(concept)) {
10648
- errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "] must be an object");
10649
- continue;
10650
- }
10651
- if (!hasString(concept.id)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].id is required");
10652
- if (!hasString(concept.prefLabel)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].prefLabel is required");
10653
- if (!isOptionalStringArray(concept.altLabels)) errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].altLabels must be a string array");
10654
- if (concept.metadata !== void 0 && !isPlainRecord(concept.metadata)) {
10655
- errors.push("items[" + index + "].skos_concepts[" + conceptIndex + "].metadata must be an object");
10656
- }
10657
- }
10658
- }
10659
- }
10660
- if (item.skos_relations !== void 0) {
10661
- if (!Array.isArray(item.skos_relations)) {
10662
- errors.push("items[" + index + "].skos_relations must be an array when present");
10663
- } else {
10664
- for (const [relationIndex, relation] of item.skos_relations.entries()) {
10665
- if (!isPlainRecord(relation)) {
10666
- errors.push("items[" + index + "].skos_relations[" + relationIndex + "] must be an object");
10667
- continue;
10668
- }
10669
- if (!hasString(relation.type)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].type is required");
10670
- if (!hasString(relation.source_id)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].source_id is required");
10671
- if (!hasString(relation.target_id)) errors.push("items[" + index + "].skos_relations[" + relationIndex + "].target_id is required");
10672
- if (relation.metadata !== void 0 && !isPlainRecord(relation.metadata)) {
10673
- errors.push("items[" + index + "].skos_relations[" + relationIndex + "].metadata must be an object");
10674
- }
10675
- }
10676
- }
10677
- }
10678
- if (item.provenance_events !== void 0) {
10679
- if (!Array.isArray(item.provenance_events)) {
10680
- errors.push("items[" + index + "].provenance_events must be an array when present");
10681
- } else {
10682
- for (const [eventIndex, event] of item.provenance_events.entries()) {
10683
- if (!isPlainRecord(event)) {
10684
- errors.push("items[" + index + "].provenance_events[" + eventIndex + "] must be an object");
10685
- continue;
10686
- }
10687
- if (!hasString(event.activity)) errors.push("items[" + index + "].provenance_events[" + eventIndex + "].activity is required");
10688
- if (event.attributes !== void 0 && !isPlainRecord(event.attributes)) {
10689
- errors.push("items[" + index + "].provenance_events[" + eventIndex + "].attributes must be an object");
10690
- }
10691
- }
10692
- }
10693
- }
10694
- if (Array.isArray(item.relationships)) {
10695
- for (const [relationshipIndex, relationship] of item.relationships.entries()) {
10696
- if (!isPlainRecord(relationship)) {
10697
- errors.push("items[" + index + "].relationships[" + relationshipIndex + "] must be an object");
10698
- continue;
10699
- }
10700
- if (relationship.metadata !== void 0 && !isPlainRecord(relationship.metadata)) {
10701
- errors.push("items[" + index + "].relationships[" + relationshipIndex + "].metadata must be an object");
10702
- }
10703
- if (relationship.direction !== void 0 && relationship.direction !== "upstream" && relationship.direction !== "downstream" && relationship.direction !== "related") {
10704
- errors.push("items[" + index + "].relationships[" + relationshipIndex + "].direction must be upstream, downstream, or related");
10705
- }
10706
- if (relationship.target_path !== void 0 && typeof relationship.target_path !== "string") {
10707
- errors.push("items[" + index + "].relationships[" + relationshipIndex + "].target_path must be a string");
10708
- }
10709
- }
10710
- }
10711
- if (item.search !== void 0) {
10712
- if (!isPlainRecord(item.search)) {
10713
- errors.push("items[" + index + "].search must be an object");
10714
- } else {
10715
- if (!isOptionalStringArray(item.search.triggers)) errors.push("items[" + index + "].search.triggers must be a string array");
10716
- if (!isOptionalStringArray(item.search.aliases)) errors.push("items[" + index + "].search.aliases must be a string array");
10717
- if (!isOptionalStringArray(item.search.tags)) errors.push("items[" + index + "].search.tags must be a string array");
10718
- if (item.search.frontmatter !== void 0 && !isPlainRecord(item.search.frontmatter)) {
10719
- errors.push("items[" + index + "].search.frontmatter must be an object");
10720
- }
10721
- }
10722
- }
10723
- if (item.chunks !== void 0) {
10724
- if (!Array.isArray(item.chunks)) {
10725
- errors.push("items[" + index + "].chunks must be an array when present");
10726
- } else {
10727
- for (const [chunkIndex, chunk] of item.chunks.entries()) {
10728
- if (!isPlainRecord(chunk)) {
10729
- errors.push("items[" + index + "].chunks[" + chunkIndex + "] must be an object");
10730
- continue;
10731
- }
10732
- if (chunk.metadata !== void 0 && !isPlainRecord(chunk.metadata)) {
10733
- errors.push("items[" + index + "].chunks[" + chunkIndex + "].metadata must be an object");
9986
+ if (relationship.direction !== void 0 && relationship.direction !== "upstream" && relationship.direction !== "downstream" && relationship.direction !== "related") {
9987
+ errors.push("items[" + index + "].relationships[" + relationshipIndex + "].direction must be upstream, downstream, or related");
9988
+ }
9989
+ if (relationship.target_path !== void 0 && typeof relationship.target_path !== "string") {
9990
+ errors.push("items[" + index + "].relationships[" + relationshipIndex + "].target_path must be a string");
9991
+ }
9992
+ }
9993
+ }
9994
+ if (item.search !== void 0) {
9995
+ if (!isPlainRecord(item.search)) {
9996
+ errors.push("items[" + index + "].search must be an object");
9997
+ } else {
9998
+ if (!isOptionalStringArray(item.search.triggers)) errors.push("items[" + index + "].search.triggers must be a string array");
9999
+ if (!isOptionalStringArray(item.search.aliases)) errors.push("items[" + index + "].search.aliases must be a string array");
10000
+ if (!isOptionalStringArray(item.search.tags)) errors.push("items[" + index + "].search.tags must be a string array");
10001
+ if (item.search.frontmatter !== void 0 && !isPlainRecord(item.search.frontmatter)) {
10002
+ errors.push("items[" + index + "].search.frontmatter must be an object");
10003
+ }
10004
+ }
10005
+ }
10006
+ if (item.chunks !== void 0) {
10007
+ if (!Array.isArray(item.chunks)) {
10008
+ errors.push("items[" + index + "].chunks must be an array when present");
10009
+ } else {
10010
+ for (const [chunkIndex, chunk] of item.chunks.entries()) {
10011
+ if (!isPlainRecord(chunk)) {
10012
+ errors.push("items[" + index + "].chunks[" + chunkIndex + "] must be an object");
10013
+ continue;
10014
+ }
10015
+ if (chunk.metadata !== void 0 && !isPlainRecord(chunk.metadata)) {
10016
+ errors.push("items[" + index + "].chunks[" + chunkIndex + "].metadata must be an object");
10734
10017
  }
10735
10018
  }
10736
10019
  }
@@ -10779,7 +10062,15 @@ function validateProvenanceItems(item, index, errors) {
10779
10062
  if (!isPrivacyClassification(prov.privacy)) errors.push(at + ".privacy must be one of private, sanitized, public");
10780
10063
  }
10781
10064
  }
10782
- var V2_ONLY_RECORD_FIELDS = ["search", "chunks", "embeddings", "skos_concepts", "skos_relations", "compatibility"];
10065
+ var V2_ONLY_RECORD_FIELDS = [
10066
+ "search",
10067
+ "chunks",
10068
+ "embeddings",
10069
+ "skos_concepts",
10070
+ "skos_relations",
10071
+ "provenance_events",
10072
+ "compatibility"
10073
+ ];
10783
10074
  var V2_ONLY_SOURCE_FIELDS = ["origin", "generated", "checksum", "updated_at"];
10784
10075
  var V2_ONLY_RELATIONSHIP_FIELDS = ["target_path", "direction", "metadata"];
10785
10076
  function forbidV2FieldsOnV1Record(item, index, errors) {
@@ -10810,7 +10101,7 @@ function forbidV2FieldsOnV1Record(item, index, errors) {
10810
10101
  }
10811
10102
  }
10812
10103
  function validateAiwgFortemiIndexExport(value) {
10813
- const errors = validateAiwgFortemiIndexExportSchema(value).errors;
10104
+ const errors = [];
10814
10105
  const counts = /* @__PURE__ */ Object.create(null);
10815
10106
  const data = isPlainRecord(value) ? value : {};
10816
10107
  if (!isPlainRecord(value)) errors.push("index export must be an object");
@@ -10849,6 +10140,9 @@ function validateAiwgFortemiIndexExport(value) {
10849
10140
  if (!isSupportedRecordSchemaVersion(item.schema_version)) {
10850
10141
  errors.push("items[" + index + "].schema_version must be aiwg.fortemi.index.record.v1 or aiwg.fortemi.index.record.v2");
10851
10142
  }
10143
+ if (data.schema_version === "aiwg.fortemi.index.export.v1" && item.schema_version === "aiwg.fortemi.index.record.v2") {
10144
+ errors.push("items[" + index + "].schema_version must match aiwg.fortemi.index.export.v1");
10145
+ }
10852
10146
  if (!hasString(item.id)) errors.push("items[" + index + "].id is required");
10853
10147
  if (hasString(item.id) && ids.has(item.id)) errors.push("duplicate id: " + item.id);
10854
10148
  if (hasString(item.id)) ids.add(item.id);
@@ -10956,6 +10250,33 @@ function assertAiwgFortemiChunkManifest(value) {
10956
10250
  }
10957
10251
  return value;
10958
10252
  }
10253
+ function validateProjectedRecordShape(item, index, errors) {
10254
+ const at = "items[" + index + "]";
10255
+ if (!item.privacy || !isPlainRecord(item.privacy)) {
10256
+ errors.push(at + "/privacy requires classification and pii");
10257
+ } else {
10258
+ if (!isPrivacyClassification(item.privacy.classification)) {
10259
+ errors.push(at + "/privacy/classification must be one of private, sanitized, public");
10260
+ }
10261
+ if (typeof item.privacy.pii !== "boolean") {
10262
+ errors.push(at + "/privacy/pii must be boolean");
10263
+ }
10264
+ }
10265
+ if (Array.isArray(item.provenance)) {
10266
+ for (const [provIndex, prov] of item.provenance.entries()) {
10267
+ if (!isPlainRecord(prov)) {
10268
+ errors.push(at + "/provenance/" + provIndex + " must be an object");
10269
+ continue;
10270
+ }
10271
+ if (!isProvenanceConfidence(prov.confidence)) {
10272
+ errors.push(at + "/provenance/" + provIndex + "/confidence must be one of source, candidate, reviewed, rejected");
10273
+ }
10274
+ if (!isPrivacyClassification(prov.privacy)) {
10275
+ errors.push(at + "/provenance/" + provIndex + "/privacy must be one of private, sanitized, public");
10276
+ }
10277
+ }
10278
+ }
10279
+ }
10959
10280
  function validateProjectedRecords(items, sourceSchemaVersion) {
10960
10281
  const errors = [];
10961
10282
  const ids = /* @__PURE__ */ new Set();
@@ -10965,8 +10286,7 @@ function validateProjectedRecords(items, sourceSchemaVersion) {
10965
10286
  errors.push("items[" + index + "] must be an object");
10966
10287
  continue;
10967
10288
  }
10968
- const schemaValidation = validateAiwgFortemiProjectedRecordSchema(item);
10969
- errors.push(...schemaValidation.errors.map((error) => `items[${index}]${error}`));
10289
+ validateProjectedRecordShape(item, index, errors);
10970
10290
  const expectedRecordVersion = sourceSchemaVersion === "aiwg.fortemi.index.export.v2" ? "aiwg.fortemi.index.record.v2" : "aiwg.fortemi.index.record.v1";
10971
10291
  if (item.schema_version !== expectedRecordVersion) {
10972
10292
  errors.push(`items[${index}].schema_version must match ${sourceSchemaVersion}`);
@@ -11130,6 +10450,137 @@ function generatedAtString(value) {
11130
10450
  if (value instanceof Date) return value.toISOString();
11131
10451
  return value ?? (/* @__PURE__ */ new Date()).toISOString();
11132
10452
  }
10453
+ var SHA256_K = [
10454
+ 1116352408,
10455
+ 1899447441,
10456
+ 3049323471,
10457
+ 3921009573,
10458
+ 961987163,
10459
+ 1508970993,
10460
+ 2453635748,
10461
+ 2870763221,
10462
+ 3624381080,
10463
+ 310598401,
10464
+ 607225278,
10465
+ 1426881987,
10466
+ 1925078388,
10467
+ 2162078206,
10468
+ 2614888103,
10469
+ 3248222580,
10470
+ 3835390401,
10471
+ 4022224774,
10472
+ 264347078,
10473
+ 604807628,
10474
+ 770255983,
10475
+ 1249150122,
10476
+ 1555081692,
10477
+ 1996064986,
10478
+ 2554220882,
10479
+ 2821834349,
10480
+ 2952996808,
10481
+ 3210313671,
10482
+ 3336571891,
10483
+ 3584528711,
10484
+ 113926993,
10485
+ 338241895,
10486
+ 666307205,
10487
+ 773529912,
10488
+ 1294757372,
10489
+ 1396182291,
10490
+ 1695183700,
10491
+ 1986661051,
10492
+ 2177026350,
10493
+ 2456956037,
10494
+ 2730485921,
10495
+ 2820302411,
10496
+ 3259730800,
10497
+ 3345764771,
10498
+ 3516065817,
10499
+ 3600352804,
10500
+ 4094571909,
10501
+ 275423344,
10502
+ 430227734,
10503
+ 506948616,
10504
+ 659060556,
10505
+ 883997877,
10506
+ 958139571,
10507
+ 1322822218,
10508
+ 1537002063,
10509
+ 1747873779,
10510
+ 1955562222,
10511
+ 2024104815,
10512
+ 2227730452,
10513
+ 2361852424,
10514
+ 2428436474,
10515
+ 2756734187,
10516
+ 3204031479,
10517
+ 3329325298
10518
+ ];
10519
+ function rotr(value, bits) {
10520
+ return value >>> bits | value << 32 - bits;
10521
+ }
10522
+ function sha256Hex2(data) {
10523
+ const bitLength = data.length * 8;
10524
+ const padded = new Uint8Array(data.length + 9 + 63 >> 6 << 6);
10525
+ padded.set(data);
10526
+ padded[data.length] = 128;
10527
+ const view = new DataView(padded.buffer);
10528
+ view.setUint32(padded.length - 4, bitLength >>> 0);
10529
+ view.setUint32(padded.length - 8, Math.floor(bitLength / 4294967296));
10530
+ let h0 = 1779033703;
10531
+ let h1 = 3144134277;
10532
+ let h2 = 1013904242;
10533
+ let h3 = 2773480762;
10534
+ let h4 = 1359893119;
10535
+ let h5 = 2600822924;
10536
+ let h6 = 528734635;
10537
+ let h7 = 1541459225;
10538
+ const w = new Uint32Array(64);
10539
+ for (let offset = 0; offset < padded.length; offset += 64) {
10540
+ for (let i = 0; i < 16; i++) w[i] = view.getUint32(offset + i * 4);
10541
+ for (let i = 16; i < 64; i++) {
10542
+ const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ w[i - 15] >>> 3;
10543
+ const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ w[i - 2] >>> 10;
10544
+ w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
10545
+ }
10546
+ let a = h0;
10547
+ let b = h1;
10548
+ let c = h2;
10549
+ let d = h3;
10550
+ let e = h4;
10551
+ let f = h5;
10552
+ let g = h6;
10553
+ let h = h7;
10554
+ for (let i = 0; i < 64; i++) {
10555
+ const s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
10556
+ const ch = e & f ^ ~e & g;
10557
+ const temp1 = h + s1 + ch + SHA256_K[i] + w[i] >>> 0;
10558
+ const s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
10559
+ const maj = a & b ^ a & c ^ b & c;
10560
+ const temp2 = s0 + maj >>> 0;
10561
+ h = g;
10562
+ g = f;
10563
+ f = e;
10564
+ e = d + temp1 >>> 0;
10565
+ d = c;
10566
+ c = b;
10567
+ b = a;
10568
+ a = temp1 + temp2 >>> 0;
10569
+ }
10570
+ h0 = h0 + a >>> 0;
10571
+ h1 = h1 + b >>> 0;
10572
+ h2 = h2 + c >>> 0;
10573
+ h3 = h3 + d >>> 0;
10574
+ h4 = h4 + e >>> 0;
10575
+ h5 = h5 + f >>> 0;
10576
+ h6 = h6 + g >>> 0;
10577
+ h7 = h7 + h >>> 0;
10578
+ }
10579
+ return [h0, h1, h2, h3, h4, h5, h6, h7].map((part) => part.toString(16).padStart(8, "0")).join("");
10580
+ }
10581
+ function computeAiwgIndexHash(data) {
10582
+ return `sha256:${sha256Hex2(data)}`;
10583
+ }
11133
10584
  async function buildAiwgStaticEmbeddingSet(index, options) {
11134
10585
  assertAiwgFortemiIndexExport(index);
11135
10586
  const granularity = options.granularity ?? "body";
@@ -11145,7 +10596,7 @@ async function buildAiwgStaticEmbeddingSet(index, options) {
11145
10596
  record_id: record.id,
11146
10597
  embedding,
11147
10598
  granularity,
11148
- input_hash: computeHash(new TextEncoder().encode(input)),
10599
+ input_hash: computeAiwgIndexHash(new TextEncoder().encode(input)),
11149
10600
  source_path: record.source.path
11150
10601
  });
11151
10602
  }
@@ -11997,220 +11448,937 @@ function createAiwgIndexController(initialIndex) {
11997
11448
  return {
11998
11449
  loadIndex(value) {
11999
11450
  try {
12000
- const parsed = assertAiwgFortemiIndexExport(value);
12001
- index = parsed;
12002
- chunked = null;
12003
- data = null;
12004
- reviewDecisions = [];
11451
+ const parsed = assertAiwgFortemiIndexExport(value);
11452
+ index = parsed;
11453
+ chunked = null;
11454
+ data = null;
11455
+ reviewDecisions = [];
11456
+ error = null;
11457
+ notify();
11458
+ return parsed;
11459
+ } catch (err) {
11460
+ error = err instanceof Error ? err : new Error(String(err));
11461
+ notify();
11462
+ throw error;
11463
+ }
11464
+ },
11465
+ loadChunkedIndex(manifest, loader, options = {}) {
11466
+ try {
11467
+ const parsed = assertAiwgFortemiChunkManifest(manifest);
11468
+ index = null;
11469
+ chunked = {
11470
+ manifest: parsed,
11471
+ loader,
11472
+ maxCachedParts: clampMaxCachedParts(options.maxCachedParts),
11473
+ partCache: /* @__PURE__ */ new Map(),
11474
+ detailLoader: options.detailLoader,
11475
+ maxCachedDetails: clampMaxCachedDetails(options.maxCachedDetails),
11476
+ detailCache: /* @__PURE__ */ new Map(),
11477
+ maxCachedMatches: clampMaxCachedMatches(options.maxCachedMatches),
11478
+ matchCache: /* @__PURE__ */ new Map()
11479
+ };
11480
+ data = null;
11481
+ reviewDecisions = [];
11482
+ error = null;
11483
+ notify();
11484
+ return parsed;
11485
+ } catch (err) {
11486
+ error = err instanceof Error ? err : new Error(String(err));
11487
+ notify();
11488
+ throw error;
11489
+ }
11490
+ },
11491
+ getIndex() {
11492
+ return index;
11493
+ },
11494
+ getChunkedManifest() {
11495
+ return chunked?.manifest ?? null;
11496
+ },
11497
+ getSnapshot() {
11498
+ return snapshot();
11499
+ },
11500
+ query(query = "", options) {
11501
+ const result = queryAiwgFortemiIndex(requireIndex(), query, options);
11502
+ data = result;
11503
+ error = null;
11504
+ notify();
11505
+ return result;
11506
+ },
11507
+ async queryChunked(query = "", options) {
11508
+ if (!chunked) throw new Error("No AIWG chunked index manifest loaded");
11509
+ try {
11510
+ const result = await queryChunkedAiwgFortemiIndex(chunked, query, options);
11511
+ data = result;
12005
11512
  error = null;
12006
11513
  notify();
12007
- return parsed;
11514
+ return result;
12008
11515
  } catch (err) {
12009
11516
  error = err instanceof Error ? err : new Error(String(err));
12010
11517
  notify();
12011
11518
  throw error;
12012
11519
  }
12013
11520
  },
12014
- loadChunkedIndex(manifest, loader, options = {}) {
11521
+ async getRecord(id) {
11522
+ if (chunked) {
11523
+ try {
11524
+ return await getChunkRecord(chunked, id);
11525
+ } catch (err) {
11526
+ error = err instanceof Error ? err : new Error(String(err));
11527
+ notify();
11528
+ throw error;
11529
+ }
11530
+ }
11531
+ const found = requireIndex().items.find((item) => item.id === id);
11532
+ if (!found) throw new Error("Record not found: " + id);
11533
+ return found;
11534
+ },
11535
+ async neighbors(id, options) {
12015
11536
  try {
12016
- const parsed = assertAiwgFortemiChunkManifest(manifest);
12017
- index = null;
12018
- chunked = {
12019
- manifest: parsed,
12020
- loader,
12021
- maxCachedParts: clampMaxCachedParts(options.maxCachedParts),
12022
- partCache: /* @__PURE__ */ new Map(),
12023
- detailLoader: options.detailLoader,
12024
- maxCachedDetails: clampMaxCachedDetails(options.maxCachedDetails),
12025
- detailCache: /* @__PURE__ */ new Map(),
12026
- maxCachedMatches: clampMaxCachedMatches(options.maxCachedMatches),
12027
- matchCache: /* @__PURE__ */ new Map()
12028
- };
12029
- data = null;
12030
- reviewDecisions = [];
12031
- error = null;
11537
+ const queryOptions = neighborQueryOptions(id, options);
11538
+ const result = chunked ? await relationshipResultFromChunkedRuntime(chunked, queryOptions) : relationshipResultFromRecords(requireIndex().items, queryOptions);
11539
+ return filterNeighborResult(id, result, options);
11540
+ } catch (err) {
11541
+ error = err instanceof Error ? err : new Error(String(err));
12032
11542
  notify();
12033
- return parsed;
11543
+ throw error;
11544
+ }
11545
+ },
11546
+ async relationshipQuery(options) {
11547
+ try {
11548
+ return chunked ? await relationshipResultFromChunkedRuntime(chunked, options) : relationshipResultFromRecords(requireIndex().items, options);
12034
11549
  } catch (err) {
12035
11550
  error = err instanceof Error ? err : new Error(String(err));
12036
11551
  notify();
12037
11552
  throw error;
12038
11553
  }
12039
11554
  },
12040
- getIndex() {
12041
- return index;
11555
+ async relationshipSet(options) {
11556
+ const [left, right] = await Promise.all([
11557
+ this.neighbors(options.a, options),
11558
+ this.neighbors(options.b, options)
11559
+ ]);
11560
+ const leftIds = new Set(left.nodes.map((node) => node.id).filter((id) => id !== options.a));
11561
+ const rightIds = new Set(right.nodes.map((node) => node.id).filter((id) => id !== options.b));
11562
+ let ids;
11563
+ if (options.op === "intersection") ids = [...leftIds].filter((id) => rightIds.has(id));
11564
+ else if (options.op === "difference") ids = [...leftIds].filter((id) => !rightIds.has(id));
11565
+ else ids = [.../* @__PURE__ */ new Set([...leftIds, ...rightIds])];
11566
+ return { op: options.op, ids: ids.sort() };
11567
+ },
11568
+ clearChunkCache() {
11569
+ chunked?.partCache.clear();
11570
+ chunked?.detailCache.clear();
11571
+ chunked?.matchCache.clear();
11572
+ error = null;
11573
+ notify();
11574
+ },
11575
+ toCommunityGraph(options) {
11576
+ return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
11577
+ },
11578
+ async toCommunityGraphChunked(options) {
11579
+ if (!chunked) return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
11580
+ const loaded = await recordsFromChunkedRuntime(chunked, options?.onProgress);
11581
+ return aiwgFortemiIndexToCommunityGraph({
11582
+ generated_at: chunked.manifest.generated_at,
11583
+ source: chunked.manifest.source,
11584
+ items: loaded.records
11585
+ }, options);
11586
+ },
11587
+ setReviewDecision(input) {
11588
+ const decision = {
11589
+ ...input,
11590
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
11591
+ };
11592
+ reviewDecisions = [
11593
+ ...reviewDecisions.filter((item) => item.item_id !== decision.item_id),
11594
+ decision
11595
+ ].sort((left, right) => left.item_id.localeCompare(right.item_id));
11596
+ error = null;
11597
+ notify();
11598
+ return decision;
11599
+ },
11600
+ clearReviewDecision(itemId) {
11601
+ reviewDecisions = reviewDecisions.filter((item) => item.item_id !== itemId);
11602
+ error = null;
11603
+ notify();
11604
+ },
11605
+ createReviewDecisionExport(generatedAt) {
11606
+ const source = index ?? (chunked ? { schema_version: chunked.manifest.source_export_schema_version ?? "aiwg.fortemi.index.export.v1" } : null);
11607
+ if (!source) throw new Error("No AIWG index export or chunked manifest loaded");
11608
+ return createAiwgReviewDecisionExport(source, reviewDecisions, generatedAt);
11609
+ },
11610
+ subscribe(listener) {
11611
+ listeners.add(listener);
11612
+ return () => {
11613
+ listeners.delete(listener);
11614
+ };
11615
+ }
11616
+ };
11617
+ }
11618
+ function aiwgFortemiIndexToCommunityGraph(index, options = {}) {
11619
+ const ids = new Set(index.items.map((item) => item.id));
11620
+ const relationshipWeights = options.relationshipWeights ?? /* @__PURE__ */ Object.create(null);
11621
+ const edgeCounts = /* @__PURE__ */ new Map();
11622
+ for (const item of index.items) {
11623
+ for (const relationship of item.relationships) {
11624
+ if (!ids.has(relationship.target_id) && !options.includeDanglingRelationships) continue;
11625
+ const kind = relationship.type;
11626
+ const configuredWeight = Object.prototype.hasOwnProperty.call(relationshipWeights, kind) ? relationshipWeights[kind] : void 0;
11627
+ const baseWeight = typeof configuredWeight === "number" && Number.isFinite(configuredWeight) ? configuredWeight : 1;
11628
+ const key = `${item.id}\0${relationship.target_id}\0${kind}`;
11629
+ const existing = edgeCounts.get(key);
11630
+ if (existing) existing.weight += baseWeight;
11631
+ else edgeCounts.set(key, { source: item.id, target: relationship.target_id, kind, weight: baseWeight });
11632
+ }
11633
+ }
11634
+ const communities = /* @__PURE__ */ new Map();
11635
+ for (const item of index.items) {
11636
+ const communityIds = communityIdsFor(item, options);
11637
+ for (const communityId of communityIds) {
11638
+ const nodes = communities.get(communityId) ?? [];
11639
+ nodes.push(item.id);
11640
+ communities.set(communityId, nodes);
11641
+ }
11642
+ }
11643
+ return {
11644
+ nodes: index.items.map((item) => ({ id: item.id })),
11645
+ edges: Array.from(edgeCounts.values()).sort((left, right) => left.source.localeCompare(right.source) || left.target.localeCompare(right.target) || left.kind.localeCompare(right.kind)),
11646
+ communities: Array.from(communities.entries()).map(([id, nodes]) => ({ id, nodes: [...new Set(nodes)].sort() })).sort((left, right) => left.id.localeCompare(right.id))
11647
+ };
11648
+ }
11649
+ function communityIdsFor(item, options) {
11650
+ if (options.communityFacet) {
11651
+ const values = item.facets[options.communityFacet] ?? [];
11652
+ if (values.length > 0) return values.map((value) => `${options.communityFacet}:${value}`);
11653
+ }
11654
+ if (options.communityTagPrefix) {
11655
+ const prefix = options.communityTagPrefix;
11656
+ const tags = item.tags.filter((tag) => tag.startsWith(prefix));
11657
+ if (tags.length > 0) return tags;
11658
+ }
11659
+ if (item.concepts.length > 0) return item.concepts.map((concept) => `concept:${concept}`);
11660
+ return [`type:${item.type}`];
11661
+ }
11662
+
11663
+ // schemas/aiwg-fortemi-index-export.schema.json
11664
+ var aiwg_fortemi_index_export_schema_default = {
11665
+ $schema: "https://json-schema.org/draft/2020-12/schema",
11666
+ $id: "https://aiwg.io/schemas/aiwg-fortemi-index-export.json",
11667
+ title: "AIWG Fortemi Index Export",
11668
+ type: "object",
11669
+ additionalProperties: false,
11670
+ required: ["schema_version", "generated_at", "source", "items"],
11671
+ properties: {
11672
+ schema_version: {
11673
+ enum: ["aiwg.fortemi.index.export.v1", "aiwg.fortemi.index.export.v2"]
11674
+ },
11675
+ generated_at: {
11676
+ type: "string",
11677
+ format: "date-time"
11678
+ },
11679
+ source: {
11680
+ type: "object",
11681
+ additionalProperties: false,
11682
+ required: ["repo", "privacy"],
11683
+ properties: {
11684
+ repo: {
11685
+ type: "string",
11686
+ minLength: 1
11687
+ },
11688
+ privacy: {
11689
+ $ref: "#/$defs/privacy"
11690
+ },
11691
+ graph: {
11692
+ type: "string",
11693
+ minLength: 1
11694
+ }
11695
+ }
11696
+ },
11697
+ compatibility: {
11698
+ type: "object",
11699
+ additionalProperties: false,
11700
+ required: ["previous_schema_version", "strategy"],
11701
+ properties: {
11702
+ previous_schema_version: {
11703
+ const: "aiwg.fortemi.index.export.v1"
11704
+ },
11705
+ strategy: {
11706
+ const: "supported"
11707
+ }
11708
+ }
11709
+ },
11710
+ items: {
11711
+ type: "array",
11712
+ items: {
11713
+ $ref: "#/$defs/record"
11714
+ }
11715
+ }
11716
+ },
11717
+ allOf: [
11718
+ {
11719
+ if: {
11720
+ properties: {
11721
+ schema_version: {
11722
+ const: "aiwg.fortemi.index.export.v1"
11723
+ }
11724
+ }
11725
+ },
11726
+ then: {
11727
+ not: {
11728
+ required: ["compatibility"]
11729
+ },
11730
+ properties: {
11731
+ source: {
11732
+ not: {
11733
+ required: ["graph"]
11734
+ }
11735
+ },
11736
+ items: {
11737
+ items: {
11738
+ allOf: [
11739
+ {
11740
+ properties: {
11741
+ schema_version: {
11742
+ const: "aiwg.fortemi.index.record.v1"
11743
+ }
11744
+ }
11745
+ },
11746
+ {
11747
+ $ref: "#/$defs/v1RecordCompatibility"
11748
+ }
11749
+ ]
11750
+ }
11751
+ }
11752
+ }
11753
+ }
11754
+ },
11755
+ {
11756
+ if: {
11757
+ properties: {
11758
+ schema_version: {
11759
+ const: "aiwg.fortemi.index.export.v2"
11760
+ }
11761
+ }
11762
+ },
11763
+ then: {
11764
+ required: ["compatibility"],
11765
+ properties: {
11766
+ source: {
11767
+ required: ["graph"]
11768
+ },
11769
+ items: {
11770
+ items: {
11771
+ properties: {
11772
+ schema_version: {
11773
+ const: "aiwg.fortemi.index.record.v2"
11774
+ }
11775
+ }
11776
+ }
11777
+ }
11778
+ }
11779
+ }
11780
+ }
11781
+ ],
11782
+ $defs: {
11783
+ privacy: {
11784
+ enum: ["private", "sanitized", "public"]
12042
11785
  },
12043
- getChunkedManifest() {
12044
- return chunked?.manifest ?? null;
11786
+ recordType: {
11787
+ type: "string",
11788
+ minLength: 1
12045
11789
  },
12046
- getSnapshot() {
12047
- return snapshot();
11790
+ stringArray: {
11791
+ type: "array",
11792
+ items: {
11793
+ type: "string"
11794
+ }
12048
11795
  },
12049
- query(query = "", options) {
12050
- const result = queryAiwgFortemiIndex(requireIndex(), query, options);
12051
- data = result;
12052
- error = null;
12053
- notify();
12054
- return result;
11796
+ numberArray: {
11797
+ type: "array",
11798
+ items: {
11799
+ type: "number"
11800
+ }
12055
11801
  },
12056
- async queryChunked(query = "", options) {
12057
- if (!chunked) throw new Error("No AIWG chunked index manifest loaded");
12058
- try {
12059
- const result = await queryChunkedAiwgFortemiIndex(chunked, query, options);
12060
- data = result;
12061
- error = null;
12062
- notify();
12063
- return result;
12064
- } catch (err) {
12065
- error = err instanceof Error ? err : new Error(String(err));
12066
- notify();
12067
- throw error;
11802
+ v1RecordCompatibility: {
11803
+ type: "object",
11804
+ not: {
11805
+ anyOf: [
11806
+ {
11807
+ required: ["name"]
11808
+ },
11809
+ {
11810
+ required: ["summary"]
11811
+ },
11812
+ {
11813
+ required: ["search"]
11814
+ },
11815
+ {
11816
+ required: ["chunks"]
11817
+ },
11818
+ {
11819
+ required: ["embeddings"]
11820
+ },
11821
+ {
11822
+ required: ["compatibility"]
11823
+ },
11824
+ {
11825
+ required: ["skos_concepts"]
11826
+ },
11827
+ {
11828
+ required: ["skos_relations"]
11829
+ },
11830
+ {
11831
+ required: ["provenance_events"]
11832
+ }
11833
+ ]
11834
+ },
11835
+ properties: {
11836
+ source: {
11837
+ not: {
11838
+ anyOf: [
11839
+ {
11840
+ required: ["origin"]
11841
+ },
11842
+ {
11843
+ required: ["generated"]
11844
+ },
11845
+ {
11846
+ required: ["checksum"]
11847
+ },
11848
+ {
11849
+ required: ["updated_at"]
11850
+ }
11851
+ ]
11852
+ }
11853
+ },
11854
+ relationships: {
11855
+ items: {
11856
+ not: {
11857
+ anyOf: [
11858
+ {
11859
+ required: ["target_path"]
11860
+ },
11861
+ {
11862
+ required: ["direction"]
11863
+ },
11864
+ {
11865
+ required: ["label"]
11866
+ },
11867
+ {
11868
+ required: ["confidence"]
11869
+ },
11870
+ {
11871
+ required: ["privacy"]
11872
+ },
11873
+ {
11874
+ required: ["metadata"]
11875
+ }
11876
+ ]
11877
+ }
11878
+ }
11879
+ },
11880
+ privacy: {
11881
+ not: {
11882
+ required: ["locality"]
11883
+ }
11884
+ }
12068
11885
  }
12069
11886
  },
12070
- async getRecord(id) {
12071
- if (chunked) {
12072
- try {
12073
- return await getChunkRecord(chunked, id);
12074
- } catch (err) {
12075
- error = err instanceof Error ? err : new Error(String(err));
12076
- notify();
12077
- throw error;
11887
+ record: {
11888
+ type: "object",
11889
+ additionalProperties: false,
11890
+ required: [
11891
+ "schema_version",
11892
+ "id",
11893
+ "type",
11894
+ "source",
11895
+ "title",
11896
+ "text",
11897
+ "facets",
11898
+ "tags",
11899
+ "concepts",
11900
+ "relationships",
11901
+ "provenance",
11902
+ "privacy",
11903
+ "updated_at"
11904
+ ],
11905
+ properties: {
11906
+ schema_version: {
11907
+ enum: [
11908
+ "aiwg.fortemi.index.record.v1",
11909
+ "aiwg.fortemi.index.record.v2"
11910
+ ]
11911
+ },
11912
+ id: {
11913
+ type: "string",
11914
+ minLength: 1
11915
+ },
11916
+ type: {
11917
+ $ref: "#/$defs/recordType"
11918
+ },
11919
+ source: {
11920
+ type: "object",
11921
+ additionalProperties: false,
11922
+ required: ["path", "repo_relative_path", "locator"],
11923
+ properties: {
11924
+ path: {
11925
+ type: "string",
11926
+ minLength: 1
11927
+ },
11928
+ repo_relative_path: {
11929
+ type: "string",
11930
+ minLength: 1
11931
+ },
11932
+ locator: {
11933
+ type: "string",
11934
+ minLength: 1
11935
+ },
11936
+ origin: {
11937
+ type: "string",
11938
+ minLength: 1
11939
+ },
11940
+ generated: {
11941
+ type: "boolean"
11942
+ },
11943
+ checksum: {
11944
+ type: "string"
11945
+ },
11946
+ updated_at: {
11947
+ type: "string",
11948
+ format: "date-time"
11949
+ }
11950
+ }
11951
+ },
11952
+ title: {
11953
+ type: "string"
11954
+ },
11955
+ name: {
11956
+ type: "string"
11957
+ },
11958
+ summary: {
11959
+ type: "string"
11960
+ },
11961
+ text: {
11962
+ type: "string"
11963
+ },
11964
+ search: {
11965
+ type: "object",
11966
+ additionalProperties: false,
11967
+ required: [
11968
+ "title",
11969
+ "body",
11970
+ "triggers",
11971
+ "aliases",
11972
+ "tags",
11973
+ "frontmatter"
11974
+ ],
11975
+ properties: {
11976
+ title: {
11977
+ type: "string"
11978
+ },
11979
+ name: {
11980
+ type: "string"
11981
+ },
11982
+ summary: {
11983
+ type: "string"
11984
+ },
11985
+ body: {
11986
+ type: "string"
11987
+ },
11988
+ triggers: {
11989
+ $ref: "#/$defs/stringArray"
11990
+ },
11991
+ aliases: {
11992
+ $ref: "#/$defs/stringArray"
11993
+ },
11994
+ capability: {
11995
+ type: "string"
11996
+ },
11997
+ tags: {
11998
+ $ref: "#/$defs/stringArray"
11999
+ },
12000
+ phase: {
12001
+ type: "string"
12002
+ },
12003
+ type: {
12004
+ type: "string"
12005
+ },
12006
+ frontmatter: {
12007
+ type: "object"
12008
+ }
12009
+ }
12010
+ },
12011
+ facets: {
12012
+ type: "object",
12013
+ additionalProperties: {
12014
+ $ref: "#/$defs/stringArray"
12015
+ }
12016
+ },
12017
+ tags: {
12018
+ $ref: "#/$defs/stringArray"
12019
+ },
12020
+ concepts: {
12021
+ $ref: "#/$defs/stringArray"
12022
+ },
12023
+ relationships: {
12024
+ type: "array",
12025
+ items: {
12026
+ type: "object",
12027
+ additionalProperties: false,
12028
+ required: ["type", "target_id"],
12029
+ properties: {
12030
+ type: {
12031
+ type: "string",
12032
+ minLength: 1
12033
+ },
12034
+ target_id: {
12035
+ type: "string",
12036
+ minLength: 1
12037
+ },
12038
+ source_path: {
12039
+ type: "string"
12040
+ },
12041
+ target_path: {
12042
+ type: "string"
12043
+ },
12044
+ direction: {
12045
+ enum: ["upstream", "downstream", "related"]
12046
+ },
12047
+ label: {
12048
+ type: "string"
12049
+ },
12050
+ confidence: {
12051
+ type: "number"
12052
+ },
12053
+ privacy: {
12054
+ $ref: "#/$defs/privacy"
12055
+ },
12056
+ metadata: {
12057
+ type: "object"
12058
+ }
12059
+ }
12060
+ }
12061
+ },
12062
+ provenance: {
12063
+ type: "array",
12064
+ minItems: 1,
12065
+ items: {
12066
+ type: "object",
12067
+ additionalProperties: false,
12068
+ required: ["field", "source", "path", "confidence", "privacy"],
12069
+ properties: {
12070
+ field: {
12071
+ type: "string",
12072
+ minLength: 1
12073
+ },
12074
+ source: {
12075
+ type: "string",
12076
+ minLength: 1
12077
+ },
12078
+ path: {
12079
+ type: "string",
12080
+ minLength: 1
12081
+ },
12082
+ confidence: {
12083
+ enum: ["source", "candidate", "reviewed", "rejected"]
12084
+ },
12085
+ privacy: {
12086
+ $ref: "#/$defs/privacy"
12087
+ }
12088
+ }
12089
+ }
12090
+ },
12091
+ privacy: {
12092
+ type: "object",
12093
+ additionalProperties: false,
12094
+ required: ["classification", "pii"],
12095
+ properties: {
12096
+ classification: {
12097
+ $ref: "#/$defs/privacy"
12098
+ },
12099
+ pii: {
12100
+ type: "boolean"
12101
+ },
12102
+ locality: {
12103
+ enum: ["project", "framework", "external"]
12104
+ }
12105
+ }
12106
+ },
12107
+ chunks: {
12108
+ type: "array",
12109
+ items: {
12110
+ type: "object",
12111
+ additionalProperties: false,
12112
+ properties: {
12113
+ id: {
12114
+ type: "string",
12115
+ minLength: 1
12116
+ },
12117
+ text: {
12118
+ type: "string"
12119
+ },
12120
+ body: {
12121
+ type: "string"
12122
+ },
12123
+ summary: {
12124
+ type: "string"
12125
+ },
12126
+ source_path: {
12127
+ type: "string"
12128
+ },
12129
+ metadata: {
12130
+ type: "object"
12131
+ },
12132
+ checksum: {
12133
+ type: "string"
12134
+ }
12135
+ }
12136
+ }
12137
+ },
12138
+ embeddings: {
12139
+ type: "array",
12140
+ items: {
12141
+ type: "object",
12142
+ additionalProperties: false,
12143
+ properties: {
12144
+ id: {
12145
+ type: "string"
12146
+ },
12147
+ model: {
12148
+ type: "string"
12149
+ },
12150
+ embedding: {
12151
+ $ref: "#/$defs/numberArray"
12152
+ },
12153
+ vector: {
12154
+ $ref: "#/$defs/numberArray"
12155
+ },
12156
+ granularity: {
12157
+ type: "string"
12158
+ },
12159
+ source_path: {
12160
+ type: "string"
12161
+ },
12162
+ metadata: {
12163
+ type: "object"
12164
+ },
12165
+ chunk_id: {
12166
+ type: "string"
12167
+ },
12168
+ vector_ref: {
12169
+ type: "string"
12170
+ },
12171
+ input_hash: {
12172
+ type: "string"
12173
+ }
12174
+ }
12175
+ }
12176
+ },
12177
+ compatibility: {
12178
+ type: "object"
12179
+ },
12180
+ skos_concepts: {
12181
+ type: "array",
12182
+ items: {
12183
+ type: "object",
12184
+ additionalProperties: false,
12185
+ required: ["id", "prefLabel"],
12186
+ properties: {
12187
+ id: {
12188
+ type: "string",
12189
+ minLength: 1
12190
+ },
12191
+ prefLabel: {
12192
+ type: "string",
12193
+ minLength: 1
12194
+ },
12195
+ definition: {
12196
+ type: "string"
12197
+ },
12198
+ scheme: {
12199
+ type: "string"
12200
+ },
12201
+ notation: {
12202
+ type: "string"
12203
+ },
12204
+ uri: {
12205
+ type: "string"
12206
+ },
12207
+ altLabels: {
12208
+ $ref: "#/$defs/stringArray"
12209
+ },
12210
+ metadata: {
12211
+ type: "object"
12212
+ }
12213
+ }
12214
+ }
12215
+ },
12216
+ skos_relations: {
12217
+ type: "array",
12218
+ items: {
12219
+ type: "object",
12220
+ additionalProperties: false,
12221
+ required: ["type", "source_id", "target_id"],
12222
+ properties: {
12223
+ type: {
12224
+ type: "string",
12225
+ minLength: 1
12226
+ },
12227
+ source_id: {
12228
+ type: "string",
12229
+ minLength: 1
12230
+ },
12231
+ target_id: {
12232
+ type: "string",
12233
+ minLength: 1
12234
+ },
12235
+ source_path: {
12236
+ type: "string"
12237
+ },
12238
+ metadata: {
12239
+ type: "object"
12240
+ }
12241
+ }
12242
+ }
12243
+ },
12244
+ provenance_events: {
12245
+ type: "array",
12246
+ items: {
12247
+ type: "object",
12248
+ additionalProperties: false,
12249
+ required: ["activity"],
12250
+ properties: {
12251
+ id: {
12252
+ type: "string"
12253
+ },
12254
+ activity: {
12255
+ type: "string",
12256
+ minLength: 1
12257
+ },
12258
+ agent: {
12259
+ type: "string"
12260
+ },
12261
+ started_at: {
12262
+ type: "string",
12263
+ format: "date-time"
12264
+ },
12265
+ ended_at: {
12266
+ type: "string",
12267
+ format: "date-time"
12268
+ },
12269
+ source: {
12270
+ type: "string"
12271
+ },
12272
+ path: {
12273
+ type: "string"
12274
+ },
12275
+ confidence: {
12276
+ enum: ["source", "candidate", "reviewed", "rejected"]
12277
+ },
12278
+ privacy: {
12279
+ $ref: "#/$defs/privacy"
12280
+ },
12281
+ attributes: {
12282
+ type: "object"
12283
+ }
12284
+ }
12285
+ }
12286
+ },
12287
+ updated_at: {
12288
+ type: "string",
12289
+ format: "date-time"
12078
12290
  }
12079
12291
  }
12080
- const found = requireIndex().items.find((item) => item.id === id);
12081
- if (!found) throw new Error("Record not found: " + id);
12082
- return found;
12083
- },
12084
- async neighbors(id, options) {
12085
- try {
12086
- const queryOptions = neighborQueryOptions(id, options);
12087
- const result = chunked ? await relationshipResultFromChunkedRuntime(chunked, queryOptions) : relationshipResultFromRecords(requireIndex().items, queryOptions);
12088
- return filterNeighborResult(id, result, options);
12089
- } catch (err) {
12090
- error = err instanceof Error ? err : new Error(String(err));
12091
- notify();
12092
- throw error;
12093
- }
12094
- },
12095
- async relationshipQuery(options) {
12096
- try {
12097
- return chunked ? await relationshipResultFromChunkedRuntime(chunked, options) : relationshipResultFromRecords(requireIndex().items, options);
12098
- } catch (err) {
12099
- error = err instanceof Error ? err : new Error(String(err));
12100
- notify();
12101
- throw error;
12102
- }
12103
- },
12104
- async relationshipSet(options) {
12105
- const [left, right] = await Promise.all([
12106
- this.neighbors(options.a, options),
12107
- this.neighbors(options.b, options)
12108
- ]);
12109
- const leftIds = new Set(left.nodes.map((node) => node.id).filter((id) => id !== options.a));
12110
- const rightIds = new Set(right.nodes.map((node) => node.id).filter((id) => id !== options.b));
12111
- let ids;
12112
- if (options.op === "intersection") ids = [...leftIds].filter((id) => rightIds.has(id));
12113
- else if (options.op === "difference") ids = [...leftIds].filter((id) => !rightIds.has(id));
12114
- else ids = [.../* @__PURE__ */ new Set([...leftIds, ...rightIds])];
12115
- return { op: options.op, ids: ids.sort() };
12116
- },
12117
- clearChunkCache() {
12118
- chunked?.partCache.clear();
12119
- chunked?.detailCache.clear();
12120
- chunked?.matchCache.clear();
12121
- error = null;
12122
- notify();
12123
- },
12124
- toCommunityGraph(options) {
12125
- return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
12126
- },
12127
- async toCommunityGraphChunked(options) {
12128
- if (!chunked) return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
12129
- const loaded = await recordsFromChunkedRuntime(chunked, options?.onProgress);
12130
- return aiwgFortemiIndexToCommunityGraph({
12131
- generated_at: chunked.manifest.generated_at,
12132
- source: chunked.manifest.source,
12133
- items: loaded.records
12134
- }, options);
12135
- },
12136
- setReviewDecision(input) {
12137
- const decision = {
12138
- ...input,
12139
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
12140
- };
12141
- reviewDecisions = [
12142
- ...reviewDecisions.filter((item) => item.item_id !== decision.item_id),
12143
- decision
12144
- ].sort((left, right) => left.item_id.localeCompare(right.item_id));
12145
- error = null;
12146
- notify();
12147
- return decision;
12148
- },
12149
- clearReviewDecision(itemId) {
12150
- reviewDecisions = reviewDecisions.filter((item) => item.item_id !== itemId);
12151
- error = null;
12152
- notify();
12153
- },
12154
- createReviewDecisionExport(generatedAt) {
12155
- const source = index ?? (chunked ? { schema_version: chunked.manifest.source_export_schema_version ?? "aiwg.fortemi.index.export.v1" } : null);
12156
- if (!source) throw new Error("No AIWG index export or chunked manifest loaded");
12157
- return createAiwgReviewDecisionExport(source, reviewDecisions, generatedAt);
12158
- },
12159
- subscribe(listener) {
12160
- listeners.add(listener);
12161
- return () => {
12162
- listeners.delete(listener);
12163
- };
12164
- }
12165
- };
12166
- }
12167
- function aiwgFortemiIndexToCommunityGraph(index, options = {}) {
12168
- const ids = new Set(index.items.map((item) => item.id));
12169
- const relationshipWeights = options.relationshipWeights ?? /* @__PURE__ */ Object.create(null);
12170
- const edgeCounts = /* @__PURE__ */ new Map();
12171
- for (const item of index.items) {
12172
- for (const relationship of item.relationships) {
12173
- if (!ids.has(relationship.target_id) && !options.includeDanglingRelationships) continue;
12174
- const kind = relationship.type;
12175
- const configuredWeight = Object.prototype.hasOwnProperty.call(relationshipWeights, kind) ? relationshipWeights[kind] : void 0;
12176
- const baseWeight = typeof configuredWeight === "number" && Number.isFinite(configuredWeight) ? configuredWeight : 1;
12177
- const key = `${item.id}\0${relationship.target_id}\0${kind}`;
12178
- const existing = edgeCounts.get(key);
12179
- if (existing) existing.weight += baseWeight;
12180
- else edgeCounts.set(key, { source: item.id, target: relationship.target_id, kind, weight: baseWeight });
12181
- }
12182
- }
12183
- const communities = /* @__PURE__ */ new Map();
12184
- for (const item of index.items) {
12185
- const communityIds = communityIdsFor(item, options);
12186
- for (const communityId of communityIds) {
12187
- const nodes = communities.get(communityId) ?? [];
12188
- nodes.push(item.id);
12189
- communities.set(communityId, nodes);
12190
12292
  }
12191
12293
  }
12192
- return {
12193
- nodes: index.items.map((item) => ({ id: item.id })),
12194
- edges: Array.from(edgeCounts.values()).sort((left, right) => left.source.localeCompare(right.source) || left.target.localeCompare(right.target) || left.kind.localeCompare(right.kind)),
12195
- communities: Array.from(communities.entries()).map(([id, nodes]) => ({ id, nodes: [...new Set(nodes)].sort() })).sort((left, right) => left.id.localeCompare(right.id))
12196
- };
12294
+ };
12295
+
12296
+ // src/aiwg-index-schema.ts
12297
+ var PROJECTED_FIELDS = [
12298
+ "schema_version",
12299
+ "id",
12300
+ "type",
12301
+ "title",
12302
+ "text",
12303
+ "facets",
12304
+ "tags",
12305
+ "concepts",
12306
+ "privacy"
12307
+ ];
12308
+ var ajvInstance2;
12309
+ var exportValidator;
12310
+ var projectedRecordValidator;
12311
+ function getAiwgFortemiIndexExportSchema() {
12312
+ return aiwg_fortemi_index_export_schema_default;
12197
12313
  }
12198
- function communityIdsFor(item, options) {
12199
- if (options.communityFacet) {
12200
- const values = item.facets[options.communityFacet] ?? [];
12201
- if (values.length > 0) return values.map((value) => `${options.communityFacet}:${value}`);
12314
+ function getAjv2() {
12315
+ if (!ajvInstance2) {
12316
+ ajvInstance2 = new Ajv2020({
12317
+ allErrors: true,
12318
+ strict: false,
12319
+ validateFormats: false
12320
+ });
12321
+ ajvInstance2.addSchema(aiwg_fortemi_index_export_schema_default);
12202
12322
  }
12203
- if (options.communityTagPrefix) {
12204
- const prefix = options.communityTagPrefix;
12205
- const tags = item.tags.filter((tag) => tag.startsWith(prefix));
12206
- if (tags.length > 0) return tags;
12323
+ return ajvInstance2;
12324
+ }
12325
+ function formatErrors2(errors) {
12326
+ return (errors ?? []).map((error) => {
12327
+ const path = error.instancePath || "(root)";
12328
+ return `${path} ${error.message ?? "is invalid"}`;
12329
+ });
12330
+ }
12331
+ function getExportValidator() {
12332
+ exportValidator ??= getAjv2().getSchema(aiwg_fortemi_index_export_schema_default.$id) ?? getAjv2().compile(aiwg_fortemi_index_export_schema_default);
12333
+ return exportValidator;
12334
+ }
12335
+ function getProjectedRecordValidator() {
12336
+ if (!projectedRecordValidator) {
12337
+ const properties = Object.fromEntries(Object.keys(aiwg_fortemi_index_export_schema_default.$defs.record.properties).map((field) => [
12338
+ field,
12339
+ { $ref: `${aiwg_fortemi_index_export_schema_default.$id}#/$defs/record/properties/${field}` }
12340
+ ]));
12341
+ projectedRecordValidator = getAjv2().compile({
12342
+ type: "object",
12343
+ required: PROJECTED_FIELDS,
12344
+ properties,
12345
+ additionalProperties: true,
12346
+ allOf: [
12347
+ {
12348
+ if: {
12349
+ properties: {
12350
+ schema_version: { const: "aiwg.fortemi.index.record.v1" }
12351
+ }
12352
+ },
12353
+ then: { $ref: `${aiwg_fortemi_index_export_schema_default.$id}#/$defs/v1RecordCompatibility` }
12354
+ }
12355
+ ]
12356
+ });
12207
12357
  }
12208
- if (item.concepts.length > 0) return item.concepts.map((concept) => `concept:${concept}`);
12209
- return [`type:${item.type}`];
12358
+ return projectedRecordValidator;
12359
+ }
12360
+ function validateAiwgFortemiIndexExportSchema(value) {
12361
+ const validate = getExportValidator();
12362
+ const schemaValue = value && typeof value === "object" && Array.isArray(value.items) ? {
12363
+ ...value,
12364
+ items: value.items.map((item) => {
12365
+ if (!item || typeof item !== "object" || Array.isArray(item)) return item;
12366
+ const schemaRecord = { ...item };
12367
+ Reflect.deleteProperty(schemaRecord, "binary_sources");
12368
+ return schemaRecord;
12369
+ })
12370
+ } : value;
12371
+ const valid = validate(schemaValue);
12372
+ return { valid, errors: formatErrors2(validate.errors) };
12373
+ }
12374
+ function validateAiwgFortemiProjectedRecordSchema(value) {
12375
+ const validate = getProjectedRecordValidator();
12376
+ const valid = validate(value);
12377
+ return { valid, errors: formatErrors2(validate.errors) };
12210
12378
  }
12211
12379
 
12212
12380
  // src/index.ts
12213
- var VERSION = "2026.7.4";
12381
+ var VERSION = "2026.7.5";
12214
12382
 
12215
12383
  export { AIWG_SCAN_REQUIRED_FIELDS, ArchiveManager, AttachmentsRepository, CURRENT_MIGRATION_HEAD, CURRENT_SHARD_VERSION, CapabilityManager, CaptureKnowledgeInputSchema, CollectionsRepository, CommunitiesRepository, DB_SNAPSHOT_SCHEMA_VERSION, DbSnapshotVersionError, EMBED_REQUEST_KIND, EMBED_RESPONSE_KIND, EmbeddingSetsRepository, FORTEMI_COMPATIBILITY_PATH, FORTEMI_COMPATIBILITY_STATES, FORTEMI_REQUIRED_COMPATIBILITY_CAPABILITIES, FallbackRouter, FortemiToolManifest, GetNoteInputSchema, GraphRepository, JOB_CAPABILITIES, JOB_PRIORITIES, JobQueueWorker, LOCAL_ENDPOINTS, LinksRepository, ListNotesInputSchema, ManageArchiveInputSchema, ManageAttachmentsInputSchema, ManageCapabilitiesInputSchema, ManageCollectionsInputSchema, ManageLinksInputSchema, ManageNoteInputSchema, ManageTagsInputSchema, MemoryBlobStore, MigrationRunner, NotesRepository, OpenAICompatibleProvider, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, ProvenanceRepository, ProviderRegistry, SHARD_FORMAT, SUPPORTED_PGLITE_VERSION, SearchInputSchema, SearchRepository, SkosRepository, TagsRepository, TransactionProxy, TypedEventBus, VERSION, aiRevisionHandler, aiwgFortemiIndexToCommunityGraph, allMigrations, appendPluginScript, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, assertShardComponentRecord, buildAiwgChunkedIndex, buildAiwgStaticEmbeddingSet, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, clearPrefetchedShard, collectionFromShard, collectionToShard, computeBlobHash, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, createBlobStore, createCosineSemanticProvider, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteBackend, createPGliteInstance, createRemoteBackend, createRoutes, createShardBackend, createWorkerEmbedFunction, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, dumpDbSnapshot, embeddingConfigToShard, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchAndValidateFortemiCompatibility, fetchPluginScript, filterAiwgRecordsByPrivacy, findAiwgStaticDuplicatePairs, formatFortemiCompatibilitySummary, fortemiCompatibilityUrl, fortemiManifest, fromPrefetched, generateId, getAiwgFortemiFacets, getAiwgFortemiIndexExportSchema, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getKnowledgeShardSchema, getLlmFunction, getNote, getPrefetchedSha256, handleEmbedRequests, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, isShardPrefetched, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, openShard, packTarGz, parseCspReport, prefetchShard, provenanceEdgeToShard, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, registerLlmCapability, registerSemanticCapability, registerSemanticCapabilityWorker, registerServiceWorker, restoreDbSnapshot, searchTool, selectBackend, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsToShard, templateToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, urlLinkToShard, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgFortemiIndexExportSchema, validateAiwgFortemiProjectedRecordSchema, validateAiwgStaticEmbeddingSet, validateChecksums, validateFortemiCompatibilityResponse, validateShardArchive, validateShardComponentRecord, validateShardManifest, verifyDbSnapshotMeta, verifySri };
12216
12384
  //# sourceMappingURL=index.js.map