@aiwg/cli 2026.8.19 → 2026.8.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/THIRD_PARTY_NOTICES.md +12 -0
  2. package/dist/src/api/index.d.ts +2 -0
  3. package/dist/src/api/index.js +2 -0
  4. package/dist/src/artifacts/backend-runtime.js +26 -0
  5. package/dist/src/artifacts/backends/sqlite-backend.js +204 -28
  6. package/dist/src/artifacts/dep-graph.js +27 -5
  7. package/dist/src/artifacts/graph-backend.js +2 -2
  8. package/dist/src/artifacts/graph-query.js +21 -9
  9. package/dist/src/artifacts/index-builder.js +15 -0
  10. package/dist/src/artifacts/index-status.js +4 -1
  11. package/dist/src/artifacts/stats.js +4 -1
  12. package/dist/src/artifacts/types.js +13 -1
  13. package/dist/src/cli/handlers/artifact-verify.js +3 -0
  14. package/dist/src/cli/handlers/help.js +2 -0
  15. package/dist/src/cli/handlers/index.js +6 -2
  16. package/dist/src/cli/handlers/mission.js +27 -0
  17. package/dist/src/cli/handlers/refresh.js +37 -2
  18. package/dist/src/cli/handlers/runtime-info.js +29 -0
  19. package/dist/src/cli/handlers/steward.js +12 -0
  20. package/dist/src/cli/handlers/subcommands.js +26 -20
  21. package/dist/src/cli/handlers/uhp.js +88 -0
  22. package/dist/src/cli/handlers/utilities.js +3 -0
  23. package/dist/src/cli/router.js +27 -0
  24. package/dist/src/config/aiwg-config.js +10 -0
  25. package/dist/src/extensions/commands/definitions.js +38 -0
  26. package/dist/src/installation/manager-command.mjs +10 -1
  27. package/dist/src/mission-protocol/codecs.js +265 -0
  28. package/dist/src/mission-protocol/index.js +3 -0
  29. package/dist/src/mission-protocol/types.js +2 -0
  30. package/dist/src/storage/backend-contract.js +64 -0
  31. package/dist/src/storage/index.js +2 -0
  32. package/dist/src/storage/migration-protocol.js +378 -0
  33. package/dist/src/uhp/client.js +374 -0
  34. package/dist/src/uhp/config.js +130 -0
  35. package/dist/src/uhp/errors.js +63 -0
  36. package/dist/src/uhp/index.js +7 -0
  37. package/dist/src/uhp/mission.js +111 -0
  38. package/dist/src/uhp/sse.js +76 -0
  39. package/dist/src/uhp/types.js +2 -0
  40. package/dist/src/update/service.mjs +2 -5
  41. package/package.json +1 -1
@@ -0,0 +1,265 @@
1
+ import { MISSION_API_VERSION, } from './types.js';
2
+ const TERMINAL = new Set(['completed', 'failed', 'incomplete', 'cancelled']);
3
+ function object(value, label = 'Mission input') {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value))
5
+ throw new Error(`${label} must be an object.`);
6
+ return value;
7
+ }
8
+ function string(value) {
9
+ return typeof value === 'string' && value.length ? value : undefined;
10
+ }
11
+ function requiredId(record) {
12
+ const metadata = record.metadata && typeof record.metadata === 'object' ? record.metadata : {};
13
+ const id = string(record.missionId) ?? string(record.mission_id) ?? string(record.id)
14
+ ?? string(record.taskId) ?? string(record.task_id) ?? string(record.responseId) ?? string(metadata.id);
15
+ if (!id)
16
+ throw new Error('Mission source is missing a stable identifier.');
17
+ return id;
18
+ }
19
+ export function normalizeMissionState(nativeState) {
20
+ const state = String(nativeState ?? 'unknown').toLowerCase().replace(/_/g, '-');
21
+ if (['done', 'completed', 'succeeded', 'success'].includes(state))
22
+ return 'completed';
23
+ if (['aborted', 'cancelled', 'canceled'].includes(state))
24
+ return 'cancelled';
25
+ if (['failed', 'error', 'rejected', 'timed-out'].includes(state))
26
+ return 'failed';
27
+ if (['incomplete', 'budget-exhausted', 'max-iterations', 'max-tokens'].includes(state))
28
+ return 'incomplete';
29
+ if (['running', 'in-progress', 'working', 'started', 'assigned', 'admitted', 'starting'].includes(state))
30
+ return 'running';
31
+ if (['pending', 'submitted', 'queued', 'runnable', 'scheduled'].includes(state))
32
+ return 'pending';
33
+ if (['blocked', 'blocked-hitl', 'input-required', 'auth-required', 'paused', 'suspended'].includes(state))
34
+ return 'blocked';
35
+ if (['operator-review', 'operator-review-required', 'manual-review'].includes(state))
36
+ return 'operator-review';
37
+ if (['unknown', 'disconnected', 'detached', 'unreachable'].includes(state))
38
+ return 'unknown';
39
+ return 'unknown';
40
+ }
41
+ function knownKeysFor(source) {
42
+ const common = ['id', 'missionId', 'mission_id', 'taskId', 'task_id', 'responseId', 'title', 'goal', 'objective', 'prompt', 'completion', 'completionCriterion', 'completion_criterion', 'status', 'state', 'nativeState', 'createdAt', 'created_at', 'updatedAt', 'updated_at', 'metadata', 'spec', 'provenance', 'extensions', 'artifacts', 'output', 'partialOutput', 'error', 'checkpoint', 'cycles', 'activityLog', 'totalCost', 'runtimesUsed', 'apiVersion', 'api_version', 'schemaVersion', 'schema_version', 'kind', 'session_id', 'previous_response_id'];
43
+ if (source === 'uhp-2026-08-11')
44
+ common.push('object', 'model', 'incomplete_details', 'store', 'usage');
45
+ return new Set(common);
46
+ }
47
+ function extensions(record, source) {
48
+ const explicit = record.extensions && typeof record.extensions === 'object' ? structuredClone(record.extensions) : {};
49
+ if (record.metadata && typeof record.metadata === 'object')
50
+ explicit.metadata = structuredClone(record.metadata);
51
+ if (record.status && typeof record.status === 'object')
52
+ explicit.nativeStatus = structuredClone(record.status);
53
+ for (const [key, value] of Object.entries(record))
54
+ if (!knownKeysFor(source).has(key))
55
+ explicit[key] = structuredClone(value);
56
+ return explicit;
57
+ }
58
+ function artifacts(record) {
59
+ const values = Array.isArray(record.artifacts) ? record.artifacts : [];
60
+ return values.flatMap((item, index) => {
61
+ if (!item || typeof item !== 'object')
62
+ return [];
63
+ const artifact = item;
64
+ const id = string(artifact.id) ?? string(artifact.fileId) ?? string(artifact.file_id) ?? string(artifact.uri) ?? `artifact-${index}`;
65
+ return [{
66
+ id,
67
+ kind: string(artifact.kind) ?? 'other',
68
+ ...(string(artifact.uri) ? { uri: string(artifact.uri) } : {}),
69
+ ...(string(artifact.sha256) ? { sha256: string(artifact.sha256) } : {}),
70
+ ...(string(artifact.mediaType) ?? string(artifact.media_type) ? { mediaType: string(artifact.mediaType) ?? string(artifact.media_type) } : {}),
71
+ extensions: structuredClone(artifact),
72
+ }];
73
+ });
74
+ }
75
+ function uhpOutputArtifacts(record) {
76
+ const found = new Map();
77
+ function visit(value) {
78
+ if (Array.isArray(value)) {
79
+ value.forEach(visit);
80
+ return;
81
+ }
82
+ if (!value || typeof value !== 'object')
83
+ return;
84
+ const item = value;
85
+ const id = string(item.file_id);
86
+ if (id)
87
+ found.set(id, { id, kind: 'uhp-file', ...(string(item.media_type) ? { mediaType: string(item.media_type) } : {}), extensions: { 'uhp.file': structuredClone(item) } });
88
+ Object.values(item).forEach(visit);
89
+ }
90
+ visit(record.output);
91
+ return [...found.values()];
92
+ }
93
+ function nativeStateFor(source, record, statusRecord) {
94
+ const explicit = string(statusRecord.state) ?? string(record.nativeState) ?? string(record.status)
95
+ ?? string(record.state) ?? string(record.observed_state) ?? string(record.observedState) ?? string(record.nodeState);
96
+ if (explicit)
97
+ return explicit;
98
+ if (source === 'mission-ledger' && record.checkpoint && typeof record.checkpoint === 'object') {
99
+ const checkpoint = record.checkpoint;
100
+ if (Array.isArray(checkpoint.pending) && checkpoint.pending.length)
101
+ return 'running';
102
+ if (Array.isArray(checkpoint.failed) && checkpoint.failed.length)
103
+ return 'failed';
104
+ if (Array.isArray(checkpoint.completed) && checkpoint.completed.length)
105
+ return 'completed';
106
+ }
107
+ return 'unknown';
108
+ }
109
+ function sourceVersion(source, record) {
110
+ if (source === 'canonical')
111
+ return string(record.apiVersion) ?? 'unknown';
112
+ if (source === 'uhp-2026-08-11')
113
+ return '2026-08-11';
114
+ if (source === 'executor-v1')
115
+ return 'executor.aiwg.io/v1';
116
+ if (source === 'fleet-workload-v1')
117
+ return 'fleet-workload/v1';
118
+ if (source === 'graph-flow-v1')
119
+ return 'graph.flow.aiwg.io/v1';
120
+ if (source === 'activity-v1')
121
+ return 'activity.aiwg.io/v1';
122
+ return string(record.apiVersion) ?? string(record.api_version) ?? string(record.schemaVersion) ?? string(record.schema_version) ?? 'unversioned';
123
+ }
124
+ function assertSupported(version) {
125
+ const supported = new Set(['unversioned', MISSION_API_VERSION, '2026-08-11', 'executor.aiwg.io/v1', 'fleet-workload/v1', 'graph.flow.aiwg.io/v1', 'activity.aiwg.io/v1']);
126
+ if (supported.has(version))
127
+ return;
128
+ const major = version.match(/(?:^|\/)v(\d+)(?:$|[.-])/)?.[1];
129
+ if (major && major !== '1')
130
+ throw new Error(`Unsupported Mission source major version '${version}'; supported major is v1.`);
131
+ throw new Error(`Unsupported Mission source version '${version}'.`);
132
+ }
133
+ export function validateCanonicalMission(value) {
134
+ const record = object(value, 'Canonical Mission');
135
+ if (record.apiVersion !== MISSION_API_VERSION)
136
+ throw new Error(`Unsupported canonical Mission version '${String(record.apiVersion)}'.`);
137
+ if (record.kind !== 'Mission')
138
+ throw new Error("Canonical Mission kind must be 'Mission'.");
139
+ const metadata = object(record.metadata, 'Mission metadata');
140
+ const spec = object(record.spec, 'Mission spec');
141
+ const status = object(record.status, 'Mission status');
142
+ const provenance = object(record.provenance, 'Mission provenance');
143
+ if (!string(metadata.id) || !string(spec.objective) || !string(provenance.sourceContract) || !string(provenance.sourceVersion))
144
+ throw new Error('Canonical Mission is missing required identity, objective, or provenance.');
145
+ const state = normalizeMissionState(status.state);
146
+ if (status.state !== state)
147
+ throw new Error(`Canonical Mission state '${String(status.state)}' is not normalized.`);
148
+ if (status.terminal !== TERMINAL.has(state))
149
+ throw new Error(`Canonical Mission terminal flag contradicts state '${state}'.`);
150
+ if (!Array.isArray(status.artifacts))
151
+ throw new Error('Canonical Mission artifacts must be an array.');
152
+ return structuredClone(value);
153
+ }
154
+ export function decodeMission(input, source) {
155
+ const record = object(input);
156
+ if (source === 'canonical') {
157
+ const value = validateCanonicalMission(record);
158
+ return { value, sourceVersion: MISSION_API_VERSION, warnings: [], preservedExtensions: structuredClone(value.extensions ?? {}), lossReport: [] };
159
+ }
160
+ const version = sourceVersion(source, record);
161
+ assertSupported(version);
162
+ const statusRecord = record.status && typeof record.status === 'object' ? record.status : {};
163
+ const nativeState = nativeStateFor(source, record, statusRecord);
164
+ const state = normalizeMissionState(nativeState);
165
+ const objective = string(record.goal) ?? string(record.objective) ?? string(record.title) ?? string(record.prompt) ?? '(legacy mission objective unavailable)';
166
+ const completionCriterion = string(record.completionCriterion) ?? string(record.completion_criterion) ?? string(record.completion);
167
+ const preserved = extensions(record, source);
168
+ const warnings = [];
169
+ const lossReport = [];
170
+ if (objective.startsWith('(legacy'))
171
+ warnings.push('Source did not contain a mission objective; placeholder retained.');
172
+ if (state === 'unknown' && nativeState !== 'unknown')
173
+ warnings.push(`Unknown native state '${nativeState}' preserved beside normalized unknown state.`);
174
+ const sourceArtifacts = artifacts(record);
175
+ if (source === 'uhp-2026-08-11') {
176
+ const ids = new Set(sourceArtifacts.map(artifact => artifact.id));
177
+ for (const artifact of uhpOutputArtifacts(record))
178
+ if (!ids.has(artifact.id))
179
+ sourceArtifacts.push(artifact);
180
+ }
181
+ const budgets = record.budgets && typeof record.budgets === 'object' ? record.budgets : undefined;
182
+ const lineage = Array.isArray(record.lineage) ? record.lineage.flatMap(item => {
183
+ if (!item || typeof item !== 'object')
184
+ return [];
185
+ const entry = item;
186
+ return string(entry.relation) && string(entry.id) ? [{ relation: string(entry.relation), id: string(entry.id) }] : [];
187
+ }) : undefined;
188
+ const value = {
189
+ apiVersion: MISSION_API_VERSION,
190
+ kind: 'Mission',
191
+ metadata: {
192
+ id: requiredId(record),
193
+ ...(string(record.createdAt) ?? string(record.created_at) ? { createdAt: string(record.createdAt) ?? string(record.created_at) } : {}),
194
+ ...(string(record.updatedAt) ?? string(record.updated_at) ? { updatedAt: string(record.updatedAt) ?? string(record.updated_at) } : {}),
195
+ ...(string(record.previous_response_id) ? { previousId: string(record.previous_response_id) } : {}),
196
+ ...(lineage?.length ? { lineage } : {}),
197
+ },
198
+ spec: { objective, ...(completionCriterion ? { completionCriterion } : {}), ...(budgets ? { budgets: structuredClone(budgets) } : {}) },
199
+ status: {
200
+ state,
201
+ terminal: TERMINAL.has(state),
202
+ nativeState,
203
+ artifacts: sourceArtifacts,
204
+ ...(record.output !== undefined || record.partialOutput !== undefined || record.partial_output !== undefined ? { partialOutput: structuredClone(record.partialOutput ?? record.partial_output ?? record.output) } : {}),
205
+ },
206
+ provenance: { sourceContract: source, sourceVersion: version, ...(source === 'a2a' || source.startsWith('uhp') ? { transport: source.split('-')[0] } : {}), sourceId: requiredId(record) },
207
+ ...(Object.keys(preserved).length ? { extensions: { [`aiwg.source.${source}`]: preserved } } : {}),
208
+ };
209
+ return { value, sourceVersion: version, warnings, preservedExtensions: preserved, lossReport };
210
+ }
211
+ function projectionLosses(value, target) {
212
+ const losses = [];
213
+ if (value.status.verification?.length)
214
+ losses.push({ path: '/status/verification', reason: `${target} has no native verification ledger`, severity: 'warning' });
215
+ if (value.metadata.lineage?.length && !['mission-ledger', 'fleet-workload-v1', 'canonical'].includes(target))
216
+ losses.push({ path: '/metadata/lineage', reason: `${target} cannot represent full lineage`, severity: 'required' });
217
+ if (value.spec.budgets && !['fleet-workload-v1', 'canonical'].includes(target))
218
+ losses.push({ path: '/spec/budgets', reason: `${target} cannot represent every canonical budget`, severity: 'warning' });
219
+ return losses;
220
+ }
221
+ export function encodeMission(value, target, options = {}) {
222
+ const mission = validateCanonicalMission(value);
223
+ if (target === 'canonical')
224
+ return { value: mission, targetVersion: MISSION_API_VERSION, warnings: [], lossReport: [] };
225
+ const lossReport = projectionLosses(mission, target);
226
+ const required = lossReport.filter(loss => loss.severity === 'required');
227
+ if (required.length && !options.allowLoss)
228
+ throw new Error(`Projection to ${target} would silently lose required semantics: ${required.map(loss => loss.path).join(', ')}.`);
229
+ const base = {
230
+ missionId: mission.metadata.id,
231
+ goal: mission.spec.objective,
232
+ completionCriterion: mission.spec.completionCriterion,
233
+ status: mission.status.nativeState ?? mission.status.state,
234
+ artifacts: structuredClone(mission.status.artifacts),
235
+ partialOutput: structuredClone(mission.status.partialOutput),
236
+ lineage: structuredClone(mission.metadata.lineage ?? []),
237
+ extensions: {
238
+ 'aiwg.mission.canonical': { apiVersion: mission.apiVersion, state: mission.status.state, lossReport },
239
+ ...(mission.extensions ?? {}),
240
+ },
241
+ };
242
+ let projected = base;
243
+ if (target === 'mission-plan')
244
+ projected = { missionId: base.missionId, goal: base.goal, completionCriterion: base.completionCriterion ?? '', cycles: [], extensions: base.extensions };
245
+ else if (target === 'mission-ledger')
246
+ projected = { ...base, activityLog: [], cycles: [], totalCost: 0, checkpoint: { completed: [], pending: [], failed: [] }, runtimesUsed: [] };
247
+ else if (target === 'uhp-2026-08-11')
248
+ projected = { id: mission.provenance.sourceId ?? mission.metadata.id, object: 'response', created_at: 0, status: base.status, model: '', output: mission.status.partialOutput ?? [], metadata: base.extensions };
249
+ else if (target === 'a2a')
250
+ projected = { id: mission.provenance.sourceId ?? mission.metadata.id, status: { state: base.status }, artifacts: base.artifacts, partialOutput: base.partialOutput, metadata: base.extensions };
251
+ else if (target === 'graph-flow-v1')
252
+ projected = { schemaVersion: 'graph.flow.aiwg.io/v1', runId: mission.metadata.id, nodeState: mission.status.state, metadata: base.extensions };
253
+ else if (target === 'cockpit')
254
+ projected = { id: mission.metadata.id, session_id: mission.metadata.id, source: mission.provenance.transport ?? mission.provenance.sourceContract, title: mission.spec.objective, completion: mission.spec.completionCriterion, status: mission.status.state, artifacts: base.artifacts, partialOutput: base.partialOutput, extensions: base.extensions };
255
+ else if (target === 'activity-v1')
256
+ projected = { event: 'mission.projected', missionId: mission.metadata.id, objective: mission.spec.objective, state: mission.status.state, metadata: base.extensions };
257
+ else if (target === 'executor-v1')
258
+ projected = { mission_id: mission.metadata.id, objective: mission.spec.objective, completion_criterion: mission.spec.completionCriterion, state: base.status, artifacts: base.artifacts, partial_output: base.partialOutput, metadata: base.extensions };
259
+ else if (target === 'fleet-workload-v1')
260
+ projected = { mission_id: mission.metadata.id, objective: mission.spec.objective, completion_criterion: mission.spec.completionCriterion, observed_state: base.status, budgets: mission.spec.budgets, artifacts: base.artifacts, partial_output: base.partialOutput, lineage: base.lineage, metadata: base.extensions };
261
+ else if (target === 'mission-control-session')
262
+ projected = { id: mission.metadata.id, objective: mission.spec.objective, status: mission.status.state, completion: mission.spec.completionCriterion, artifacts: base.artifacts, partialOutput: base.partialOutput, extensions: base.extensions };
263
+ return { value: projected, targetVersion: target, warnings: lossReport.map(loss => `${loss.path}: ${loss.reason}`), lossReport };
264
+ }
265
+ //# sourceMappingURL=codecs.js.map
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './codecs.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ export const MISSION_API_VERSION = 'mission.aiwg.io/v1';
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Versioned capability contract for scalable storage and index backends.
3
+ *
4
+ * This contract describes semantics; it does not make optional capabilities
5
+ * available. Consumers must negotiate before using anything beyond the
6
+ * required baseline.
7
+ *
8
+ * @issue #2193
9
+ */
10
+ export const STORAGE_BACKEND_CONTRACT = 'aiwg.storage-backend/v1';
11
+ export class StorageCapabilityError extends Error {
12
+ code = 'AIWG_STORAGE_CAPABILITY_NEGOTIATION_FAILED';
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'StorageCapabilityError';
16
+ }
17
+ }
18
+ /** Fail-closed negotiation. Unknown major contracts and missing capabilities never degrade silently. */
19
+ export function negotiateStorageCapabilities(descriptor, request) {
20
+ if (request.contract !== STORAGE_BACKEND_CONTRACT) {
21
+ throw new StorageCapabilityError(`unsupported storage contract "${request.contract}"; backend provides ${STORAGE_BACKEND_CONTRACT}`);
22
+ }
23
+ if (request.acceptedSchemaVersions?.length &&
24
+ !request.acceptedSchemaVersions.includes(descriptor.schemaVersion)) {
25
+ throw new StorageCapabilityError(`backend schema ${descriptor.schemaVersion} is not in the accepted schema set`);
26
+ }
27
+ const available = new Set(descriptor.capabilities);
28
+ const missing = [...new Set(request.required)].filter(capability => !available.has(capability));
29
+ if (missing.length) {
30
+ throw new StorageCapabilityError(`backend ${descriptor.backend} lacks required capabilities: ${missing.sort().join(', ')}`);
31
+ }
32
+ return {
33
+ contract: STORAGE_BACKEND_CONTRACT,
34
+ backend: descriptor.backend,
35
+ schemaVersion: descriptor.schemaVersion,
36
+ capabilities: [...descriptor.capabilities].sort(),
37
+ };
38
+ }
39
+ const BASELINE = ['read', 'subsystem-isolation'];
40
+ export const STORAGE_BACKEND_MATRIX = {
41
+ 'json-filesystem': descriptor('json-filesystem', 'supported', BASELINE, 'filesystem', 'single-host', 'none', 'regenerable-index'),
42
+ graphology: descriptor('graphology', 'supported', BASELINE, 'process', 'local-process', 'none', 'regenerable-index'),
43
+ sqlite: descriptor('sqlite', 'supported', [...BASELINE, 'atomic-batch', 'consistent-snapshot', 'tombstones', 'idempotency-keys', 'filtered-query', 'cursor-pagination', 'backup', 'restore'], 'wal', 'single-host', 'serializable', 'regenerable-index'),
44
+ 'fortemi-core-static': descriptor('fortemi-core-static', 'supported', ['read', 'filtered-query', 'recursive-traversal', 'set-operations'], 'filesystem', 'single-host', 'snapshot', 'static-cache'),
45
+ 'fortemi-server': descriptor('fortemi-server', 'alpha', [...BASELINE, 'filtered-query', 'health', 'tls', 'tenant-isolation'], 'replicated', 'remote-service', 'none', 'remote-persistence'),
46
+ 'postgres-direct': descriptor('postgres-direct', 'advanced', [], 'replicated', 'remote-service', 'none', 'canonical'),
47
+ 'postgres-postgrest': descriptor('postgres-postgrest', 'advanced', [], 'replicated', 'remote-service', 'none', 'canonical'),
48
+ mysql: descriptor('mysql', 'deferred', [], 'replicated', 'remote-service', 'none', 'canonical'),
49
+ };
50
+ function descriptor(backend, maturity, capabilities, durability, availability, isolation, dataClass) {
51
+ return {
52
+ contract: STORAGE_BACKEND_CONTRACT,
53
+ backend,
54
+ implementationVersion: '1.0.0',
55
+ schemaVersion: '1',
56
+ maturity,
57
+ capabilities,
58
+ durability,
59
+ availability,
60
+ isolation,
61
+ dataClass,
62
+ };
63
+ }
64
+ //# sourceMappingURL=backend-contract.js.map
@@ -21,6 +21,8 @@ export { FilesystemAdapter } from './backends/fs.js';
21
21
  export { ObsidianAdapter } from './backends/obsidian.js';
22
22
  export { LogseqAdapter } from './backends/logseq.js';
23
23
  export { FortemiAdapter } from './backends/fortemi.js';
24
+ export { STORAGE_BACKEND_CONTRACT, STORAGE_BACKEND_MATRIX, StorageCapabilityError, negotiateStorageCapabilities, } from './backend-contract.js';
25
+ export { STORAGE_MIGRATION_PROTOCOL, MigrationProtocolError, StorageMigrationCoordinator, approvalDigest, digestRecords, validateManifest, } from './migration-protocol.js';
24
26
  let state = null;
25
27
  /**
26
28
  * Initialize or reset the registry for a given project root. Most