@aiwg/cli 2026.10.10 → 2026.10.12

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 (156) hide show
  1. package/agentic/code/providers/model-capabilities.v1.json +78 -14
  2. package/agentic/code/providers/model-catalog.v1.json +62 -12
  3. package/dist/src/artifacts/binding-target-identity.js +51 -0
  4. package/dist/src/artifacts/checksum-manifest.js +12 -0
  5. package/dist/src/artifacts/index-builder.js +11 -13
  6. package/dist/src/artifacts/query-engine.js +5 -11
  7. package/dist/src/cli/handlers/doctor-help.js +32 -0
  8. package/dist/src/cli/handlers/gates.js +19 -18
  9. package/dist/src/cli/handlers/models-help.js +7 -1
  10. package/dist/src/cli/handlers/models.js +3 -3
  11. package/dist/src/cli/handlers/script-runner.js +8 -5
  12. package/dist/src/cli/handlers/sessions-intake.js +104 -0
  13. package/dist/src/cli/handlers/sessions-tail.js +172 -0
  14. package/dist/src/cli/handlers/sessions.js +287 -31
  15. package/dist/src/cli/handlers/skill-lint.js +10 -3
  16. package/dist/src/cli/handlers/steward-format.js +100 -0
  17. package/dist/src/cli/handlers/steward-models.js +167 -0
  18. package/dist/src/cli/handlers/steward.js +14 -248
  19. package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
  20. package/dist/src/cli/handlers/use.js +18 -28
  21. package/dist/src/cli/handlers/utilities.js +1 -24
  22. package/dist/src/config/aiwg-config.js +7 -0
  23. package/dist/src/config/authorization-cli.js +89 -0
  24. package/dist/src/config/cli-help.js +1 -0
  25. package/dist/src/config/cli.js +10 -1
  26. package/dist/src/config/worker-context.js +337 -0
  27. package/dist/src/decision/context-pruning.js +3 -2
  28. package/dist/src/decision/ensemble/contract.js +15 -4
  29. package/dist/src/decision/ensemble-study/artifacts.js +5 -0
  30. package/dist/src/decision/ensemble-study/score.js +4 -3
  31. package/dist/src/decision/feature-export.js +3 -9
  32. package/dist/src/decision/heldout/collector.js +2 -2
  33. package/dist/src/decision/issue-triage/runtime.js +3 -9
  34. package/dist/src/decision/qualification/gates.js +2 -1
  35. package/dist/src/decision/qualification/release.js +2 -3
  36. package/dist/src/decision/routing/report.js +2 -0
  37. package/dist/src/decision/sdlc-screening.js +3 -5
  38. package/dist/src/decision/sensitivity/comparative.js +5 -3
  39. package/dist/src/gates/driver.js +6 -77
  40. package/dist/src/gates/evaluate.js +4 -11
  41. package/dist/src/gates/floors.js +4 -4
  42. package/dist/src/gates/index.js +3 -3
  43. package/dist/src/gates/lattice.js +26 -0
  44. package/dist/src/gates/registry.js +2 -1
  45. package/dist/src/gates/report.js +19 -7
  46. package/dist/src/issues/audit-cli.js +120 -0
  47. package/dist/src/issues/audit-contract.js +64 -0
  48. package/dist/src/issues/audit-local.js +82 -0
  49. package/dist/src/issues/audit.js +220 -0
  50. package/dist/src/lint/rule-activation.js +15 -1
  51. package/dist/src/mcp/tools/worker-invoke.mjs +108 -10
  52. package/dist/src/mission-protocol/canonical-codecs.js +270 -0
  53. package/dist/src/mission-protocol/codecs.js +22 -550
  54. package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
  55. package/dist/src/mission-protocol/health-trace-types.js +43 -0
  56. package/dist/src/mission-protocol/types.js +2 -42
  57. package/dist/src/mission-protocol/worker-contract-json.js +10 -0
  58. package/dist/src/mission-protocol/worker-review-gate.js +100 -0
  59. package/dist/src/mission-protocol/worker-review-types.js +2 -0
  60. package/dist/src/models/catalog-policy.js +280 -0
  61. package/dist/src/models/index.js +1 -1
  62. package/dist/src/models/model-capabilities.v1.json +78 -14
  63. package/dist/src/models/model-catalog.v1.json +62 -12
  64. package/dist/src/models/policy-resources.js +28 -0
  65. package/dist/src/models/provider-policy.js +10 -539
  66. package/dist/src/models/resolver.js +26 -8
  67. package/dist/src/models/router.js +15 -2
  68. package/dist/src/models/tiers.js +13 -0
  69. package/dist/src/models/types.js +0 -6
  70. package/dist/src/models/worker-ceilings.js +59 -0
  71. package/dist/src/models/worker-invocation-policy.js +243 -0
  72. package/dist/src/models/worker-plan.js +16 -20
  73. package/dist/src/models/worker-review-lineage.js +55 -0
  74. package/dist/src/models/worker-selection-policy.js +1 -1
  75. package/dist/src/models/wrapper-route.js +6 -3
  76. package/dist/src/policy/authorization.js +30 -1
  77. package/dist/src/policy/hitl-config.js +63 -0
  78. package/dist/src/policy/hitl-receipt.js +57 -0
  79. package/dist/src/policy/hitl-types.js +4 -0
  80. package/dist/src/policy/hitl-validation.js +39 -0
  81. package/dist/src/policy/hitl.js +117 -0
  82. package/dist/src/process/aiwg-probe-command.d.mts +15 -0
  83. package/dist/src/process/aiwg-probe-command.mjs +37 -0
  84. package/dist/src/rules/activation.d.mts +1 -1
  85. package/dist/src/rules/activation.mjs +0 -2
  86. package/dist/src/rules/gate-coverage.js +51 -0
  87. package/dist/src/rules/gate-references.js +16 -0
  88. package/dist/src/rules/rule-frontmatter.schema.json +7 -1
  89. package/dist/src/serve/worker-command-request.js +21 -4
  90. package/dist/src/serve/worker-invocation-preparation.js +3 -1
  91. package/dist/src/serve/worker-invocation.js +21 -10
  92. package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
  93. package/dist/src/sessions/adapters/grok-build-native.js +269 -0
  94. package/dist/src/sessions/adapters/grok-build.js +57 -15
  95. package/dist/src/sessions/adapters/grokbot.js +7 -0
  96. package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
  97. package/dist/src/sessions/adapters/hermes.js +42 -3
  98. package/dist/src/sessions/adapters/warp.js +1 -1
  99. package/dist/src/sessions/batch-import.js +44 -6
  100. package/dist/src/sessions/contracts.js +20 -1
  101. package/dist/src/sessions/coverage-preflight.js +7 -1
  102. package/dist/src/sessions/discovery-capability.js +38 -0
  103. package/dist/src/sessions/fortemi-export-mapping.js +33 -3
  104. package/dist/src/sessions/host-catalog.js +157 -0
  105. package/dist/src/sessions/image-blobs.js +141 -0
  106. package/dist/src/sessions/importer.js +9 -232
  107. package/dist/src/sessions/index.js +6 -0
  108. package/dist/src/sessions/intake-dir.js +71 -0
  109. package/dist/src/sessions/normalization.js +251 -0
  110. package/dist/src/sessions/refresh.js +25 -2
  111. package/dist/src/sessions/repository.js +164 -22
  112. package/dist/src/sessions/tail.js +91 -0
  113. package/dist/src/sessions/workspace-discovery.js +88 -9
  114. package/dist/src/skills/agent-skill-sidecar.js +28 -0
  115. package/dist/src/skills/agent-skills.js +4 -23
  116. package/dist/src/skills/claude-surface-projection.js +25 -0
  117. package/dist/src/skills/deployer.js +8 -288
  118. package/dist/src/skills/deployment-policy.js +114 -0
  119. package/dist/src/skills/deployment-projection.js +152 -0
  120. package/dist/src/skills/deployment-types.js +20 -0
  121. package/dist/src/skills/exporter.js +8 -31
  122. package/dist/src/skills/provider-extensions.js +41 -0
  123. package/dist/src/skills/run.js +6 -0
  124. package/dist/src/skills/types.js +0 -8
  125. package/dist/src/skills/validator-resources.js +68 -0
  126. package/dist/src/skills/validator.js +6 -55
  127. package/dist/src/storage/cli-migrate-options.js +125 -0
  128. package/dist/src/storage/cli-migrate.js +111 -0
  129. package/dist/src/storage/cli.js +4 -279
  130. package/dist/src/storage/migration-adapter.js +79 -0
  131. package/dist/src/storage/migration-copy.js +108 -0
  132. package/dist/src/storage/migration-protocol.js +14 -197
  133. package/dist/src/storage/migration-records.js +186 -0
  134. package/dist/src/storage/migration-types.js +12 -0
  135. package/dist/src/tracker/forge-http.js +2 -1
  136. package/dist/src/tracker/issue-pages.js +110 -0
  137. package/package.json +7 -1
  138. package/schemas/mission-v1.schema.json +335 -0
  139. package/schemas/models/model-catalog.v1.schema.json +19 -1
  140. package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
  141. package/schemas/models/model-policy.v1.schema.json +1 -1
  142. package/tools/agents/providers/provider-paths-staging.mjs +35 -0
  143. package/tools/agents/providers/rule-binding-targets.mjs +146 -0
  144. package/tools/agents/providers/rule-delivery.mjs +7 -126
  145. package/tools/ralph-external/lib/muse-adapter.mjs +10 -0
  146. package/tools/ralph-external/lib/worker-context.mjs +237 -0
  147. package/tools/ralph-external/lib/worker-invocation-ancestry.mjs +132 -0
  148. package/tools/ralph-external/lib/worker-invocation-processes.mjs +123 -0
  149. package/tools/ralph-external/lib/worker-isolation-status.mjs +48 -0
  150. package/tools/ralph-external/lib/worker-isolation.mjs +17 -29
  151. package/tools/ralph-external/lib/worker-launch-cli.mjs +3 -1
  152. package/tools/ralph-external/lib/worker-overflow.mjs +48 -13
  153. package/tools/ralph-external/lib/worker-retry-evidence.mjs +103 -0
  154. package/tools/ralph-external/lib/worker-termination.mjs +82 -0
  155. package/tools/ralph-external/session-launcher.mjs +51 -96
  156. package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
