dsh-mnemon-source-memory-spaces 0.5.0-rc.1
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/LICENSE +21 -0
- package/README.md +38 -0
- package/lib/client.js +3462 -0
- package/lib/contracts.d.ts +498 -0
- package/lib/contracts.js +41 -0
- package/lib/definitions-CEpa-tvm.d.ts +135 -0
- package/lib/definitions-DfmOqJjR.js +214 -0
- package/lib/index.d.ts +47 -0
- package/lib/index.js +3456 -0
- package/lib/plugin-DlsNeZbQ.js +388 -0
- package/lib/process-B-t3UflO.js +81 -0
- package/lib/provider-sdk.d.ts +54 -0
- package/lib/provider-sdk.js +105 -0
- package/lib/testing.d.ts +28 -0
- package/lib/testing.js +106 -0
- package/lib/types/client/ProviderIcon.d.ts +10 -0
- package/lib/types/client/api.d.ts +39 -0
- package/lib/types/client/pages.d.ts +72 -0
- package/lib/types/client/provider-presentation.d.ts +6 -0
- package/lib/types/client/ui.d.ts +17 -0
- package/lib/types/client.d.ts +3 -0
- package/lib/types/contracts.d.ts +496 -0
- package/package.json +103 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { a as digest, i as defineMemorySpaceProviderDefinition, o as requiredId } from "./definitions-DfmOqJjR.js";
|
|
2
|
+
//#region src/providers/catalog.ts
|
|
3
|
+
function memoryProviderDescriptor(id, catalog = []) {
|
|
4
|
+
const descriptor = catalog.find((candidate) => candidate.id === id);
|
|
5
|
+
if (descriptor === void 0) throw new Error(`unsupported memory provider: ${String(id)}`);
|
|
6
|
+
return descriptor;
|
|
7
|
+
}
|
|
8
|
+
function normalizeUrl(value, label) {
|
|
9
|
+
const normalized = value.trim().replace(/\/+$/u, "");
|
|
10
|
+
let url;
|
|
11
|
+
try {
|
|
12
|
+
url = new URL(normalized);
|
|
13
|
+
} catch {
|
|
14
|
+
throw new Error(`${label} must be a valid http(s) URL`);
|
|
15
|
+
}
|
|
16
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error(`${label} must use http or https`);
|
|
17
|
+
if (url.username !== "" || url.password !== "") throw new Error(`${label} must not contain credentials`);
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|
|
20
|
+
function normalizeString(value, field) {
|
|
21
|
+
let normalized = typeof value === "string" ? value.trim() : value === void 0 || value === null ? "" : String(value).trim();
|
|
22
|
+
if (field.normalize === "trim-trailing-slash") normalized = normalized.replace(/\/+$/u, "");
|
|
23
|
+
const maximum = field.maxLength ?? (field.input === "secret" ? 8e3 : 2e3);
|
|
24
|
+
if (normalized.length > maximum) throw new Error(`${field.label} is too long (max ${maximum} characters)`);
|
|
25
|
+
if (field.required && normalized === "") throw new Error(`${field.label} is required`);
|
|
26
|
+
if (field.input === "url" && normalized !== "") return normalizeUrl(normalized, field.label);
|
|
27
|
+
if (field.options !== void 0 && normalized !== "" && !field.options.some((option) => option.value === normalized)) throw new Error(`${field.label} has an unsupported value`);
|
|
28
|
+
if (field.pattern !== void 0 && normalized !== "" && !new RegExp(field.pattern, "u").test(normalized)) throw new Error(field.validationMessage ?? `${field.label.charAt(0).toLowerCase()}${field.label.slice(1)} has an invalid format`);
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
function validateFieldBounds(field, value) {
|
|
32
|
+
if (field.min !== void 0 && field.max !== void 0 && (value < field.min || value > field.max)) throw new Error(`${field.label.charAt(0).toLowerCase()}${field.label.slice(1)} must be within ${field.min}..${field.max}`);
|
|
33
|
+
if (field.min !== void 0 && value < field.min) throw new Error(`${field.label} must be at least ${field.min}`);
|
|
34
|
+
if (field.max !== void 0 && value > field.max) throw new Error(`${field.label} must be at most ${field.max}`);
|
|
35
|
+
}
|
|
36
|
+
function normalizeScopedProviderConnection(providerId, scope, input, previous = {}, clearSecrets = [], catalog = []) {
|
|
37
|
+
const descriptor = memoryProviderDescriptor(providerId, catalog);
|
|
38
|
+
if ((descriptor.typeId ?? descriptor.id) === "mnemon-native") return {};
|
|
39
|
+
const fields = descriptor.fields.filter((item) => item.scope === scope);
|
|
40
|
+
const allowed = new Set(fields.map((item) => item.key));
|
|
41
|
+
for (const key of Object.keys(input ?? {})) if (!allowed.has(key)) throw new Error(`unsupported ${descriptor.label} ${scope} setting: ${key}`);
|
|
42
|
+
for (const key of clearSecrets) if (fields.find((item) => item.key === key)?.input !== "secret") throw new Error(`cannot clear non-secret ${descriptor.label} ${scope} setting: ${key}`);
|
|
43
|
+
const output = {};
|
|
44
|
+
for (const configField of fields) {
|
|
45
|
+
if (clearSecrets.includes(configField.key)) {
|
|
46
|
+
output[configField.key] = "";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const value = input?.[configField.key] ?? previous[configField.key] ?? configField.defaultValue;
|
|
50
|
+
if (configField.input === "boolean") {
|
|
51
|
+
if (value === void 0) continue;
|
|
52
|
+
if (typeof value === "boolean") output[configField.key] = value;
|
|
53
|
+
else if (value === "true" || value === "false") output[configField.key] = value === "true";
|
|
54
|
+
else throw new Error(`${configField.label} must be true or false`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (configField.input === "number") {
|
|
58
|
+
if (value === void 0 || value === "") continue;
|
|
59
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
60
|
+
if (!Number.isFinite(parsed)) throw new Error(`${configField.label} must be a finite number`);
|
|
61
|
+
validateFieldBounds(configField, parsed);
|
|
62
|
+
output[configField.key] = parsed;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const normalized = normalizeString(value, configField);
|
|
66
|
+
if (normalized !== "" || configField.required || configField.input === "secret") output[configField.key] = normalized;
|
|
67
|
+
}
|
|
68
|
+
return output;
|
|
69
|
+
}
|
|
70
|
+
function providerServiceFields(providerId, catalog = []) {
|
|
71
|
+
return memoryProviderDescriptor(providerId, catalog).fields.filter((field) => field.scope === "service");
|
|
72
|
+
}
|
|
73
|
+
function providerMemoryFields(providerId, catalog = []) {
|
|
74
|
+
return memoryProviderDescriptor(providerId, catalog).fields.filter((field) => field.scope === "memory");
|
|
75
|
+
}
|
|
76
|
+
function splitProviderConnection(providerId, connection, catalog = []) {
|
|
77
|
+
const serviceKeys = new Set(providerServiceFields(providerId, catalog).map((field) => field.key));
|
|
78
|
+
return {
|
|
79
|
+
service: Object.fromEntries(Object.entries(connection ?? {}).filter(([key]) => serviceKeys.has(key))),
|
|
80
|
+
memory: Object.fromEntries(Object.entries(connection ?? {}).filter(([key]) => !serviceKeys.has(key)))
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function normalizeProviderServiceConnection(providerId, input, previous = {}, clearSecrets = [], catalog = []) {
|
|
84
|
+
return normalizeScopedProviderConnection(providerId, "service", input, previous, clearSecrets, catalog);
|
|
85
|
+
}
|
|
86
|
+
function normalizeProviderMemoryConnection(providerId, input, previous = {}, catalog = []) {
|
|
87
|
+
return normalizeScopedProviderConnection(providerId, "memory", input, previous, [], catalog);
|
|
88
|
+
}
|
|
89
|
+
function normalizeProviderConnection(providerId, input, previous = {}, clearSecrets = [], catalog = []) {
|
|
90
|
+
const descriptor = memoryProviderDescriptor(providerId, catalog);
|
|
91
|
+
if ((descriptor.typeId ?? descriptor.id) === "mnemon-native") return {};
|
|
92
|
+
const allowed = new Set(descriptor.fields.map((item) => item.key));
|
|
93
|
+
for (const key of Object.keys(input ?? {})) if (!allowed.has(key)) throw new Error(`unsupported ${descriptor.label} setting: ${key}`);
|
|
94
|
+
for (const key of clearSecrets) if (descriptor.fields.find((item) => item.key === key)?.input !== "secret") throw new Error(`cannot clear non-secret ${descriptor.label} setting: ${key}`);
|
|
95
|
+
const output = {};
|
|
96
|
+
for (const configField of descriptor.fields) {
|
|
97
|
+
if (clearSecrets.includes(configField.key)) {
|
|
98
|
+
output[configField.key] = "";
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const supplied = input?.[configField.key];
|
|
102
|
+
const fallback = previous[configField.key] ?? configField.defaultValue;
|
|
103
|
+
const value = supplied ?? fallback;
|
|
104
|
+
if (configField.input === "boolean") {
|
|
105
|
+
if (value === void 0) continue;
|
|
106
|
+
if (typeof value === "boolean") output[configField.key] = value;
|
|
107
|
+
else if (value === "true" || value === "false") output[configField.key] = value === "true";
|
|
108
|
+
else throw new Error(`${configField.label} must be true or false`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (configField.input === "number") {
|
|
112
|
+
if (value === void 0 || value === "") continue;
|
|
113
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
114
|
+
if (!Number.isFinite(parsed)) throw new Error(`${configField.label} must be a finite number`);
|
|
115
|
+
validateFieldBounds(configField, parsed);
|
|
116
|
+
output[configField.key] = parsed;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const normalized = normalizeString(value, configField);
|
|
120
|
+
if (normalized !== "" || configField.required || configField.input === "secret") output[configField.key] = normalized;
|
|
121
|
+
}
|
|
122
|
+
return output;
|
|
123
|
+
}
|
|
124
|
+
function publicScopedProviderConnection(providerId, scope, connection, catalog = []) {
|
|
125
|
+
const fields = memoryProviderDescriptor(providerId, catalog).fields.filter((item) => item.scope === scope);
|
|
126
|
+
const keys = new Set(fields.map((item) => item.key));
|
|
127
|
+
const secrets = new Set(fields.filter((item) => item.input === "secret").map((item) => item.key));
|
|
128
|
+
return {
|
|
129
|
+
settings: Object.fromEntries(Object.entries(connection).filter(([key]) => keys.has(key) && !secrets.has(key))),
|
|
130
|
+
configuredSecrets: [...secrets].filter((key) => String(connection[key] ?? "") !== "")
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function publicProviderConnection(providerId, connection, catalog = []) {
|
|
134
|
+
const descriptor = memoryProviderDescriptor(providerId, catalog);
|
|
135
|
+
const secrets = new Set(descriptor.fields.filter((item) => item.input === "secret").map((item) => item.key));
|
|
136
|
+
return {
|
|
137
|
+
settings: Object.fromEntries(Object.entries(connection).filter(([key]) => !secrets.has(key))),
|
|
138
|
+
configuredSecrets: [...secrets].filter((key) => String(connection[key] ?? "") !== "")
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** Immutable descriptor/config normalizer scoped to one Provider snapshot. */
|
|
142
|
+
var MemoryProviderCatalog = class {
|
|
143
|
+
providers;
|
|
144
|
+
constructor(providers) {
|
|
145
|
+
const ids = /* @__PURE__ */ new Set();
|
|
146
|
+
this.providers = Object.freeze(providers.map((provider) => {
|
|
147
|
+
if (ids.has(provider.id)) throw new Error(`memory provider descriptor is already registered: ${provider.id}`);
|
|
148
|
+
ids.add(provider.id);
|
|
149
|
+
return Object.freeze(structuredClone(provider));
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
has(id) {
|
|
153
|
+
return typeof id === "string" && this.providers.some((provider) => provider.id === id);
|
|
154
|
+
}
|
|
155
|
+
descriptor(id) {
|
|
156
|
+
return memoryProviderDescriptor(id, this.providers);
|
|
157
|
+
}
|
|
158
|
+
serviceFields(id) {
|
|
159
|
+
return providerServiceFields(id, this.providers);
|
|
160
|
+
}
|
|
161
|
+
memoryFields(id) {
|
|
162
|
+
return providerMemoryFields(id, this.providers);
|
|
163
|
+
}
|
|
164
|
+
split(id, connection) {
|
|
165
|
+
return splitProviderConnection(id, connection, this.providers);
|
|
166
|
+
}
|
|
167
|
+
normalizeService(id, input, previous = {}, clearSecrets = []) {
|
|
168
|
+
return normalizeProviderServiceConnection(id, input, previous, clearSecrets, this.providers);
|
|
169
|
+
}
|
|
170
|
+
normalizeMemory(id, input, previous = {}) {
|
|
171
|
+
return normalizeProviderMemoryConnection(id, input, previous, this.providers);
|
|
172
|
+
}
|
|
173
|
+
normalize(id, input, previous = {}, clearSecrets = []) {
|
|
174
|
+
return normalizeProviderConnection(id, input, previous, clearSecrets, this.providers);
|
|
175
|
+
}
|
|
176
|
+
publicScoped(id, scope, connection) {
|
|
177
|
+
return publicScopedProviderConnection(id, scope, connection, this.providers);
|
|
178
|
+
}
|
|
179
|
+
public(id, connection) {
|
|
180
|
+
return publicProviderConnection(id, connection, this.providers);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const EMPTY_MEMORY_PROVIDER_CATALOG = new MemoryProviderCatalog([]);
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/providers/registry.ts
|
|
186
|
+
/** Lifecycle-owned factory directory used by Provider plugins and the Host. */
|
|
187
|
+
var MemoryAdapterFactoryRegistry = class {
|
|
188
|
+
factories = /* @__PURE__ */ new Map();
|
|
189
|
+
constructor(factories = []) {
|
|
190
|
+
for (const factory of factories) this.register(factory);
|
|
191
|
+
}
|
|
192
|
+
register(factory) {
|
|
193
|
+
if (this.factories.has(factory.id)) throw new Error(`memory adapter factory is already registered: ${factory.id}`);
|
|
194
|
+
this.factories.set(factory.id, factory);
|
|
195
|
+
let active = true;
|
|
196
|
+
return () => {
|
|
197
|
+
if (!active) return;
|
|
198
|
+
active = false;
|
|
199
|
+
if (this.factories.get(factory.id) === factory) this.factories.delete(factory.id);
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
create(context) {
|
|
203
|
+
const adapters = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const factory of this.factories.values()) {
|
|
205
|
+
const adapter = factory.create(context);
|
|
206
|
+
if (adapter.id !== factory.id) throw new Error(`memory adapter factory ${factory.id} returned ${adapter.id}`);
|
|
207
|
+
if (adapters.has(adapter.id)) throw new Error(`memory adapter is already created: ${adapter.id}`);
|
|
208
|
+
adapters.set(adapter.id, adapter);
|
|
209
|
+
}
|
|
210
|
+
return adapters;
|
|
211
|
+
}
|
|
212
|
+
ids() {
|
|
213
|
+
return [...this.factories.keys()];
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
var MemoryProviderAdapterRegistry = class extends MemoryAdapterFactoryRegistry {};
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/providers/host.ts
|
|
219
|
+
const SOURCE_INSTANCE_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
220
|
+
function requiredSourceInstanceId(value) {
|
|
221
|
+
const normalized = value.trim();
|
|
222
|
+
if (!SOURCE_INSTANCE_ID.test(normalized)) throw new Error("Memory Spaces Source instanceId must start with a letter or digit and contain only letters, digits, ., _, :, / or -");
|
|
223
|
+
return normalized;
|
|
224
|
+
}
|
|
225
|
+
/** Presentation labels/icons do not change the semantic Generation digest. */
|
|
226
|
+
function semanticManifest(manifest) {
|
|
227
|
+
return {
|
|
228
|
+
apiVersion: manifest.apiVersion,
|
|
229
|
+
kind: manifest.kind,
|
|
230
|
+
typeId: manifest.typeId,
|
|
231
|
+
packageName: manifest.packageName,
|
|
232
|
+
version: manifest.version,
|
|
233
|
+
origin: manifest.origin,
|
|
234
|
+
locality: manifest.locality,
|
|
235
|
+
workspaceBinding: manifest.workspaceBinding,
|
|
236
|
+
capabilities: manifest.capabilities,
|
|
237
|
+
fields: manifest.fields.map((field) => ({
|
|
238
|
+
key: field.key,
|
|
239
|
+
scope: field.scope,
|
|
240
|
+
role: field.role,
|
|
241
|
+
input: field.input,
|
|
242
|
+
required: field.required,
|
|
243
|
+
defaultValue: field.defaultValue,
|
|
244
|
+
min: field.min,
|
|
245
|
+
max: field.max,
|
|
246
|
+
maxLength: field.maxLength,
|
|
247
|
+
pattern: field.pattern,
|
|
248
|
+
normalize: field.normalize,
|
|
249
|
+
discoveryDefaultFrom: field.discoveryDefaultFrom,
|
|
250
|
+
options: field.options?.map((option) => option.value)
|
|
251
|
+
})),
|
|
252
|
+
secrets: manifest.secrets,
|
|
253
|
+
scoreSemantics: manifest.scoreSemantics
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function assertRuntime(definition, adapter) {
|
|
257
|
+
const { manifest } = definition;
|
|
258
|
+
if (adapter.id !== manifest.typeId) throw new Error(`Memory Space Provider ${manifest.typeId} factory returned ${String(adapter.id)}`);
|
|
259
|
+
const requiredMethods = [
|
|
260
|
+
[manifest.capabilities.search, "search"],
|
|
261
|
+
[manifest.capabilities.browse, "list"],
|
|
262
|
+
[manifest.capabilities.graph, "graph"],
|
|
263
|
+
[manifest.capabilities.related, "related"],
|
|
264
|
+
[manifest.capabilities.remember, "remember"],
|
|
265
|
+
[manifest.capabilities.link, "link"],
|
|
266
|
+
[manifest.capabilities.forget, "forget"]
|
|
267
|
+
];
|
|
268
|
+
for (const [required, method] of requiredMethods) if (required && typeof adapter[method] !== "function") throw new Error(`Memory Space Provider ${manifest.typeId} declares ${String(method)} but its runtime does not implement it`);
|
|
269
|
+
if (manifest.scoreSemantics === "normalized-relevance" && adapter.scoreSemantics?.kind !== "normalized-relevance") throw new Error(`Memory Space Provider ${manifest.typeId} declares normalized scores but its runtime does not`);
|
|
270
|
+
}
|
|
271
|
+
/** Expose the configured child identity while preserving the driver methods. */
|
|
272
|
+
function instanceAdapter(adapter, instanceId) {
|
|
273
|
+
return new Proxy(adapter, { get(target, property) {
|
|
274
|
+
if (property === "id") return instanceId;
|
|
275
|
+
const value = Reflect.get(target, property, target);
|
|
276
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
277
|
+
} });
|
|
278
|
+
}
|
|
279
|
+
var MemorySpaceProviderSnapshot = class {
|
|
280
|
+
digest;
|
|
281
|
+
entries;
|
|
282
|
+
constructor(entries) {
|
|
283
|
+
const sorted = [...entries].sort((left, right) => left.childKey.localeCompare(right.childKey));
|
|
284
|
+
this.entries = Object.freeze(sorted.map((entry) => Object.freeze({ ...entry })));
|
|
285
|
+
this.digest = digest(sorted.map((entry) => ({
|
|
286
|
+
childKey: entry.childKey,
|
|
287
|
+
instanceId: entry.instanceId,
|
|
288
|
+
configDigest: entry.configDigest,
|
|
289
|
+
manifest: semanticManifest(entry.definition.manifest)
|
|
290
|
+
})), "Memory Space Provider snapshot");
|
|
291
|
+
Object.freeze(this);
|
|
292
|
+
}
|
|
293
|
+
descriptors() {
|
|
294
|
+
return this.entries.map(({ instanceId, definition }) => ({
|
|
295
|
+
id: instanceId,
|
|
296
|
+
...instanceId === definition.manifest.typeId ? {} : { typeId: definition.manifest.typeId },
|
|
297
|
+
label: definition.manifest.label,
|
|
298
|
+
...definition.manifest.icon === void 0 ? {} : { icon: structuredClone(definition.manifest.icon) },
|
|
299
|
+
kind: definition.manifest.locality,
|
|
300
|
+
workspaceBinding: definition.manifest.workspaceBinding,
|
|
301
|
+
summary: definition.manifest.summary,
|
|
302
|
+
...definition.manifest.summaryI18nKey === void 0 ? {} : { summaryI18nKey: definition.manifest.summaryI18nKey },
|
|
303
|
+
origin: definition.manifest.origin,
|
|
304
|
+
capabilities: structuredClone(definition.manifest.capabilities),
|
|
305
|
+
fields: structuredClone(definition.manifest.fields)
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
adapterRegistry() {
|
|
309
|
+
return new MemoryProviderAdapterRegistry(this.entries.map(({ instanceId, definition }) => ({
|
|
310
|
+
id: instanceId,
|
|
311
|
+
create: (context) => {
|
|
312
|
+
const adapter = definition.create({
|
|
313
|
+
...context,
|
|
314
|
+
providerInstanceId: instanceId,
|
|
315
|
+
manifest: definition.manifest
|
|
316
|
+
});
|
|
317
|
+
assertRuntime(definition, adapter);
|
|
318
|
+
return instanceAdapter(adapter, instanceId);
|
|
319
|
+
}
|
|
320
|
+
})));
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* Source-private definition host. It is a plain closure-owned object, never a
|
|
325
|
+
* Cordis Context service and never a Mnemon contribution registry.
|
|
326
|
+
*/
|
|
327
|
+
var PrivateMemorySpaceProviderHost = class {
|
|
328
|
+
sourceInstanceId;
|
|
329
|
+
registrations = /* @__PURE__ */ new Map();
|
|
330
|
+
constructor(sourceInstanceId) {
|
|
331
|
+
this.sourceInstanceId = sourceInstanceId;
|
|
332
|
+
this.sourceInstanceId = requiredSourceInstanceId(sourceInstanceId);
|
|
333
|
+
}
|
|
334
|
+
bind(instanceIdValue, moduleTypeIdValue, config) {
|
|
335
|
+
const instanceId = requiredId(instanceIdValue, "Memory Space Provider instanceId");
|
|
336
|
+
const moduleTypeId = requiredId(moduleTypeIdValue, "Memory Space Provider module id");
|
|
337
|
+
const childKey = `${this.sourceInstanceId}/provider:${instanceId}`;
|
|
338
|
+
const configDigest = digest(config ?? null, `Memory Space Provider ${instanceId} config`);
|
|
339
|
+
let installed = false;
|
|
340
|
+
return Object.freeze({ install: (owner, definitionValue) => {
|
|
341
|
+
if (installed) throw new Error(`Memory Space Provider child already installed a definition: ${childKey}`);
|
|
342
|
+
const definition = defineMemorySpaceProviderDefinition(definitionValue);
|
|
343
|
+
if (definition.manifest.typeId !== moduleTypeId) throw new Error(`Memory Space Provider module ${moduleTypeId} installed definition ${definition.manifest.typeId}`);
|
|
344
|
+
installed = true;
|
|
345
|
+
return owner.effect(() => {
|
|
346
|
+
if (this.registrations.has(childKey)) throw new Error(`Memory Space Provider child is already installed: ${childKey}`);
|
|
347
|
+
const registration = Object.freeze({
|
|
348
|
+
childKey,
|
|
349
|
+
instanceId,
|
|
350
|
+
configDigest,
|
|
351
|
+
definition
|
|
352
|
+
});
|
|
353
|
+
this.registrations.set(childKey, registration);
|
|
354
|
+
let active = true;
|
|
355
|
+
return () => {
|
|
356
|
+
if (!active) return;
|
|
357
|
+
active = false;
|
|
358
|
+
if (this.registrations.get(childKey) === registration) this.registrations.delete(childKey);
|
|
359
|
+
};
|
|
360
|
+
}, `dsh-mnemon: install private Provider ${childKey}`);
|
|
361
|
+
} });
|
|
362
|
+
}
|
|
363
|
+
has(instanceId) {
|
|
364
|
+
return this.registrations.has(`${this.sourceInstanceId}/provider:${instanceId}`);
|
|
365
|
+
}
|
|
366
|
+
snapshot() {
|
|
367
|
+
return new MemorySpaceProviderSnapshot([...this.registrations.values()]);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/providers/plugin.ts
|
|
372
|
+
/**
|
|
373
|
+
* Build an ordinary child plugin whose only capability is a closure-held
|
|
374
|
+
* registration into its Memory Spaces parent. No ctx.mnemonProvider service
|
|
375
|
+
* exists, and core cannot resolve this host.
|
|
376
|
+
*/
|
|
377
|
+
function createMemorySpaceProviderPlugin(entry, host) {
|
|
378
|
+
const plugin = {
|
|
379
|
+
name: `dsh-mnemon-provider-${entry.module.id}`,
|
|
380
|
+
apply(ctx, config = entry.config) {
|
|
381
|
+
return entry.module.apply(ctx, host.bind(entry.instanceId, entry.module.id, config), config);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
if (entry.module.Config !== void 0) plugin.Config = entry.module.Config;
|
|
385
|
+
return plugin;
|
|
386
|
+
}
|
|
387
|
+
//#endregion
|
|
388
|
+
export { MemoryProviderCatalog as a, EMPTY_MEMORY_PROVIDER_CATALOG as i, PrivateMemorySpaceProviderHost as n, MemoryProviderAdapterRegistry as r, createMemorySpaceProviderPlugin as t };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
//#region src/providers/adapter.ts
|
|
3
|
+
const NORMALIZED_RELEVANCE_SCORE = Object.freeze({ kind: "normalized-relevance" });
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/providers/process.ts
|
|
6
|
+
const DEFAULT_MAX_OUTPUT_BYTES = 2097152;
|
|
7
|
+
/** Spawn without a shell, with bounded output and cooperative cancellation. */
|
|
8
|
+
const runProcess = (command, args, options) => new Promise((resolve, reject) => {
|
|
9
|
+
const label = options.label ?? "mnemon";
|
|
10
|
+
const child = spawn(command, [...args], {
|
|
11
|
+
stdio: [
|
|
12
|
+
"ignore",
|
|
13
|
+
"pipe",
|
|
14
|
+
"pipe"
|
|
15
|
+
],
|
|
16
|
+
shell: false,
|
|
17
|
+
windowsHide: true,
|
|
18
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
19
|
+
...options.env === void 0 ? {} : { env: options.env }
|
|
20
|
+
});
|
|
21
|
+
const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
22
|
+
let stdout = "";
|
|
23
|
+
let stderr = "";
|
|
24
|
+
let outputBytes = 0;
|
|
25
|
+
let settled = false;
|
|
26
|
+
let killTimer;
|
|
27
|
+
const stop = () => {
|
|
28
|
+
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
29
|
+
child.kill("SIGTERM");
|
|
30
|
+
killTimer = setTimeout(() => {
|
|
31
|
+
if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
|
|
32
|
+
}, 1500);
|
|
33
|
+
};
|
|
34
|
+
const finish = (error, result) => {
|
|
35
|
+
if (settled) return;
|
|
36
|
+
settled = true;
|
|
37
|
+
clearTimeout(timeout);
|
|
38
|
+
if (killTimer !== void 0) clearTimeout(killTimer);
|
|
39
|
+
options.signal?.removeEventListener("abort", abort);
|
|
40
|
+
if (error === null) resolve(result);
|
|
41
|
+
else reject(error);
|
|
42
|
+
};
|
|
43
|
+
const abort = () => {
|
|
44
|
+
stop();
|
|
45
|
+
finish(/* @__PURE__ */ new Error(`${label} command aborted: ${String(options.signal?.reason ?? "cancelled")}`));
|
|
46
|
+
};
|
|
47
|
+
const append = (target, chunk) => {
|
|
48
|
+
outputBytes += chunk.byteLength;
|
|
49
|
+
if (outputBytes > maxOutputBytes) {
|
|
50
|
+
stop();
|
|
51
|
+
finish(/* @__PURE__ */ new Error(`${label} output exceeded ${maxOutputBytes} bytes`));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (target === "stdout") stdout += chunk.toString("utf8");
|
|
55
|
+
else stderr += chunk.toString("utf8");
|
|
56
|
+
};
|
|
57
|
+
child.stdout.on("data", (chunk) => {
|
|
58
|
+
append("stdout", chunk);
|
|
59
|
+
});
|
|
60
|
+
child.stderr.on("data", (chunk) => {
|
|
61
|
+
append("stderr", chunk);
|
|
62
|
+
});
|
|
63
|
+
child.on("error", (error) => {
|
|
64
|
+
finish(/* @__PURE__ */ new Error(`failed to launch ${label} (${JSON.stringify(command)}): ${error.message}`));
|
|
65
|
+
});
|
|
66
|
+
child.on("close", (exitCode) => {
|
|
67
|
+
finish(null, {
|
|
68
|
+
stdout,
|
|
69
|
+
stderr,
|
|
70
|
+
exitCode
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
const timeout = setTimeout(() => {
|
|
74
|
+
stop();
|
|
75
|
+
finish(/* @__PURE__ */ new Error(`${label} did not respond within ${options.timeoutMs}ms`));
|
|
76
|
+
}, options.timeoutMs);
|
|
77
|
+
if (options.signal?.aborted === true) abort();
|
|
78
|
+
else options.signal?.addEventListener("abort", abort, { once: true });
|
|
79
|
+
});
|
|
80
|
+
//#endregion
|
|
81
|
+
export { NORMALIZED_RELEVANCE_SCORE as n, runProcess as t };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { CATEGORIES, Category, EDGE_TYPES, EdgeType, INTENTS, Insight, Intent, JsonValue, MemoryBody, MemoryBodyProvider, MemoryBodyStats, MemoryGraphEdge, MemoryGraphNode, MemoryGraphSnapshot, MemoryListRequest, MemoryProviderCapabilities, MemoryProviderConfigField, MemoryProviderConfigOption, MemoryProviderConnection, MemoryProviderConnectionValue, MemoryProviderDescriptor, MemoryProviderIcon, MemoryProviderId, OpenVikingBodyConnection, RememberRequest, SOURCES, SearchRequest, Source } from "./contracts.js";
|
|
2
|
+
import { _ as NORMALIZED_RELEVANCE_SCORE, a as MemorySpaceProviderHost, b as ProviderScoreSemantics, c as MemorySpaceProviderRuntimeContext, d as defineMemorySpaceProviderDefinition, f as MemoryProviderAdapter, g as MemorySpaceNativeRunner, h as MemorySpaceAuthority, i as MemorySpaceProviderEntry, l as MemorySpaceProviderScoreSemantics, m as MemoryProviderScoreSemantics, n as MemorySpaceProviderDefinition, o as MemorySpaceProviderManifest, p as MemoryProviderAdapterFactoryContext, r as MemorySpaceProviderDisposer, s as MemorySpaceProviderModule, t as MEMORY_SPACE_PROVIDER_API_VERSION, u as defineMemorySpaceProvider, v as ProviderBodyStatus, x as ProviderSearchResult, y as ProviderMemorySpace } from "./definitions-CEpa-tvm.js";
|
|
3
|
+
//#region src/providers/http.d.ts
|
|
4
|
+
interface HttpProviderOptions {
|
|
5
|
+
label?: string;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
requestTimeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
interface JsonRequestOptions {
|
|
10
|
+
method?: string;
|
|
11
|
+
headers?: HeadersInit;
|
|
12
|
+
json?: JsonValue;
|
|
13
|
+
signal?: AbortSignal | undefined;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
declare function jsonObject(value: unknown): Record<string, unknown> | undefined;
|
|
17
|
+
declare function jsonString(value: unknown): string | undefined;
|
|
18
|
+
declare function jsonNumber(value: unknown): number | undefined;
|
|
19
|
+
declare function jsonArray(value: unknown): unknown[];
|
|
20
|
+
declare function firstArray(value: unknown, ...keys: string[]): unknown[];
|
|
21
|
+
/** Shared timeout, cancellation, error, and projection behavior for HTTP providers. */
|
|
22
|
+
declare abstract class HttpMemoryProvider {
|
|
23
|
+
protected readonly memoryBodies: MemorySpaceAuthority;
|
|
24
|
+
abstract readonly id: MemoryProviderId;
|
|
25
|
+
protected readonly label: string | undefined;
|
|
26
|
+
protected readonly requestFetch: typeof fetch;
|
|
27
|
+
protected readonly requestTimeoutMs: number;
|
|
28
|
+
constructor(memoryBodies: MemorySpaceAuthority, options?: HttpProviderOptions);
|
|
29
|
+
abstract list(body: MemoryBody, request: MemoryListRequest, signal?: AbortSignal): Promise<Insight[]>;
|
|
30
|
+
graph(body: MemoryBody, signal?: AbortSignal): Promise<MemoryGraphSnapshot>;
|
|
31
|
+
protected connection(body: MemoryBody): MemoryProviderConnection;
|
|
32
|
+
protected request(body: MemoryBody, path: string, options?: JsonRequestOptions): Promise<unknown>;
|
|
33
|
+
protected requestConnection(connection: MemoryProviderConnection, path: string, options?: JsonRequestOptions): Promise<unknown>;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/providers/process.d.ts
|
|
37
|
+
interface ProcessResult {
|
|
38
|
+
stdout: string;
|
|
39
|
+
stderr: string;
|
|
40
|
+
exitCode: number | null;
|
|
41
|
+
}
|
|
42
|
+
interface ProcessOptions {
|
|
43
|
+
signal?: AbortSignal | undefined;
|
|
44
|
+
timeoutMs: number;
|
|
45
|
+
maxOutputBytes?: number;
|
|
46
|
+
cwd?: string | undefined;
|
|
47
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
48
|
+
label?: string | undefined;
|
|
49
|
+
}
|
|
50
|
+
type ProcessRunner = (command: string, args: readonly string[], options: ProcessOptions) => Promise<ProcessResult>;
|
|
51
|
+
/** Spawn without a shell, with bounded output and cooperative cancellation. */
|
|
52
|
+
declare const runProcess: ProcessRunner;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { CATEGORIES, type Category, EDGE_TYPES, type EdgeType, HttpMemoryProvider, HttpProviderOptions, INTENTS, type Insight, type Intent, JsonRequestOptions, type JsonValue, MEMORY_SPACE_PROVIDER_API_VERSION, type MemoryBody, type MemoryBodyProvider, type MemoryBodyStats, type MemoryGraphEdge, type MemoryGraphNode, type MemoryGraphSnapshot, type MemoryListRequest, MemoryProviderAdapter, MemoryProviderAdapterFactoryContext, type MemoryProviderCapabilities, type MemoryProviderConfigField, type MemoryProviderConfigOption, type MemoryProviderConnection, type MemoryProviderConnectionValue, type MemoryProviderDescriptor, type MemoryProviderIcon, type MemoryProviderId, MemoryProviderScoreSemantics, MemorySpaceAuthority, MemorySpaceNativeRunner, type MemorySpaceProviderDefinition, type MemorySpaceProviderDisposer, type MemorySpaceProviderEntry, type MemorySpaceProviderHost, type MemorySpaceProviderManifest, type MemorySpaceProviderModule, type MemorySpaceProviderRuntimeContext, type MemorySpaceProviderScoreSemantics, NORMALIZED_RELEVANCE_SCORE, type OpenVikingBodyConnection, ProcessOptions, ProcessResult, ProcessRunner, ProviderBodyStatus, ProviderMemorySpace, ProviderScoreSemantics, ProviderSearchResult, type RememberRequest, SOURCES, type SearchRequest, type Source, defineMemorySpaceProvider, defineMemorySpaceProviderDefinition, firstArray, jsonArray, jsonNumber, jsonObject, jsonString, runProcess };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { CATEGORIES, EDGE_TYPES, INTENTS, SOURCES } from "./contracts.js";
|
|
2
|
+
import { n as NORMALIZED_RELEVANCE_SCORE, t as runProcess } from "./process-B-t3UflO.js";
|
|
3
|
+
import { i as defineMemorySpaceProviderDefinition, r as defineMemorySpaceProvider, t as MEMORY_SPACE_PROVIDER_API_VERSION } from "./definitions-DfmOqJjR.js";
|
|
4
|
+
//#region src/providers/http.ts
|
|
5
|
+
function jsonObject(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
7
|
+
}
|
|
8
|
+
function jsonString(value) {
|
|
9
|
+
return typeof value === "string" ? value : void 0;
|
|
10
|
+
}
|
|
11
|
+
function jsonNumber(value) {
|
|
12
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
13
|
+
}
|
|
14
|
+
function jsonArray(value) {
|
|
15
|
+
return Array.isArray(value) ? value : [];
|
|
16
|
+
}
|
|
17
|
+
function firstArray(value, ...keys) {
|
|
18
|
+
if (Array.isArray(value)) return value;
|
|
19
|
+
const root = jsonObject(value);
|
|
20
|
+
for (const key of keys) if (Array.isArray(root?.[key])) return root[key];
|
|
21
|
+
const nested = jsonObject(root?.data);
|
|
22
|
+
for (const key of keys) if (Array.isArray(nested?.[key])) return nested[key];
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
function errorDetail(payload) {
|
|
26
|
+
if (typeof payload === "string") return payload.trim() || void 0;
|
|
27
|
+
const root = jsonObject(payload);
|
|
28
|
+
const direct = jsonString(root?.message) ?? jsonString(root?.error) ?? jsonString(root?.detail);
|
|
29
|
+
if (direct !== void 0) return direct;
|
|
30
|
+
const error = jsonObject(root?.error);
|
|
31
|
+
return jsonString(error?.message) ?? jsonString(error?.detail);
|
|
32
|
+
}
|
|
33
|
+
/** Shared timeout, cancellation, error, and projection behavior for HTTP providers. */
|
|
34
|
+
var HttpMemoryProvider = class {
|
|
35
|
+
memoryBodies;
|
|
36
|
+
label;
|
|
37
|
+
requestFetch;
|
|
38
|
+
requestTimeoutMs;
|
|
39
|
+
constructor(memoryBodies, options = {}) {
|
|
40
|
+
this.memoryBodies = memoryBodies;
|
|
41
|
+
this.label = options.label;
|
|
42
|
+
this.requestFetch = options.fetch ?? globalThis.fetch;
|
|
43
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
|
|
44
|
+
}
|
|
45
|
+
async graph(body, signal) {
|
|
46
|
+
return {
|
|
47
|
+
nodes: (await this.list(body, { limit: 200 }, signal)).map((item) => ({
|
|
48
|
+
...item,
|
|
49
|
+
color: "#6574d9"
|
|
50
|
+
})),
|
|
51
|
+
edges: [],
|
|
52
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
connection(body) {
|
|
56
|
+
if ((body.provider.typeId ?? body.provider.id) !== this.id) throw new Error(`${this.id} cannot serve provider ${body.provider.id}`);
|
|
57
|
+
return this.memoryBodies.providerConnection(body.id, body.provider.id);
|
|
58
|
+
}
|
|
59
|
+
async request(body, path, options = {}) {
|
|
60
|
+
const connection = this.connection(body);
|
|
61
|
+
return this.requestConnection(connection, path, options);
|
|
62
|
+
}
|
|
63
|
+
async requestConnection(connection, path, options = {}) {
|
|
64
|
+
const endpoint = String(connection.endpoint ?? "").replace(/\/+$/u, "");
|
|
65
|
+
const label = this.label ?? this.id;
|
|
66
|
+
if (endpoint === "") throw new Error(`${label} endpoint is not configured`);
|
|
67
|
+
if (!path.startsWith("/")) throw new Error(`${label} request path must be absolute`);
|
|
68
|
+
options.signal?.throwIfAborted();
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
const relay = () => controller.abort(options.signal?.reason);
|
|
71
|
+
options.signal?.addEventListener("abort", relay, { once: true });
|
|
72
|
+
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
73
|
+
const timer = setTimeout(() => controller.abort(/* @__PURE__ */ new Error(`${label} request timed out`)), timeoutMs);
|
|
74
|
+
const headers = new Headers(options.headers);
|
|
75
|
+
if (options.json !== void 0 && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
|
76
|
+
try {
|
|
77
|
+
const response = await this.requestFetch(`${endpoint}${path}`, {
|
|
78
|
+
method: options.method ?? (options.json === void 0 ? "GET" : "POST"),
|
|
79
|
+
headers,
|
|
80
|
+
...options.json === void 0 ? {} : { body: JSON.stringify(options.json) },
|
|
81
|
+
signal: controller.signal
|
|
82
|
+
});
|
|
83
|
+
const raw = await response.text();
|
|
84
|
+
let payload = {};
|
|
85
|
+
if (raw !== "") try {
|
|
86
|
+
payload = JSON.parse(raw);
|
|
87
|
+
} catch {
|
|
88
|
+
payload = raw;
|
|
89
|
+
}
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
const detail = errorDetail(payload);
|
|
92
|
+
throw new Error(`${label} HTTP ${response.status}${detail === void 0 ? "" : `: ${detail}`}`);
|
|
93
|
+
}
|
|
94
|
+
return payload;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (controller.signal.aborted && options.signal?.aborted !== true) throw new Error(`${label} request timed out after ${timeoutMs}ms`);
|
|
97
|
+
throw error;
|
|
98
|
+
} finally {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
options.signal?.removeEventListener("abort", relay);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
export { CATEGORIES, EDGE_TYPES, HttpMemoryProvider, INTENTS, MEMORY_SPACE_PROVIDER_API_VERSION, NORMALIZED_RELEVANCE_SCORE, SOURCES, defineMemorySpaceProvider, defineMemorySpaceProviderDefinition, firstArray, jsonArray, jsonNumber, jsonObject, jsonString, runProcess };
|
package/lib/testing.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MemoryBody, MemoryProviderConnection, MemoryProviderDescriptor } from "./contracts.js";
|
|
2
|
+
import { f as MemoryProviderAdapter, h as MemorySpaceAuthority, o as MemorySpaceProviderManifest, p as MemoryProviderAdapterFactoryContext, s as MemorySpaceProviderModule } from "./definitions-CEpa-tvm.js";
|
|
3
|
+
//#region src/testing.d.ts
|
|
4
|
+
interface MemorySpaceProviderTest {
|
|
5
|
+
readonly registered: boolean;
|
|
6
|
+
readonly descriptor: MemoryProviderDescriptor;
|
|
7
|
+
readonly manifest: MemorySpaceProviderManifest;
|
|
8
|
+
createAdapter(context: MemoryProviderAdapterFactoryContext): MemoryProviderAdapter;
|
|
9
|
+
dispose(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/** Real private-child registration and factory validation, without exposing its Host/Registry. */
|
|
12
|
+
declare function mountMemorySpaceProvider<C>(module: MemorySpaceProviderModule<C>, options: {
|
|
13
|
+
instanceId?: string;
|
|
14
|
+
sourceInstanceId?: string;
|
|
15
|
+
config: C;
|
|
16
|
+
}): Promise<MemorySpaceProviderTest>;
|
|
17
|
+
/** Driver fixture only: real descriptor validation, no Core or service singleton. */
|
|
18
|
+
declare function createMemorySpaceProviderFixture(descriptor: MemoryProviderDescriptor, input: MemoryProviderConnection | undefined, options: {
|
|
19
|
+
dataDir: string;
|
|
20
|
+
instanceId?: string;
|
|
21
|
+
memoryBodyId?: string;
|
|
22
|
+
}): {
|
|
23
|
+
body: MemoryBody;
|
|
24
|
+
authority: MemorySpaceAuthority;
|
|
25
|
+
connection: MemoryProviderConnection;
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { MemorySpaceProviderTest, createMemorySpaceProviderFixture, mountMemorySpaceProvider };
|