@fortemi/core 2026.6.0 → 2026.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,7 +38,7 @@ Most browser note and knowledge apps choose between a thin IndexedDB wrapper, a
38
38
  | Queryable knowledge | SQL-backed repositories for notes, links, tags, collections, SKOS concepts, jobs, and search |
39
39
  | Retrieval quality | Full-text search, pgvector-backed semantic search, hybrid ranking, snippets, facets, and filters |
40
40
  | AI-ready workflows | Optional embeddings, local LLM capability discovery, job provenance, and fallback routing |
41
- | Portable archives | Knowledge Shard tar.gz import/export with checksums and JSON format parity |
41
+ | Portable archives | Knowledge Shard tar.gz import/export with set-scoped exports, chunked imports, checksums, and JSON format parity |
42
42
  | Agent integration | Manifest-backed tools and direct helper functions for bridge adapters and automation |
43
43
  | UI freedom | A headless package you can use from React, another framework, a browser extension, or a custom host |
44
44
 
@@ -102,6 +102,62 @@ const results = await search.search('hello')
102
102
  await registerServiceWorker()
103
103
  ```
104
104
 
105
+ ## Static AIWG Index Search
106
+
107
+ Static documentation hosts can import the AIWG index helpers without pulling in
108
+ PGlite, workers, shards, or browser storage:
109
+
110
+ ```ts
111
+ import { createAiwgIndexController } from '@fortemi/core/aiwg-index'
112
+
113
+ const controller = createAiwgIndexController()
114
+ controller.loadIndex(await fetch('/aiwg-index.json').then((res) => res.json()))
115
+
116
+ const results = controller.query('deployment', {
117
+ types: ['docs.page'],
118
+ rank: true,
119
+ snippets: true,
120
+ limit: 10,
121
+ })
122
+ ```
123
+
124
+ Use this subpath for Pagenary-style command palettes, static docs search, and
125
+ vanilla JavaScript review surfaces. The top-level `@fortemi/core` export remains
126
+ available for full archive/runtime integrations.
127
+
128
+ Large static indexes can use the chunked browser path instead of downloading one
129
+ full `aiwg.fortemi.index.export.v1` file. Host a manifest plus deterministic part
130
+ files:
131
+
132
+ ```text
133
+ /search/aiwg-index/manifest.json
134
+ /search/aiwg-index/part-0000.json
135
+ /search/aiwg-index/part-0001.json
136
+ ```
137
+
138
+ ```ts
139
+ import {
140
+ createAiwgFetchChunkLoader,
141
+ createAiwgIndexController,
142
+ } from '@fortemi/core/aiwg-index'
143
+
144
+ const controller = createAiwgIndexController()
145
+ const manifest = await fetch('/search/aiwg-index/manifest.json').then((res) => res.json())
146
+
147
+ controller.loadChunkedIndex(
148
+ manifest,
149
+ createAiwgFetchChunkLoader('/search/aiwg-index/'),
150
+ { maxCachedParts: 3 },
151
+ )
152
+
153
+ const page = await controller.queryChunked('', { offset: 100, limit: 25 })
154
+ ```
155
+
156
+ Unfiltered browse requests fetch only the part files intersecting the requested
157
+ `offset` and `limit`. Filtered or ranked searches scan part files to compute exact
158
+ results, but the controller keeps only a bounded part cache and never sets a
159
+ materialized full export in `getIndex()`.
160
+
105
161
  ## What You Get
106
162
 
107
163
  | Surface | Description |
@@ -111,7 +167,7 @@ await registerServiceWorker()
111
167
  | Event bus | Typed subscriptions for note, job, archive, and capability events |
112
168
  | Capability system | Embeddings, local LLM, GPU detection, local-provider discovery, fallback routing |
113
169
  | Job queue | Server-compatible background workflow for revisions, titles, embeddings, concepts, and links |
114
- | Knowledge Shards | Tar.gz import/export with checksums and JSON format parity |
170
+ | Knowledge Shards | Tar.gz import/export with checksums, progress callbacks, yielding imports, set-scoped embedding exports, and JSON format parity |
115
171
  | Service-worker helpers | Route registration primitives for standalone browser integration |
116
172
 
117
173
  ## Search and Knowledge Model
@@ -144,11 +200,11 @@ Use the manifest when a host needs to advertise Fortemi operations to an agent r
144
200
  | `idb` | IndexedDB-backed PGlite data directory | Firefox and broad compatibility |
145
201
  | `memory` | In-memory database | Tests, demos, restricted browser contexts |
146
202
 
147
- Data stays in the selected browser storage mode unless your application explicitly exports it, imports it, or wires external providers. Optional AI capabilities are opt-in and can be routed to local WASM, local provider servers, or host-provided integrations depending on your product requirements.
203
+ Data stays in the selected browser storage mode unless your application explicitly exports it, imports it, or wires external providers. Optional AI capabilities are opt-in and can be routed to local WASM, local provider servers, OpenAI-compatible APIs, or host-provided integrations depending on your product requirements. API keys should live only in browser or machine secure storage; if secure storage is unavailable, do not persist them.
148
204
 
149
205
  ## React Bindings
150
206
 
151
- For React applications, install `@fortemi/react`. It wraps `@fortemi/core` with `FortemiProvider`, context access, and 21 hooks.
207
+ For React applications, install `@fortemi/react`. It wraps `@fortemi/core` with `FortemiProvider`, context access, worker-mode PGlite, graph visualization primitives, and the React hook surface.
152
208
 
153
209
  ```bash
