@aiwg/cli 2026.7.20 → 2026.7.23

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 (62) hide show
  1. package/README.md +18 -7
  2. package/dist/src/api/index.d.ts +2 -0
  3. package/dist/src/api/index.js +2 -0
  4. package/dist/src/artifacts/browser-export.js +7 -0
  5. package/dist/src/artifacts/citation-parser.js +96 -35
  6. package/dist/src/artifacts/index-builder.js +54 -17
  7. package/dist/src/artifacts/state-transfer.js +27 -0
  8. package/dist/src/artifacts/stats.js +8 -0
  9. package/dist/src/cli/cli-extension-loader.js +73 -0
  10. package/dist/src/cli/handlers/index.js +3 -1
  11. package/dist/src/cli/handlers/sessions.js +1265 -0
  12. package/dist/src/cli/handlers/skill-lint.js +49 -45
  13. package/dist/src/cli/handlers/use.js +143 -60
  14. package/dist/src/cli/handlers/utilities.js +22 -8
  15. package/dist/src/cli/skill-usage.js +146 -24
  16. package/dist/src/config/aiwg-config.js +12 -0
  17. package/dist/src/config/cli.js +16 -3
  18. package/dist/src/extensions/commands/definitions.js +29 -0
  19. package/dist/src/extensions/manifest.js +29 -0
  20. package/dist/src/security/threat-assessment-config.js +296 -0
  21. package/dist/src/sessions/adapters/claude.js +385 -0
  22. package/dist/src/sessions/adapters/codex.js +548 -0
  23. package/dist/src/sessions/adapters/copilot.js +226 -0
  24. package/dist/src/sessions/adapters/cursor.js +528 -0
  25. package/dist/src/sessions/adapters/factory.js +386 -0
  26. package/dist/src/sessions/adapters/generic.js +225 -0
  27. package/dist/src/sessions/adapters/hermes.js +341 -0
  28. package/dist/src/sessions/adapters/openclaw.js +381 -0
  29. package/dist/src/sessions/adapters/opencode.js +454 -0
  30. package/dist/src/sessions/adapters/openhuman.js +315 -0
  31. package/dist/src/sessions/adapters/warp.js +160 -0
  32. package/dist/src/sessions/adapters/windsurf.js +212 -0
  33. package/dist/src/sessions/batch-contracts.js +121 -0
  34. package/dist/src/sessions/batch-import.js +265 -0
  35. package/dist/src/sessions/candidates.js +210 -0
  36. package/dist/src/sessions/contracts.js +337 -0
  37. package/dist/src/sessions/discovery.js +51 -0
  38. package/dist/src/sessions/fixtures.js +12 -0
  39. package/dist/src/sessions/import-lease.js +152 -0
  40. package/dist/src/sessions/importer.js +464 -0
  41. package/dist/src/sessions/index.js +31 -0
  42. package/dist/src/sessions/knowledge-shard.js +61 -0
  43. package/dist/src/sessions/optional-backends.js +238 -0
  44. package/dist/src/sessions/origin.js +117 -0
  45. package/dist/src/sessions/policy.js +192 -0
  46. package/dist/src/sessions/ports.js +2 -0
  47. package/dist/src/sessions/promotion.js +367 -0
  48. package/dist/src/sessions/readers.js +176 -0
  49. package/dist/src/sessions/repository.js +1892 -0
  50. package/dist/src/sessions/timeline.js +148 -0
  51. package/dist/src/sessions/workspace-discovery.js +319 -0
  52. package/dist/src/skills/adapters/agent-skills.js +59 -0
  53. package/dist/src/skills/adapters/local.js +19 -1
  54. package/dist/src/skills/agent-skills.js +249 -0
  55. package/dist/src/skills/cli.js +463 -7
  56. package/dist/src/skills/deployer.js +554 -0
  57. package/dist/src/skills/doctor.js +105 -0
  58. package/dist/src/skills/exporter.js +382 -0
  59. package/dist/src/skills/importer.js +921 -0
  60. package/dist/src/skills/registry.js +19 -0
  61. package/dist/src/skills/validator.js +323 -0
  62. package/package.json +2 -2
@@ -0,0 +1,464 @@
1
+ import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, } from './contracts.js';
2
+ import { redactSessionText, sanitizeNativeExtensions } from './policy.js';
3
+ import { fingerprintSourcePrefix } from './readers.js';
4
+ import { classifySessionEventOrigin, deriveSessionIntent, } from './origin.js';
5
+ const DEFAULT_LIMITS = {
6
+ maxRecords: 1_000_000,
7
+ maxRecordBytes: 8 * 1024 * 1024,
8
+ maxTotalBytes: 1024 * 1024 * 1024,
9
+ batchSize: 1_000,
10
+ };
11
+ export class SessionImportFailure extends SessionContractError {
12
+ failureReceipt;
13
+ constructor(failureReceipt, cause) {
14
+ super(cause instanceof SessionContractError ? cause.code : 'IMPORT_INTERRUPTED', cause instanceof Error ? cause.message : 'session import failed');
15
+ this.failureReceipt = failureReceipt;
16
+ this.name = 'SessionImportFailure';
17
+ }
18
+ }
19
+ export class IncrementalSessionImporter {
20
+ repository;
21
+ constructor(repository) {
22
+ this.repository = repository;
23
+ }
24
+ async import(request) {
25
+ assertSupportedSchemaMajor(request.source.sourceSchemaVersion);
26
+ if (request.inactivityThresholdMs !== undefined
27
+ && (!Number.isFinite(request.inactivityThresholdMs) || request.inactivityThresholdMs < 0)) {
28
+ throw new SessionContractError('INVALID_ARGUMENT', 'session inactivity threshold must be a non-negative duration');
29
+ }
30
+ if (request.workspaceId !== request.selectedSource.authorizedScope.workspaceId) {
31
+ throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'session import workspace is outside the authorized source scope');
32
+ }
33
+ const limits = { ...DEFAULT_LIMITS, ...request.limits };
34
+ const previous = request.batchRunId
35
+ ? this.repository.getBatchCheckpoint(request.source.sourceId, request.adapter.adapterVersion, request.batchRunId) ?? this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion)
36
+ : this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion);
37
+ const continuity = await sourceContinuity(request, previous);
38
+ const sourceObservedAt = continuity
39
+ ? new Date(continuity.mtimeMs).toISOString()
40
+ : undefined;
41
+ const sourceGeneration = continuity?.sourceGeneration ?? sourceGenerationDigest(request);
42
+ if (previous?.sourceGeneration && previous.sourceGeneration !== sourceGeneration) {
43
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source generation changed; explicit restart or migration is required');
44
+ }
45
+ if (previous?.adapterVersion && previous.adapterVersion !== request.adapter.adapterVersion) {
46
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint adapter version changed; checkpoint migration is required');
47
+ }
48
+ if (previous?.sourceSchemaVersion
49
+ && previous.sourceSchemaVersion !== request.source.sourceSchemaVersion) {
50
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint source schema changed; checkpoint migration is required');
51
+ }
52
+ if (previous?.policyVersion && previous.policyVersion !== request.policyVersion) {
53
+ throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint policy version changed; checkpoint migration is required');
54
+ }
55
+ const checkpoint = {
56
+ cursor: previous?.cursor ?? '',
57
+ recordsRead: previous?.recordsRead ?? 0,
58
+ bytesRead: previous?.bytesRead ?? 0,
59
+ checkpointVersion: '2',
60
+ positionKind: previous?.positionKind ?? 'record-index',
61
+ sourceGeneration,
62
+ locatorClass: request.selectedSource.locatorClass,
63
+ adapterVersion: request.adapter.adapterVersion,
64
+ sourceSchemaVersion: request.source.sourceSchemaVersion,
65
+ policyVersion: request.policyVersion,
66
+ continuity: continuity
67
+ ? (!previous || previous.positionKind === 'byte-offset'
68
+ ? continuity.outcome
69
+ : 'unverified')
70
+ : (previous ? 'unverified' : 'new-generation'),
71
+ sourceSize: continuity?.size,
72
+ sourceMtimeMs: continuity?.mtimeMs,
73
+ sourceFileIdentity: continuity?.fileIdentity,
74
+ prefixDigest: continuity?.prefixDigest,
75
+ };
76
+ const receipts = [];
77
+ let batch = [];
78
+ let batchStart = checkpoint.recordsRead;
79
+ let durableCheckpoint = { ...checkpoint };
80
+ const importStarted = performance.now();
81
+ let peakHeap = process.memoryUsage().heapUsed;
82
+ let peakRss = process.memoryUsage().rss;
83
+ const flush = () => {
84
+ if (batch.length === 0)
85
+ return;
86
+ if (request.signal?.aborted) {
87
+ throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled at a durable batch boundary');
88
+ }
89
+ const runId = sha256([
90
+ request.source.sourceId, request.adapter.adapterVersion,
91
+ batchStart, checkpoint.recordsRead,
92
+ ...batch.map((record) => sha256(JSON.stringify(record))),
93
+ ].join('\0'));
94
+ const normalized = normalizeBatch(request, batch, runId, sourceObservedAt);
95
+ const run = {
96
+ contractVersion: SESSION_CONTRACT_VERSION,
97
+ importRunId: runId,
98
+ sourceId: request.source.sourceId,
99
+ parserVersion: request.adapter.adapterVersion,
100
+ policyVersion: request.policyVersion,
101
+ sourceSchemaVersion: request.source.sourceSchemaVersion,
102
+ consistency: request.source.consistency,
103
+ status: 'running',
104
+ checkpoint: { ...checkpoint },
105
+ startedAt: new Date().toISOString(),
106
+ completedAt: null,
107
+ errorCode: null,
108
+ };
109
+ const flushStarted = performance.now();
110
+ const sanitizedSource = {
111
+ ...request.source,
112
+ extensions: sanitizeNativeExtensions(request.source.extensions).value,
113
+ };
114
+ const receipt = this.repository.applyImport({
115
+ source: sanitizedSource, run,
116
+ sessions: normalized.sessions, events: normalized.events,
117
+ batchRunId: request.batchRunId,
118
+ }, { ...checkpoint }, request.publish ?? request.source.consistency !== 'complete');
119
+ const memory = process.memoryUsage();
120
+ peakHeap = Math.max(peakHeap, memory.heapUsed);
121
+ peakRss = Math.max(peakRss, memory.rss);
122
+ receipt.metrics = {
123
+ records: batch.length,
124
+ normalizedEvents: normalized.events.length,
125
+ normalizedBytes: batch.reduce((total, record) => total + Buffer.byteLength(JSON.stringify(record)), 0),
126
+ durationMs: performance.now() - importStarted,
127
+ batchLatencyMs: performance.now() - flushStarted,
128
+ heapUsedBytes: peakHeap,
129
+ rssBytes: peakRss,
130
+ checkpointDurable: true,
131
+ };
132
+ receipts.push(receipt);
133
+ durableCheckpoint = { ...checkpoint };
134
+ batch = [];
135
+ batchStart = checkpoint.recordsRead;
136
+ };
137
+ try {
138
+ for await (const record of request.adapter.stream(request.selectedSource, previous ? { value: previous.cursor } : undefined)) {
139
+ if (request.signal?.aborted) {
140
+ throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled and can resume from its durable checkpoint');
141
+ }
142
+ const bytes = Buffer.byteLength(JSON.stringify(record));
143
+ if (bytes > limits.maxRecordBytes
144
+ || checkpoint.bytesRead + bytes > limits.maxTotalBytes
145
+ || checkpoint.recordsRead + 1 > limits.maxRecords) {
146
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'session import exceeded an authorized resource limit');
147
+ }
148
+ batch.push(record);
149
+ checkpoint.recordsRead += 1;
150
+ if (record.sourceCursor?.startsWith('byte:')) {
151
+ checkpoint.positionKind = 'byte-offset';
152
+ checkpoint.cursor = record.sourceCursor;
153
+ checkpoint.bytesRead = Number(record.sourceCursor.slice(5));
154
+ }
155
+ else {
156
+ checkpoint.bytesRead += bytes;
157
+ checkpoint.cursor = String(checkpoint.recordsRead);
158
+ }
159
+ if (batch.length >= limits.batchSize)
160
+ flush();
161
+ }
162
+ flush();
163
+ }
164
+ catch (error) {
165
+ const published = request.publish ?? request.source.consistency !== 'complete';
166
+ const committed = published ? receipts : [];
167
+ throw new SessionImportFailure({
168
+ contractVersion: '1.0.0',
169
+ outcome: 'terminal-failure',
170
+ sourceId: request.source.sourceId,
171
+ sourceGeneration,
172
+ consistency: request.source.consistency,
173
+ committedPrefix: {
174
+ batches: committed.length,
175
+ records: committed.reduce((total, receipt) => total + (receipt.metrics?.records ?? 0), 0),
176
+ events: committed.reduce((total, receipt) => total + receipt.eventsInserted, 0),
177
+ },
178
+ resumableCheckpoint: !published
179
+ ? {
180
+ ...durableCheckpoint,
181
+ cursor: '',
182
+ recordsRead: 0,
183
+ bytesRead: 0,
184
+ continuity: 'new-generation',
185
+ }
186
+ : durableCheckpoint,
187
+ errorCode: error instanceof SessionContractError
188
+ ? error.code : 'IMPORT_INTERRUPTED',
189
+ }, error);
190
+ }
191
+ if (request.publish !== false && request.source.consistency === 'complete') {
192
+ this.repository.commitStagedImports(request.source.sourceId, request.adapter.adapterVersion);
193
+ for (const receipt of receipts) {
194
+ if (receipt.outcome === 'staged')
195
+ receipt.outcome = 'committed';
196
+ }
197
+ }
198
+ return receipts;
199
+ }
200
+ }
201
+ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
202
+ const sessions = new Map();
203
+ const events = records.map((record) => {
204
+ const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
205
+ const redacted = redactSessionText(record.text);
206
+ const native = sanitizeNativeExtensions(record.extensions ?? {});
207
+ const digest = sha256(JSON.stringify(record));
208
+ const origin = classifySessionEventOrigin(request.source.provider, record);
209
+ const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
210
+ const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
211
+ const extensions = {
212
+ [`native.${request.source.provider}`]: native.value,
213
+ };
214
+ const event = SessionEventSchema.parse({
215
+ contractVersion: SESSION_CONTRACT_VERSION,
216
+ eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
217
+ sessionId, sourceId: request.source.sourceId, importRunId,
218
+ nativeId: record.nativeEventId ?? null, sequence: record.sequence,
219
+ kind: record.kind, role: record.role ?? null, occurredAt: record.occurredAt ?? null,
220
+ activityBoundary: record.activityBoundary ?? null,
221
+ activityBoundaryBasis: record.activityBoundaryBasis ?? null,
222
+ activityBoundaryConfidence: record.activityBoundaryConfidence ?? null,
223
+ origin: origin.origin,
224
+ originRule: origin.rule,
225
+ originClassifierVersion: origin.classifierVersion,
226
+ participant: record.participant ?? null,
227
+ toolName: record.toolName ?? null,
228
+ toolCallId: record.toolCallId ?? null,
229
+ model: record.model ?? null,
230
+ entities: record.entities ?? [],
231
+ extractionState: record.extractionState ?? null,
232
+ searchableText: redacted.text, digest, rawReference: record.rawReference,
233
+ adapterVersion: request.adapter.adapterVersion,
234
+ consistency: request.source.consistency,
235
+ sensitivity: {
236
+ classification: redacted.sensitivity === 'sensitive' || native.sensitivity === 'sensitive'
237
+ ? 'sensitive' : 'none',
238
+ classes: [...new Set([...redacted.classes, ...native.classes])].sort(),
239
+ },
240
+ opaque: !KNOWN_EVENT_KINDS.has(record.kind),
241
+ extensions,
242
+ });
243
+ if (!sessions.has(sessionId)) {
244
+ sessions.set(sessionId, SessionSchema.parse({
245
+ contractVersion: SESSION_CONTRACT_VERSION,
246
+ sessionId, sourceId: request.source.sourceId, provider: request.source.provider,
247
+ nativeSessionId: record.nativeSessionId, workspaceId: request.workspaceId,
248
+ startedAt: record.occurredAt ?? null, updatedAt: record.occurredAt ?? null,
249
+ consistency: request.source.consistency,
250
+ lifecycle,
251
+ sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
252
+ extensions: {
253
+ [`native.${request.source.provider}`]: {
254
+ lifecycleEvidence,
255
+ },
256
+ },
257
+ }));
258
+ }
259
+ else {
260
+ const session = sessions.get(sessionId);
261
+ session.startedAt = earlierTimestamp(session.startedAt, record.occurredAt ?? null);
262
+ session.updatedAt = laterTimestamp(session.updatedAt, record.occurredAt ?? null);
263
+ session.consistency = strongerConsistency(session.consistency, request.source.consistency);
264
+ const nativeKey = `native.${request.source.provider}`;
265
+ const nativeEnvelope = session.extensions[nativeKey];
266
+ const nativeRecord = nativeEnvelope && typeof nativeEnvelope === 'object' && !Array.isArray(nativeEnvelope)
267
+ ? nativeEnvelope
268
+ : {};
269
+ const selected = selectLifecycleTransition(session.lifecycle, nativeRecord.lifecycleEvidence, lifecycle, lifecycleEvidence);
270
+ session.lifecycle = selected.lifecycle;
271
+ session.extensions[nativeKey] = {
272
+ ...nativeRecord,
273
+ lifecycleEvidence: selected.evidence,
274
+ };
275
+ }
276
+ return event;
277
+ });
278
+ for (const session of sessions.values()) {
279
+ session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
280
+ }
281
+ return { sessions: [...sessions.values()], events };
282
+ }
283
+ const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
284
+ function earlierTimestamp(left, right) {
285
+ if (!left)
286
+ return right;
287
+ if (!right)
288
+ return left;
289
+ return Date.parse(left) <= Date.parse(right) ? left : right;
290
+ }
291
+ function laterTimestamp(left, right) {
292
+ if (!left)
293
+ return right;
294
+ if (!right)
295
+ return left;
296
+ return Date.parse(left) >= Date.parse(right) ? left : right;
297
+ }
298
+ function strongerConsistency(left, right) {
299
+ const rank = {
300
+ provisional: 0,
301
+ 'consistent-snapshot': 1,
302
+ complete: 2,
303
+ };
304
+ return rank[left] >= rank[right] ? left : right;
305
+ }
306
+ function sessionLifecycle(request, record, sourceObservedAt) {
307
+ const explicit = nativeLifecycle(record.extensions);
308
+ if (explicit)
309
+ return explicit;
310
+ if (request.source.consistency === 'complete')
311
+ return 'complete';
312
+ const observedAt = record.occurredAt ?? sourceObservedAt;
313
+ if (observedAt && isStaleHistoricalTimestamp(observedAt, inactivityThresholdMs(request)))
314
+ return 'inactive';
315
+ return 'active';
316
+ }
317
+ function sessionLifecycleEvidence(request, record, sourceObservedAt) {
318
+ const observedAt = record.occurredAt ?? sourceObservedAt;
319
+ const explicit = nativeLifecycle(record.extensions);
320
+ if (explicit) {
321
+ return {
322
+ basis: 'provider-explicit-event',
323
+ state: explicit,
324
+ observedAt: observedAt ?? request.source.authorizedAt,
325
+ confidence: 'high',
326
+ };
327
+ }
328
+ if (request.source.consistency === 'complete') {
329
+ return {
330
+ basis: 'complete-source',
331
+ state: 'complete',
332
+ observedAt: observedAt ?? request.source.authorizedAt,
333
+ confidence: 'high',
334
+ };
335
+ }
336
+ const thresholdMs = inactivityThresholdMs(request);
337
+ if (observedAt && isStaleHistoricalTimestamp(observedAt, thresholdMs)) {
338
+ return {
339
+ basis: 'inactivity-threshold',
340
+ state: 'inactive',
341
+ observedAt,
342
+ confidence: 'medium',
343
+ thresholdMs,
344
+ };
345
+ }
346
+ return {
347
+ basis: 'open-provisional-source',
348
+ state: 'active',
349
+ observedAt: observedAt ?? request.source.authorizedAt,
350
+ confidence: 'provisional',
351
+ };
352
+ }
353
+ function nativeLifecycle(extensions) {
354
+ const raw = typeof extensions?.lifecycle === 'string' ? extensions.lifecycle : undefined;
355
+ if (!raw)
356
+ return null;
357
+ const normalized = {
358
+ active: 'active',
359
+ inactive: 'inactive',
360
+ paused: 'paused',
361
+ complete: 'complete',
362
+ completed: 'complete',
363
+ archived: 'archived',
364
+ deleted: 'tombstoned',
365
+ cancelled: 'interrupted',
366
+ canceled: 'interrupted',
367
+ failed: 'interrupted',
368
+ interrupted: 'interrupted',
369
+ unknown: 'unknown',
370
+ 'unknown-at-import': 'unknown',
371
+ 'completed-at-import': 'complete',
372
+ };
373
+ return normalized[raw] ?? null;
374
+ }
375
+ function selectLifecycleTransition(leftLifecycle, left, rightLifecycle, right) {
376
+ const leftEvidence = asLifecycleEvidence(left);
377
+ if (leftLifecycle === 'tombstoned') {
378
+ return { lifecycle: leftLifecycle, evidence: leftEvidence ?? right };
379
+ }
380
+ if (!leftEvidence)
381
+ return { lifecycle: rightLifecycle, evidence: right };
382
+ const rank = {
383
+ 'open-provisional-source': 1,
384
+ 'inactivity-threshold': 1,
385
+ 'complete-source': 2,
386
+ 'provider-explicit-event': 3,
387
+ };
388
+ const leftRank = rank[String(leftEvidence.basis)] ?? 0;
389
+ const rightRank = rank[String(right.basis)] ?? 0;
390
+ const rightIsNewer = evidenceTimestamp(right) > evidenceTimestamp(leftEvidence);
391
+ return rightRank > leftRank || (rightRank === leftRank && rightIsNewer)
392
+ ? { lifecycle: rightLifecycle, evidence: right }
393
+ : { lifecycle: leftLifecycle, evidence: leftEvidence };
394
+ }
395
+ function asLifecycleEvidence(value) {
396
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
397
+ ? value
398
+ : null;
399
+ }
400
+ function evidenceTimestamp(value) {
401
+ const parsed = Date.parse(String(value.observedAt ?? ''));
402
+ return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
403
+ }
404
+ const DEFAULT_INACTIVITY_THRESHOLD_MS = 24 * 60 * 60 * 1000;
405
+ function inactivityThresholdMs(request) {
406
+ return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
407
+ }
408
+ function isStaleHistoricalTimestamp(value, thresholdMs) {
409
+ const timestamp = Date.parse(value);
410
+ return Number.isFinite(timestamp)
411
+ && Date.now() - timestamp > thresholdMs;
412
+ }
413
+ function sourceGenerationDigest(request) {
414
+ return sha256([
415
+ request.source.sourceId,
416
+ request.source.provider,
417
+ request.selectedSource.locatorClass,
418
+ request.source.sourceSchemaVersion,
419
+ request.adapter.adapterVersion,
420
+ ].join('\0'));
421
+ }
422
+ async function sourceContinuity(request, previous) {
423
+ if (request.selectedSource.authorizedScope.allowedRoots.length === 0
424
+ || /^[a-z][a-z0-9+.-]*:\/\//i.test(request.selectedSource.locator)
425
+ || request.selectedSource.locator.startsWith('<')) {
426
+ return null;
427
+ }
428
+ const authorization = {
429
+ selectedPath: request.selectedSource.locator,
430
+ allowedRoots: request.selectedSource.authorizedScope.allowedRoots,
431
+ };
432
+ const metadata = await fingerprintSourcePrefix(authorization, 0);
433
+ if (previous?.sourceSize !== undefined) {
434
+ if (metadata.size < previous.sourceSize) {
435
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source was truncated before its durable checkpoint');
436
+ }
437
+ if (previous.sourceFileIdentity
438
+ && previous.sourceFileIdentity !== metadata.fileIdentity) {
439
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source file generation was replaced or rotated');
440
+ }
441
+ const priorPrefix = await fingerprintSourcePrefix(authorization, previous.sourceSize);
442
+ if (previous.prefixDigest && priorPrefix.digest !== previous.prefixDigest) {
443
+ throw new SessionContractError('SCHEMA_DRIFT', 'session source prefix was rewritten before its durable checkpoint');
444
+ }
445
+ }
446
+ const current = await fingerprintSourcePrefix(authorization, metadata.size);
447
+ const generation = previous?.sourceGeneration ?? sha256([
448
+ sourceGenerationDigest(request),
449
+ metadata.fileIdentity,
450
+ ].join('\0'));
451
+ return {
452
+ sourceGeneration: generation,
453
+ outcome: !previous
454
+ ? 'new-generation'
455
+ : metadata.size === previous.sourceSize
456
+ && current.digest === previous.prefixDigest
457
+ ? 'unchanged-replay' : 'validated-append',
458
+ size: metadata.size,
459
+ mtimeMs: metadata.mtimeMs,
460
+ fileIdentity: metadata.fileIdentity,
461
+ prefixDigest: current.digest,
462
+ };
463
+ }
464
+ //# sourceMappingURL=importer.js.map
@@ -0,0 +1,31 @@
1
+ export * from './contracts.js';
2
+ export * from './fixtures.js';
3
+ export * from './policy.js';
4
+ export * from './discovery.js';
5
+ export * from './readers.js';
6
+ export * from './repository.js';
7
+ export * from './ports.js';
8
+ export * from './optional-backends.js';
9
+ export * from './knowledge-shard.js';
10
+ export * from './candidates.js';
11
+ export * from './promotion.js';
12
+ export * from './importer.js';
13
+ export * from './import-lease.js';
14
+ export * from './batch-contracts.js';
15
+ export * from './batch-import.js';
16
+ export * from './workspace-discovery.js';
17
+ export * from './timeline.js';
18
+ export * from './origin.js';
19
+ export * from './adapters/generic.js';
20
+ export * from './adapters/claude.js';
21
+ export * from './adapters/codex.js';
22
+ export * from './adapters/copilot.js';
23
+ export * from './adapters/cursor.js';
24
+ export * from './adapters/factory.js';
25
+ export * from './adapters/hermes.js';
26
+ export * from './adapters/opencode.js';
27
+ export * from './adapters/openclaw.js';
28
+ export * from './adapters/openhuman.js';
29
+ export * from './adapters/warp.js';
30
+ export * from './adapters/windsurf.js';
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,61 @@
1
+ export function convertSessionEventsToKnowledgeShard(source, events) {
2
+ const losses = [];
3
+ const records = events.map((event) => {
4
+ if (Object.values(event.extensions).some(hasPortableValue)) {
5
+ losses.push({
6
+ code: 'NATIVE_EXTENSION_NOT_PORTABLE',
7
+ eventId: event.eventId,
8
+ field: 'extensions',
9
+ reason: 'Knowledge Shard v1 has no canonical provider-native extension field',
10
+ });
11
+ }
12
+ if (event.rawReference.offset !== undefined) {
13
+ losses.push({
14
+ code: 'RAW_OFFSET_NOT_PORTABLE',
15
+ eventId: event.eventId,
16
+ field: 'rawReference.offset',
17
+ reason: 'Knowledge Shard v1 preserves locator class but not byte offsets',
18
+ });
19
+ }
20
+ if (event.rawReference.sequence !== undefined) {
21
+ losses.push({
22
+ code: 'RAW_SEQUENCE_NOT_PORTABLE',
23
+ eventId: event.eventId,
24
+ field: 'rawReference.sequence',
25
+ reason: 'Knowledge Shard v1 preserves event identity but not provider sequence locators',
26
+ });
27
+ }
28
+ return {
29
+ id: event.eventId,
30
+ content: event.searchableText,
31
+ metadata: {
32
+ provider: source.provider,
33
+ sessionId: event.sessionId,
34
+ eventId: event.eventId,
35
+ importRunId: event.importRunId,
36
+ sourceId: event.sourceId,
37
+ locatorClass: source.locatorClass,
38
+ role: event.role,
39
+ occurredAt: event.occurredAt,
40
+ sensitivity: event.sensitivity.classification,
41
+ },
42
+ };
43
+ });
44
+ return {
45
+ contractVersion: '1.0.0',
46
+ target: 'knowledge-shard-v1',
47
+ records,
48
+ losses,
49
+ lossless: losses.length === 0,
50
+ };
51
+ }
52
+ function hasPortableValue(value) {
53
+ if (value === null || value === undefined)
54
+ return false;
55
+ if (Array.isArray(value))
56
+ return value.length > 0;
57
+ if (typeof value === 'object')
58
+ return Object.keys(value).length > 0;
59
+ return true;
60
+ }
61
+ //# sourceMappingURL=knowledge-shard.js.map