@@ -1,9 +1,8 @@
1
- import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, schemaIssueDetail, assertSessionResourceLimit, } from './contracts.js';
1
+ import { SESSION_CONTRACT_VERSION, assertSupportedSchemaMajor, sha256, SessionContractError, schemaIssueDetail, assertSessionResourceLimit, } from './contracts.js';
2
2
  import { assertImportByteLimit, DEFAULT_IMPORT_BYTE_LIMITS, resolveImportLimits } from './import-limits.js';
3
- import { redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
3
+ import { redactSessionValue, sanitizeNativeExtensions } from './policy.js';
4
4
  import { fingerprintSourcePrefix } from './readers.js';
5
- import { DEFAULT_INACTIVITY_THRESHOLD_MS } from './lifecycle.js';
6
- import { classifySessionEventOrigin, deriveSessionIntent, } from './origin.js';
5
+ import { normalizeSessionBatch, sourceGenerationDigest } from './normalization.js';
7
6
  export const DEFAULT_IMPORT_LIMITS = {
8
7
  maxRecords: 1_000_000,
9
8
  ...DEFAULT_IMPORT_BYTE_LIMITS,
@@ -99,7 +98,7 @@ export class IncrementalSessionImporter {
99
98
  batchStart, checkpoint.recordsRead,
100
99
  ...batchDigests,
101
100
  ].join('\0'));
102
- const normalized = normalizeBatch(request, batch, batchDigests, runId, sourceObservedAt);
101
+ const normalized = normalizeSessionBatch(request, batch, batchDigests, runId, sourceObservedAt);
103
102
  const run = {
104
103
  contractVersion: SESSION_CONTRACT_VERSION,
105
104
  importRunId: runId,
@@ -123,6 +122,7 @@ export class IncrementalSessionImporter {
123
122
  source: sanitizedSource, run,
124
123
  sessions: normalized.sessions, events: normalized.events,
125
124
  batchRunId: request.batchRunId,
125
+ imageBlobs: normalized.imageBlobs,
126
126
  }, { ...checkpoint }, request.publish ?? request.source.consistency !== 'complete');
127
127
  const memory = process.memoryUsage();
128
128
  peakHeap = Math.max(peakHeap, memory.heapUsed);
@@ -176,7 +176,10 @@ export class IncrementalSessionImporter {
176
176
  }
177
177
  else {
178
178
  checkpoint.bytesRead += bytes;
179
- checkpoint.cursor = String(checkpoint.recordsRead);
179
+ // Older Pi adapters exposed bare byte counts without a byte: tag;
180
+ // those checkpoints historically counted records instead.
181
+ checkpoint.cursor = request.adapter.provider === 'pi' ? String(checkpoint.recordsRead)
182
+ : record.sourceCursor ?? String(checkpoint.recordsRead);
180
183
  }
181
184
  if (batch.length >= limits.batchSize)
182
185
  flush();
@@ -230,232 +233,6 @@ function recordIdentity(record) {
230
233
  const serialized = JSON.stringify(record);
231
234
  return { bytes: Buffer.byteLength(serialized), digest: sha256(serialized) };
232
235
  }
233
- function normalizeBatch(request, records, digests, importRunId, sourceObservedAt) {
234
- const sessions = new Map();
235
- const events = records.map((record, index) => {
236
- const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
237
- const native = sanitizeNativeExtensions(record.extensions ?? {});
238
- const lineage = request.source.provider === 'codex' && native.value.lineage
239
- ? { lineage: native.value.lineage } : {};
240
- const digest = digests[index];
241
- const origin = classifySessionEventOrigin(request.source.provider, record);
242
- const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
243
- const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
244
- const extensions = {
245
- [`native.${request.source.provider}`]: record.extensions ?? {},
246
- };
247
- const event = sanitizeSessionEvent(SessionEventSchema.parse({
248
- contractVersion: SESSION_CONTRACT_VERSION,
249
- eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
250
- sessionId, sourceId: request.source.sourceId, importRunId,
251
- nativeId: record.nativeEventId ?? null, sequence: record.sequence,
252
- kind: record.kind, role: record.role ?? null, occurredAt: record.occurredAt ?? null,
253
- activityBoundary: record.activityBoundary ?? null,
254
- activityBoundaryBasis: record.activityBoundaryBasis ?? null,
255
- activityBoundaryConfidence: record.activityBoundaryConfidence ?? null,
256
- origin: origin.origin,
257
- originRule: origin.rule,
258
- originClassifierVersion: origin.classifierVersion,
259
- participant: record.participant ?? null,
260
- toolName: record.toolName ?? null,
261
- toolCallId: record.toolCallId ?? null,
262
- model: record.model ?? null,
263
- entities: record.entities ?? [],
264
- extractionState: record.extractionState ?? null,
265
- searchableText: record.text, digest, rawReference: record.rawReference,
266
- adapterVersion: request.adapter.adapterVersion,
267
- consistency: request.source.consistency,
268
- sensitivity: { classification: 'none', classes: [] },
269
- opaque: !isKnownEventKind(record.kind),
270
- extensions,
271
- }));
272
- if (!sessions.has(sessionId)) {
273
- sessions.set(sessionId, SessionSchema.parse({
274
- contractVersion: SESSION_CONTRACT_VERSION,
275
- sessionId, sourceId: request.source.sourceId, provider: request.source.provider,
276
- nativeSessionId: record.nativeSessionId, workspaceId: request.workspaceId,
277
- startedAt: record.occurredAt ?? null, updatedAt: record.occurredAt ?? null,
278
- consistency: request.source.consistency,
279
- lifecycle,
280
- sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
281
- extensions: {
282
- [`native.${request.source.provider}`]: {
283
- ...lineage,
284
- lifecycleEvidence,
285
- },
286
- },
287
- }));
288
- }
289
- else {
290
- const session = sessions.get(sessionId);
291
- session.startedAt = earlierTimestamp(session.startedAt, record.occurredAt ?? null);
292
- session.updatedAt = laterTimestamp(session.updatedAt, record.occurredAt ?? null);
293
- session.consistency = strongerConsistency(session.consistency, request.source.consistency);
294
- const nativeKey = `native.${request.source.provider}`;
295
- const nativeEnvelope = session.extensions[nativeKey];
296
- const nativeRecord = nativeEnvelope && typeof nativeEnvelope === 'object' && !Array.isArray(nativeEnvelope)
297
- ? nativeEnvelope
298
- : {};
299
- const selected = selectLifecycleTransition(session.lifecycle, nativeRecord.lifecycleEvidence, lifecycle, lifecycleEvidence);
300
- session.lifecycle = selected.lifecycle;
301
- session.extensions[nativeKey] = {
302
- ...nativeRecord,
303
- ...lineage,
304
- lifecycleEvidence: selected.evidence,
305
- };
306
- }
307
- return event;
308
- });
309
- for (const session of sessions.values()) {
310
- session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
311
- }
312
- return { sessions: redactSessionValue([...sessions.values()]).value, events };
313
- }
314
- const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
315
- function isKnownEventKind(kind) {
316
- const normalized = kind.toLowerCase();
317
- return KNOWN_EVENT_KINDS.has(normalized)
318
- || /^(?:tool-call|tool-result)(?:[._-]|$)/.test(normalized)
319
- || /^(?:sandbox|permission|approval|hitl|human|lifecycle)(?:[._-]|$)/.test(normalized);
320
- }
321
- function earlierTimestamp(left, right) {
322
- if (!left)
323
- return right;
324
- if (!right)
325
- return left;
326
- return Date.parse(left) <= Date.parse(right) ? left : right;
327
- }
328
- function laterTimestamp(left, right) {
329
- if (!left)
330
- return right;
331
- if (!right)
332
- return left;
333
- return Date.parse(left) >= Date.parse(right) ? left : right;
334
- }
335
- function strongerConsistency(left, right) {
336
- const rank = {
337
- provisional: 0,
338
- 'consistent-snapshot': 1,
339
- complete: 2,
340
- };
341
- return rank[left] >= rank[right] ? left : right;
342
- }
343
- function sessionLifecycle(request, record, sourceObservedAt) {
344
- const explicit = nativeLifecycle(record.extensions);
345
- if (explicit)
346
- return explicit;
347
- if (request.source.consistency === 'complete')
348
- return 'complete';
349
- const observedAt = record.occurredAt ?? sourceObservedAt;
350
- if (observedAt && isStaleHistoricalTimestamp(observedAt, inactivityThresholdMs(request)))
351
- return 'inactive';
352
- return 'active';
353
- }
354
- function sessionLifecycleEvidence(request, record, sourceObservedAt) {
355
- const observedAt = record.occurredAt ?? sourceObservedAt;
356
- const explicit = nativeLifecycle(record.extensions);
357
- if (explicit) {
358
- return {
359
- basis: 'provider-explicit-event',
360
- state: explicit,
361
- observedAt: observedAt ?? request.source.authorizedAt,
362
- confidence: 'high',
363
- };
364
- }
365
- if (request.source.consistency === 'complete') {
366
- return {
367
- basis: 'complete-source',
368
- state: 'complete',
369
- observedAt: observedAt ?? request.source.authorizedAt,
370
- confidence: 'high',
371
- };
372
- }
373
- const thresholdMs = inactivityThresholdMs(request);
374
- if (observedAt && isStaleHistoricalTimestamp(observedAt, thresholdMs)) {
375
- return {
376
- basis: 'inactivity-threshold',
377
- state: 'inactive',
378
- observedAt,
379
- confidence: 'medium',
380
- thresholdMs,
381
- };
382
- }
383
- return {
384
- basis: 'open-provisional-source',
385
- state: 'active',
386
- observedAt: observedAt ?? request.source.authorizedAt,
387
- confidence: 'provisional',
388
- thresholdMs,
389
- };
390
- }
391
- function nativeLifecycle(extensions) {
392
- const raw = typeof extensions?.lifecycle === 'string' ? extensions.lifecycle : undefined;
393
- if (!raw)
394
- return null;
395
- const normalized = {
396
- active: 'active',
397
- inactive: 'inactive',
398
- paused: 'paused',
399
- complete: 'complete',
400
- completed: 'complete',
401
- archived: 'archived',
402
- deleted: 'tombstoned',
403
- cancelled: 'interrupted',
404
- canceled: 'interrupted',
405
- failed: 'interrupted',
406
- interrupted: 'interrupted',
407
- unknown: 'unknown',
408
- 'unknown-at-import': 'unknown',
409
- 'completed-at-import': 'complete',
410
- };
411
- return normalized[raw] ?? null;
412
- }
413
- function selectLifecycleTransition(leftLifecycle, left, rightLifecycle, right) {
414
- const leftEvidence = asLifecycleEvidence(left);
415
- if (leftLifecycle === 'tombstoned') {
416
- return { lifecycle: leftLifecycle, evidence: leftEvidence ?? right };
417
- }
418
- if (!leftEvidence)
419
- return { lifecycle: rightLifecycle, evidence: right };
420
- const rank = {
421
- 'open-provisional-source': 1,
422
- 'inactivity-threshold': 1,
423
- 'complete-source': 2,
424
- 'provider-explicit-event': 3,
425
- };
426
- const leftRank = rank[String(leftEvidence.basis)] ?? 0;
427
- const rightRank = rank[String(right.basis)] ?? 0;
428
- const rightIsNewer = evidenceTimestamp(right) > evidenceTimestamp(leftEvidence);
429
- return rightRank > leftRank || (rightRank === leftRank && rightIsNewer)
430
- ? { lifecycle: rightLifecycle, evidence: right }
431
- : { lifecycle: leftLifecycle, evidence: leftEvidence };
432
- }
433
- function asLifecycleEvidence(value) {
434
- return value !== null && typeof value === 'object' && !Array.isArray(value)
435
- ? value
436
- : null;
437
- }
438
- function evidenceTimestamp(value) {
439
- const parsed = Date.parse(String(value.observedAt ?? ''));
440
- return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
441
- }
442
- function inactivityThresholdMs(request) {
443
- return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
444
- }
445
- function isStaleHistoricalTimestamp(value, thresholdMs) {
446
- const timestamp = Date.parse(value);
447
- return Number.isFinite(timestamp)
448
- && Date.now() - timestamp > thresholdMs;
449
- }
450
- function sourceGenerationDigest(request) {
451
- return sha256([
452
- request.source.sourceId,
453
- request.source.provider,
454
- request.selectedSource.locatorClass,
455
- request.source.sourceSchemaVersion,
456
- request.adapter.adapterVersion,
457
- ].join('\0'));
458
- }
459
236
  async function sourceContinuity(request, previous) {
460
237
  if (request.selectedSource.authorizedScope.allowedRoots.length === 0
461
238
  || /^[a-z][a-z0-9+.-]*:\/\//i.test(request.selectedSource.locator)
@@ -1,4 +1,5 @@
1
1
  export * from './contracts.js';
2
+ export * from './image-blobs.js';
2
3
  export * from './fixtures.js';
3
4
  export * from './policy.js';
4
5
  export * from './discovery.js';
@@ -19,6 +20,8 @@ export * from './importer.js';
19
20
  export * from './import-lease.js';
20
21
  export * from './batch-contracts.js';
21
22
  export * from './batch-import.js';
23
+ export * from './intake-dir.js';
24
+ export * from './host-catalog.js';
22
25
  export * from './workspace-discovery.js';
23
26
  export * from './timeline.js';
24
27
  export * from './origin.js';
@@ -30,11 +33,13 @@ export * from './adapters/copilot.js';
30
33
  export * from './adapters/cursor.js';
31
34
  export * from './adapters/factory.js';
32
35
  export * from './adapters/hermes.js';
36
+ export * from './adapters/hermes-state-db.js';
33
37
  export * from './adapters/opencode.js';
34
38
  export * from './adapters/openclaw.js';
35
39
  export * from './adapters/openhuman.js';
36
40
  export * from './adapters/grokbot.js';
37
41
  export * from './adapters/grok-build.js';
42
+ export * from './adapters/grok-build-native.js';
38
43
  export * from './grok-build-cli.js';
39
44
  export * from './adapters/pi.js';
40
45
  export * from './adapters/deepseek-harness.js';
@@ -44,4 +49,5 @@ export * from './adapters/muse.js';
44
49
  export * from './adapters/omp.js';
45
50
  export * from './adapter-registry.js';
46
51
  export * from './coverage-preflight.js';
52
+ export * from './discovery-capability.js';
47
53
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,71 @@
1
+ // Intake-directory batch import for `sessions import --from-dir` (#3168).
2
+ import { readdir } from 'node:fs/promises';
3
+ import { SessionContractError } from './contracts.js';
4
+ export const INTAKE_DIR_SCHEMA_VERSION = '1.0.0';
5
+ /** Recognised intake files are provider export payloads, never control files. */
6
+ export function isRecognisedIntakeFile(provider, filename) {
7
+ if (filename.startsWith('.')) {
8
+ return { recognised: false, reason: `skipped dotfile ${JSON.stringify(filename)}` };
9
+ }
10
+ if (provider === 'claude') {
11
+ if (filename.endsWith('.json') || filename.endsWith('.jsonl'))
12
+ return { recognised: true };
13
+ return {
14
+ recognised: false,
15
+ reason: 'unrecognised extension for provider claude:'
16
+ + ` expected .json (web/account export) or .jsonl (transcript/hook), got ${JSON.stringify(filename)}`,
17
+ };
18
+ }
19
+ if (filename.endsWith('.json') || filename.endsWith('.jsonl'))
20
+ return { recognised: true };
21
+ return {
22
+ recognised: false,
23
+ reason: `unrecognised extension for provider ${provider}:`
24
+ + ` expected .json or .jsonl, got ${JSON.stringify(filename)}`,
25
+ };
26
+ }
27
+ /** Stable per-file source identity: an optional prefix plus the file basename. */
28
+ export function intakeSourceId(prefix, filename) {
29
+ const base = filename.replace(/[^A-Za-z0-9._-]+/g, '_');
30
+ return prefix ? `${prefix}/${base}` : base;
31
+ }
32
+ /** Sorted basenames of regular files directly inside the intake directory. */
33
+ export async function listIntakeDirFiles(dir) {
34
+ let entries;
35
+ try {
36
+ entries = await readdir(dir, { withFileTypes: true });
37
+ }
38
+ catch {
39
+ throw new SessionContractError('INVALID_ARGUMENT', `intake directory is not readable: ${dir}`);
40
+ }
41
+ return entries
42
+ .filter((entry) => entry.isFile())
43
+ .map((entry) => entry.name)
44
+ .sort();
45
+ }
46
+ /** Content-free roll-up over one receipt per intake file. */
47
+ export function summarizeIntakeReceipts(files) {
48
+ const summary = {
49
+ total: files.length,
50
+ imported: 0,
51
+ alreadyImported: 0,
52
+ skipped: 0,
53
+ rejected: 0,
54
+ sessionsInserted: 0,
55
+ eventsInserted: 0,
56
+ };
57
+ for (const file of files) {
58
+ if (file.status === 'imported')
59
+ summary.imported += 1;
60
+ else if (file.status === 'already-imported')
61
+ summary.alreadyImported += 1;
62
+ else if (file.status === 'skipped')
63
+ summary.skipped += 1;
64
+ else
65
+ summary.rejected += 1;
66
+ summary.sessionsInserted += file.sessionsInserted;
67
+ summary.eventsInserted += file.eventsInserted;
68
+ }
69
+ return summary;
70
+ }
71
+ //# sourceMappingURL=intake-dir.js.map
@@ -0,0 +1,251 @@
1
+ // Shared event normalization, image extraction, redaction, and lifecycle derivation.
2
+ import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, sha256, stableEventId, stableSessionId, } from './contracts.js';
3
+ import { redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
4
+ import { extractEventImages } from './image-blobs.js';
5
+ import { DEFAULT_INACTIVITY_THRESHOLD_MS } from './lifecycle.js';
6
+ import { classifySessionEventOrigin, deriveSessionIntent } from './origin.js';
7
+ export function normalizeSessionBatch(request, records, digests, importRunId, sourceObservedAt) {
8
+ const sessions = new Map();
9
+ // Extract inline images before sanitization: provider image blocks in
10
+ // extensions are redacted to markers below, so bytes must be lifted out
11
+ // first while the raw record is still intact (#3265).
12
+ const imageBlobs = new Map();
13
+ const events = records.map((record, index) => {
14
+ const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
15
+ const native = sanitizeNativeExtensions(record.extensions ?? {});
16
+ const lineage = request.source.provider === 'codex' && native.value.lineage
17
+ ? { lineage: native.value.lineage } : {};
18
+ const images = extractEventImages({
19
+ searchableText: record.text,
20
+ extensions: record.extensions,
21
+ rawReference: record.rawReference,
22
+ });
23
+ for (const image of images.images) {
24
+ if (!imageBlobs.has(image.digest))
25
+ imageBlobs.set(image.digest, image);
26
+ }
27
+ const digest = digests[index];
28
+ const origin = classifySessionEventOrigin(request.source.provider, record);
29
+ const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
30
+ const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
31
+ const extensions = {
32
+ [`native.${request.source.provider}`]: images.extensions,
33
+ };
34
+ const event = sanitizeSessionEvent(SessionEventSchema.parse({
35
+ contractVersion: SESSION_CONTRACT_VERSION,
36
+ eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
37
+ sessionId, sourceId: request.source.sourceId, importRunId,
38
+ nativeId: record.nativeEventId ?? null, sequence: record.sequence,
39
+ kind: record.kind, role: record.role ?? null, occurredAt: record.occurredAt ?? null,
40
+ activityBoundary: record.activityBoundary ?? null,
41
+ activityBoundaryBasis: record.activityBoundaryBasis ?? null,
42
+ activityBoundaryConfidence: record.activityBoundaryConfidence ?? null,
43
+ origin: origin.origin,
44
+ originRule: origin.rule,
45
+ originClassifierVersion: origin.classifierVersion,
46
+ participant: record.participant ?? null,
47
+ toolName: record.toolName ?? null,
48
+ toolCallId: record.toolCallId ?? null,
49
+ model: record.model ?? null,
50
+ entities: record.entities ?? [],
51
+ extractionState: record.extractionState ?? null,
52
+ searchableText: images.searchableText, imageRefs: images.imageRefs,
53
+ digest, rawReference: record.rawReference,
54
+ adapterVersion: request.adapter.adapterVersion,
55
+ consistency: request.source.consistency,
56
+ sensitivity: { classification: 'none', classes: [] },
57
+ opaque: !isKnownEventKind(record.kind),
58
+ extensions,
59
+ }));
60
+ if (!sessions.has(sessionId)) {
61
+ sessions.set(sessionId, SessionSchema.parse({
62
+ contractVersion: SESSION_CONTRACT_VERSION,
63
+ sessionId, sourceId: request.source.sourceId, provider: request.source.provider,
64
+ nativeSessionId: record.nativeSessionId, workspaceId: request.workspaceId,
65
+ startedAt: record.occurredAt ?? null, updatedAt: record.occurredAt ?? null,
66
+ consistency: request.source.consistency,
67
+ lifecycle,
68
+ sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
69
+ extensions: {
70
+ [`native.${request.source.provider}`]: {
71
+ ...lineage,
72
+ lifecycleEvidence,
73
+ },
74
+ },
75
+ }));
76
+ }
77
+ else {
78
+ const session = sessions.get(sessionId);
79
+ session.startedAt = earlierTimestamp(session.startedAt, record.occurredAt ?? null);
80
+ session.updatedAt = laterTimestamp(session.updatedAt, record.occurredAt ?? null);
81
+ session.consistency = strongerConsistency(session.consistency, request.source.consistency);
82
+ const nativeKey = `native.${request.source.provider}`;
83
+ const nativeEnvelope = session.extensions[nativeKey];
84
+ const nativeRecord = nativeEnvelope && typeof nativeEnvelope === 'object' && !Array.isArray(nativeEnvelope)
85
+ ? nativeEnvelope
86
+ : {};
87
+ const selected = selectLifecycleTransition(session.lifecycle, nativeRecord.lifecycleEvidence, lifecycle, lifecycleEvidence);
88
+ session.lifecycle = selected.lifecycle;
89
+ session.extensions[nativeKey] = {
90
+ ...nativeRecord,
91
+ ...lineage,
92
+ lifecycleEvidence: selected.evidence,
93
+ };
94
+ }
95
+ return event;
96
+ });
97
+ for (const session of sessions.values()) {
98
+ session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
99
+ }
100
+ return {
101
+ sessions: redactSessionValue([...sessions.values()]).value,
102
+ events,
103
+ imageBlobs: [...imageBlobs.values()],
104
+ };
105
+ }
106
+ const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
107
+ function isKnownEventKind(kind) {
108
+ const normalized = kind.toLowerCase();
109
+ return KNOWN_EVENT_KINDS.has(normalized)
110
+ || /^(?:tool-call|tool-result)(?:[._-]|$)/.test(normalized)
111
+ || /^(?:sandbox|permission|approval|hitl|human|lifecycle)(?:[._-]|$)/.test(normalized);
112
+ }
113
+ function earlierTimestamp(left, right) {
114
+ if (!left)
115
+ return right;
116
+ if (!right)
117
+ return left;
118
+ return Date.parse(left) <= Date.parse(right) ? left : right;
119
+ }
120
+ function laterTimestamp(left, right) {
121
+ if (!left)
122
+ return right;
123
+ if (!right)
124
+ return left;
125
+ return Date.parse(left) >= Date.parse(right) ? left : right;
126
+ }
127
+ function strongerConsistency(left, right) {
128
+ const rank = {
129
+ provisional: 0,
130
+ 'consistent-snapshot': 1,
131
+ complete: 2,
132
+ };
133
+ return rank[left] >= rank[right] ? left : right;
134
+ }
135
+ function sessionLifecycle(request, record, sourceObservedAt) {
136
+ const explicit = nativeLifecycle(record.extensions);
137
+ if (explicit)
138
+ return explicit;
139
+ if (request.source.consistency === 'complete')
140
+ return 'complete';
141
+ const observedAt = record.occurredAt ?? sourceObservedAt;
142
+ if (observedAt && isStaleHistoricalTimestamp(observedAt, inactivityThresholdMs(request)))
143
+ return 'inactive';
144
+ return 'active';
145
+ }
146
+ function sessionLifecycleEvidence(request, record, sourceObservedAt) {
147
+ const observedAt = record.occurredAt ?? sourceObservedAt;
148
+ const explicit = nativeLifecycle(record.extensions);
149
+ if (explicit) {
150
+ return {
151
+ basis: 'provider-explicit-event',
152
+ state: explicit,
153
+ observedAt: observedAt ?? request.source.authorizedAt,
154
+ confidence: 'high',
155
+ };
156
+ }
157
+ if (request.source.consistency === 'complete') {
158
+ return {
159
+ basis: 'complete-source',
160
+ state: 'complete',
161
+ observedAt: observedAt ?? request.source.authorizedAt,
162
+ confidence: 'high',
163
+ };
164
+ }
165
+ const thresholdMs = inactivityThresholdMs(request);
166
+ if (observedAt && isStaleHistoricalTimestamp(observedAt, thresholdMs)) {
167
+ return {
168
+ basis: 'inactivity-threshold',
169
+ state: 'inactive',
170
+ observedAt,
171
+ confidence: 'medium',
172
+ thresholdMs,
173
+ };
174
+ }
175
+ return {
176
+ basis: 'open-provisional-source',
177
+ state: 'active',
178
+ observedAt: observedAt ?? request.source.authorizedAt,
179
+ confidence: 'provisional',
180
+ thresholdMs,
181
+ };
182
+ }
183
+ function nativeLifecycle(extensions) {
184
+ const raw = typeof extensions?.lifecycle === 'string' ? extensions.lifecycle : undefined;
185
+ if (!raw)
186
+ return null;
187
+ const normalized = {
188
+ active: 'active',
189
+ inactive: 'inactive',
190
+ paused: 'paused',
191
+ complete: 'complete',
192
+ completed: 'complete',
193
+ archived: 'archived',
194
+ deleted: 'tombstoned',
195
+ cancelled: 'interrupted',
196
+ canceled: 'interrupted',
197
+ failed: 'interrupted',
198
+ interrupted: 'interrupted',
199
+ unknown: 'unknown',
200
+ 'unknown-at-import': 'unknown',
201
+ 'completed-at-import': 'complete',
202
+ };
203
+ return normalized[raw] ?? null;
204
+ }
205
+ function selectLifecycleTransition(leftLifecycle, left, rightLifecycle, right) {
206
+ const leftEvidence = asLifecycleEvidence(left);
207
+ if (leftLifecycle === 'tombstoned') {
208
+ return { lifecycle: leftLifecycle, evidence: leftEvidence ?? right };
209
+ }
210
+ if (!leftEvidence)
211
+ return { lifecycle: rightLifecycle, evidence: right };
212
+ const rank = {
213
+ 'open-provisional-source': 1,
214
+ 'inactivity-threshold': 1,
215
+ 'complete-source': 2,
216
+ 'provider-explicit-event': 3,
217
+ };
218
+ const leftRank = rank[String(leftEvidence.basis)] ?? 0;
219
+ const rightRank = rank[String(right.basis)] ?? 0;
220
+ const rightIsNewer = evidenceTimestamp(right) > evidenceTimestamp(leftEvidence);
221
+ return rightRank > leftRank || (rightRank === leftRank && rightIsNewer)
222
+ ? { lifecycle: rightLifecycle, evidence: right }
223
+ : { lifecycle: leftLifecycle, evidence: leftEvidence };
224
+ }
225
+ function asLifecycleEvidence(value) {
226
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
227
+ ? value
228
+ : null;
229
+ }
230
+ function evidenceTimestamp(value) {
231
+ const parsed = Date.parse(String(value.observedAt ?? ''));
232
+ return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
233
+ }
234
+ function inactivityThresholdMs(request) {
235
+ return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
236
+ }
237
+ function isStaleHistoricalTimestamp(value, thresholdMs) {
238
+ const timestamp = Date.parse(value);
239
+ return Number.isFinite(timestamp)
240
+ && Date.now() - timestamp > thresholdMs;
241
+ }
242
+ export function sourceGenerationDigest(request) {
243
+ return sha256([
244
+ request.source.sourceId,
245
+ request.source.provider,
246
+ request.selectedSource.locatorClass,
247
+ request.source.sourceSchemaVersion,
248
+ request.adapter.adapterVersion,
249
+ ].join('\0'));
250
+ }
251
+ //# sourceMappingURL=normalization.js.map