154
210
  pnpm add @fortemi/react @fortemi/core react
@@ -0,0 +1,212 @@
1
+ type AiwgFortemiRecordType = 'crm.contact' | 'crm.organization' | 'crm.event' | 'crm.interaction' | 'aiwg.artifact' | 'docs.page';
2
+ type AiwgPrivacyClassification = 'private' | 'sanitized' | 'public';
3
+ type AiwgProvenanceConfidence = 'source' | 'candidate' | 'reviewed' | 'rejected';
4
+ type AiwgReviewAction = 'accept' | 'reject' | 'defer';
5
+ interface AiwgFortemiRecordSource {
6
+ path: string;
7
+ repo_relative_path: string;
8
+ locator: string;
9
+ }
10
+ interface AiwgFortemiRelationship {
11
+ type: string;
12
+ target_id: string;
13
+ source_path?: string;
14
+ }
15
+ interface AiwgFortemiProvenance {
16
+ field: string;
17
+ source: string;
18
+ path: string;
19
+ confidence: AiwgProvenanceConfidence;
20
+ privacy: AiwgPrivacyClassification;
21
+ }
22
+ interface AiwgFortemiRecord {
23
+ schema_version: 'aiwg.fortemi.index.record.v1';
24
+ id: string;
25
+ type: AiwgFortemiRecordType;
26
+ source: AiwgFortemiRecordSource;
27
+ title: string;
28
+ text: string;
29
+ facets: Record<string, string[]>;
30
+ tags: string[];
31
+ concepts: string[];
32
+ relationships: AiwgFortemiRelationship[];
33
+ provenance: AiwgFortemiProvenance[];
34
+ privacy: {
35
+ classification: AiwgPrivacyClassification;
36
+ pii: boolean;
37
+ };
38
+ updated_at: string;
39
+ }
40
+ interface AiwgFortemiIndexExport {
41
+ schema_version: 'aiwg.fortemi.index.export.v1';
42
+ generated_at: string;
43
+ source: {
44
+ repo: string;
45
+ privacy: AiwgPrivacyClassification;
46
+ };
47
+ items: AiwgFortemiRecord[];
48
+ }
49
+ interface AiwgFortemiChunkPartRef {
50
+ href: string;
51
+ offset: number;
52
+ count: number;
53
+ }
54
+ interface AiwgFortemiChunkManifest {
55
+ schema_version: 'aiwg.fortemi.index.chunk-manifest.v1';
56
+ generated_at: string;
57
+ source: AiwgFortemiIndexExport['source'];
58
+ total: number;
59
+ part_size: number;
60
+ facets?: Record<string, Record<string, number>>;
61
+ parts: AiwgFortemiChunkPartRef[];
62
+ }
63
+ interface AiwgFortemiChunkPart {
64
+ schema_version: 'aiwg.fortemi.index.chunk.v1';
65
+ manifest_schema_version: 'aiwg.fortemi.index.chunk-manifest.v1';
66
+ offset: number;
67
+ items: AiwgFortemiRecord[];
68
+ }
69
+ interface AiwgIndexValidationResult {
70
+ valid: boolean;
71
+ errors: string[];
72
+ counts: Partial<Record<AiwgFortemiRecordType, number>>;
73
+ }
74
+ interface AiwgChunkedIndexValidationResult {
75
+ valid: boolean;
76
+ errors: string[];
77
+ }
78
+ interface AiwgIndexQueryOptions {
79
+ types?: AiwgFortemiRecordType[];
80
+ facets?: Record<string, string[]>;
81
+ tags?: string[];
82
+ concepts?: string[];
83
+ privacy?: AiwgPrivacyClassification[];
84
+ relationshipTargetId?: string;
85
+ limit?: number;
86
+ offset?: number;
87
+ rank?: boolean;
88
+ snippets?: boolean;
89
+ snippetLength?: number;
90
+ weights?: Partial<AiwgIndexQueryWeights>;
91
+ includeMatches?: boolean;
92
+ }
93
+ interface AiwgIndexQueryWeights {
94
+ title: number;
95
+ text: number;
96
+ tag: number;
97
+ concept: number;
98
+ }
99
+ interface AiwgIndexQueryMatch {
100
+ field: 'title' | 'text' | 'tag' | 'concept';
101
+ value: string;
102
+ }
103
+ interface AiwgIndexQueryRankedItem {
104
+ item: AiwgFortemiRecord;
105
+ rank: number;
106
+ snippet?: string;
107
+ matches?: AiwgIndexQueryMatch[];
108
+ }
109
+ interface AiwgIndexQueryResult {
110
+ items: AiwgFortemiRecord[];
111
+ total: number;
112
+ facets: Record<string, Record<string, number>>;
113
+ rankedItems?: AiwgIndexQueryRankedItem[];
114
+ }
115
+ type AiwgChunkedIndexLoader = (part: AiwgFortemiChunkPartRef, manifest: AiwgFortemiChunkManifest) => Promise<unknown>;
116
+ interface AiwgChunkedIndexLoadOptions {
117
+ maxCachedParts?: number;
118
+ }
119
+ type AiwgChunkedIndexProgressPhase = 'part' | 'query';
120
+ interface AiwgChunkedIndexProgress {
121
+ phase: AiwgChunkedIndexProgressPhase;
122
+ done: number;
123
+ total: number;
124
+ href?: string;
125
+ }
126
+ interface AiwgChunkedIndexQueryOptions extends AiwgIndexQueryOptions {
127
+ onProgress?: (progress: AiwgChunkedIndexProgress) => void;
128
+ }
129
+ interface AiwgChunkedIndexQueryResult extends AiwgIndexQueryResult {
130
+ manifestTotal: number;
131
+ scannedParts: number;
132
+ fetchedParts: number;
133
+ complete: boolean;
134
+ }
135
+ interface AiwgReviewDecision {
136
+ item_id: string;
137
+ action: AiwgReviewAction;
138
+ reason?: string;
139
+ updated_at: string;
140
+ }
141
+ interface AiwgReviewDecisionExport {
142
+ schema_version: 'aiwg.fortemi.review-decisions.v1';
143
+ generated_at: string;
144
+ source_export_schema_version: string;
145
+ decisions: AiwgReviewDecision[];
146
+ }
147
+ interface AiwgIndexGraphOptions {
148
+ communityFacet?: string;
149
+ communityTagPrefix?: string;
150
+ relationshipWeights?: Record<string, number>;
151
+ includeDanglingRelationships?: boolean;
152
+ }
153
+ interface AiwgReviewInput {
154
+ item_id: string;
155
+ action: AiwgReviewAction;
156
+ reason?: string;
157
+ }
158
+ interface AiwgIndexControllerSnapshot {
159
+ index: AiwgFortemiIndexExport | null;
160
+ chunked: {
161
+ manifest: AiwgFortemiChunkManifest;
162
+ cachedParts: number;
163
+ maxCachedParts: number;
164
+ } | null;
165
+ data: AiwgIndexQueryResult | null;
166
+ error: Error | null;
167
+ reviewDecisions: AiwgReviewDecision[];
168
+ }
169
+ type AiwgIndexControllerListener = (snapshot: AiwgIndexControllerSnapshot) => void;
170
+ interface AiwgIndexController {
171
+ loadIndex(value: unknown): AiwgFortemiIndexExport;
172
+ loadChunkedIndex(manifest: unknown, loader: AiwgChunkedIndexLoader, options?: AiwgChunkedIndexLoadOptions): AiwgFortemiChunkManifest;
173
+ getIndex(): AiwgFortemiIndexExport | null;
174
+ getChunkedManifest(): AiwgFortemiChunkManifest | null;
175
+ getSnapshot(): AiwgIndexControllerSnapshot;
176
+ query(query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult;
177
+ queryChunked(query?: string, options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult>;
178
+ clearChunkCache(): void;
179
+ toCommunityGraph(options?: AiwgIndexGraphOptions): ReturnType<typeof aiwgFortemiIndexToCommunityGraph>;
180
+ setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision;
181
+ clearReviewDecision(itemId: string): void;
182
+ createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport;
183
+ subscribe(listener: AiwgIndexControllerListener): () => void;
184
+ }
185
+ declare function validateAiwgFortemiIndexExport(value: unknown): AiwgIndexValidationResult;
186
+ declare function assertAiwgFortemiIndexExport(value: unknown): AiwgFortemiIndexExport;
187
+ declare function validateAiwgFortemiChunkManifest(value: unknown): AiwgChunkedIndexValidationResult;
188
+ declare function assertAiwgFortemiChunkManifest(value: unknown): AiwgFortemiChunkManifest;
189
+ declare function validateAiwgFortemiChunkPart(value: unknown, partRef?: AiwgFortemiChunkPartRef, manifest?: AiwgFortemiChunkManifest): AiwgChunkedIndexValidationResult;
190
+ declare function assertAiwgFortemiChunkPart(value: unknown, partRef?: AiwgFortemiChunkPartRef, manifest?: AiwgFortemiChunkManifest): AiwgFortemiChunkPart;
191
+ declare function createAiwgFetchChunkLoader(baseUrl?: string | URL): AiwgChunkedIndexLoader;
192
+ declare function getAiwgFortemiFacets(items: AiwgFortemiRecord[]): Record<string, Record<string, number>>;
193
+ declare function queryAiwgFortemiIndex(index: AiwgFortemiIndexExport, query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult;
194
+ declare function createAiwgReviewDecisionExport(source: AiwgFortemiIndexExport, decisions: AiwgReviewDecision[], generatedAt?: string): AiwgReviewDecisionExport;
195
+ declare function createAiwgIndexController(initialIndex?: AiwgFortemiIndexExport): AiwgIndexController;
196
+ declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport, options?: AiwgIndexGraphOptions): {
197
+ nodes: {
198
+ id: string;
199
+ }[];
200
+ edges: {
201
+ source: string;
202
+ target: string;
203
+ kind: string;
204
+ weight: number;
205
+ }[];
206
+ communities: {
207
+ id: string;
208
+ nodes: string[];
209
+ }[];
210
+ };
211
+
212
+ export { type AiwgChunkedIndexLoadOptions, type AiwgChunkedIndexLoader, type AiwgChunkedIndexProgress, type AiwgChunkedIndexProgressPhase, type AiwgChunkedIndexQueryOptions, type AiwgChunkedIndexQueryResult, type AiwgChunkedIndexValidationResult, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiProvenance, type AiwgFortemiRecord, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgIndexController, type AiwgIndexControllerListener, type AiwgIndexControllerSnapshot, type AiwgIndexGraphOptions, type AiwgIndexQueryMatch, type AiwgIndexQueryOptions, type AiwgIndexQueryRankedItem, type AiwgIndexQueryResult, type AiwgIndexQueryWeights, type AiwgIndexValidationResult, type AiwgPrivacyClassification, type AiwgProvenanceConfidence, type AiwgReviewAction, type AiwgReviewDecision, type AiwgReviewDecisionExport, type AiwgReviewInput, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, createAiwgFetchChunkLoader, createAiwgIndexController, createAiwgReviewDecisionExport, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };