@aiwg/cli 2026.10.11 → 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 (132) hide show
  1. package/agentic/code/providers/model-catalog.v1.json +62 -12
  2. package/dist/src/artifacts/binding-target-identity.js +51 -0
  3. package/dist/src/artifacts/checksum-manifest.js +12 -0
  4. package/dist/src/artifacts/index-builder.js +11 -13
  5. package/dist/src/artifacts/query-engine.js +5 -11
  6. package/dist/src/cli/handlers/doctor-help.js +32 -0
  7. package/dist/src/cli/handlers/gates.js +19 -18
  8. package/dist/src/cli/handlers/models-help.js +7 -1
  9. package/dist/src/cli/handlers/models.js +3 -3
  10. package/dist/src/cli/handlers/script-runner.js +8 -5
  11. package/dist/src/cli/handlers/sessions-intake.js +104 -0
  12. package/dist/src/cli/handlers/sessions-tail.js +172 -0
  13. package/dist/src/cli/handlers/sessions.js +90 -17
  14. package/dist/src/cli/handlers/skill-lint.js +10 -3
  15. package/dist/src/cli/handlers/steward-format.js +100 -0
  16. package/dist/src/cli/handlers/steward-models.js +167 -0
  17. package/dist/src/cli/handlers/steward.js +14 -248
  18. package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
  19. package/dist/src/cli/handlers/use.js +6 -24
  20. package/dist/src/cli/handlers/utilities.js +1 -24
  21. package/dist/src/config/aiwg-config.js +7 -0
  22. package/dist/src/config/authorization-cli.js +89 -0
  23. package/dist/src/config/cli-help.js +1 -0
  24. package/dist/src/config/cli.js +10 -1
  25. package/dist/src/decision/context-pruning.js +3 -2
  26. package/dist/src/decision/ensemble/contract.js +15 -4
  27. package/dist/src/decision/ensemble-study/artifacts.js +5 -0
  28. package/dist/src/decision/ensemble-study/score.js +4 -3
  29. package/dist/src/decision/feature-export.js +3 -9
  30. package/dist/src/decision/heldout/collector.js +2 -2
  31. package/dist/src/decision/issue-triage/runtime.js +3 -9
  32. package/dist/src/decision/qualification/gates.js +2 -1
  33. package/dist/src/decision/qualification/release.js +2 -3
  34. package/dist/src/decision/routing/report.js +2 -0
  35. package/dist/src/decision/sdlc-screening.js +3 -5
  36. package/dist/src/decision/sensitivity/comparative.js +5 -3
  37. package/dist/src/gates/driver.js +6 -77
  38. package/dist/src/gates/evaluate.js +4 -11
  39. package/dist/src/gates/floors.js +4 -4
  40. package/dist/src/gates/index.js +3 -3
  41. package/dist/src/gates/lattice.js +26 -0
  42. package/dist/src/gates/registry.js +2 -1
  43. package/dist/src/gates/report.js +19 -7
  44. package/dist/src/issues/audit-cli.js +120 -0
  45. package/dist/src/issues/audit-contract.js +64 -0
  46. package/dist/src/issues/audit-local.js +82 -0
  47. package/dist/src/issues/audit.js +220 -0
  48. package/dist/src/lint/rule-activation.js +15 -1
  49. package/dist/src/mission-protocol/canonical-codecs.js +270 -0
  50. package/dist/src/mission-protocol/codecs.js +22 -550
  51. package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
  52. package/dist/src/mission-protocol/health-trace-types.js +43 -0
  53. package/dist/src/mission-protocol/types.js +2 -42
  54. package/dist/src/mission-protocol/worker-contract-json.js +10 -0
  55. package/dist/src/mission-protocol/worker-review-gate.js +100 -0
  56. package/dist/src/mission-protocol/worker-review-types.js +2 -0
  57. package/dist/src/models/catalog-policy.js +280 -0
  58. package/dist/src/models/index.js +1 -1
  59. package/dist/src/models/model-catalog.v1.json +62 -12
  60. package/dist/src/models/policy-resources.js +28 -0
  61. package/dist/src/models/provider-policy.js +10 -546
  62. package/dist/src/models/resolver.js +26 -8
  63. package/dist/src/models/router.js +15 -2
  64. package/dist/src/models/tiers.js +13 -0
  65. package/dist/src/models/types.js +0 -6
  66. package/dist/src/models/worker-ceilings.js +59 -0
  67. package/dist/src/models/worker-invocation-policy.js +243 -0
  68. package/dist/src/models/worker-plan.js +16 -20
  69. package/dist/src/models/worker-review-lineage.js +55 -0
  70. package/dist/src/models/worker-selection-policy.js +1 -1
  71. package/dist/src/models/wrapper-route.js +6 -3
  72. package/dist/src/policy/authorization.js +1 -0
  73. package/dist/src/policy/hitl-config.js +63 -0
  74. package/dist/src/policy/hitl-receipt.js +57 -0
  75. package/dist/src/policy/hitl-types.js +4 -0
  76. package/dist/src/policy/hitl-validation.js +39 -0
  77. package/dist/src/policy/hitl.js +117 -0
  78. package/dist/src/rules/activation.d.mts +1 -1
  79. package/dist/src/rules/activation.mjs +0 -2
  80. package/dist/src/rules/gate-coverage.js +51 -0
  81. package/dist/src/rules/gate-references.js +16 -0
  82. package/dist/src/rules/rule-frontmatter.schema.json +7 -1
  83. package/dist/src/serve/worker-command-request.js +21 -4
  84. package/dist/src/serve/worker-invocation-preparation.js +3 -1
  85. package/dist/src/serve/worker-invocation.js +21 -10
  86. package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
  87. package/dist/src/sessions/adapters/grok-build-native.js +269 -0
  88. package/dist/src/sessions/adapters/grok-build.js +57 -15
  89. package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
  90. package/dist/src/sessions/adapters/hermes.js +42 -3
  91. package/dist/src/sessions/adapters/warp.js +1 -1
  92. package/dist/src/sessions/batch-import.js +10 -0
  93. package/dist/src/sessions/contracts.js +1 -1
  94. package/dist/src/sessions/discovery-capability.js +38 -0
  95. package/dist/src/sessions/importer.js +8 -251
  96. package/dist/src/sessions/index.js +4 -0
  97. package/dist/src/sessions/intake-dir.js +71 -0
  98. package/dist/src/sessions/normalization.js +251 -0
  99. package/dist/src/sessions/tail.js +91 -0
  100. package/dist/src/sessions/workspace-discovery.js +83 -7
  101. package/dist/src/skills/agent-skill-sidecar.js +28 -0
  102. package/dist/src/skills/agent-skills.js +4 -23
  103. package/dist/src/skills/claude-surface-projection.js +25 -0
  104. package/dist/src/skills/deployer.js +8 -288
  105. package/dist/src/skills/deployment-policy.js +114 -0
  106. package/dist/src/skills/deployment-projection.js +152 -0
  107. package/dist/src/skills/deployment-types.js +20 -0
  108. package/dist/src/skills/exporter.js +8 -31
  109. package/dist/src/skills/provider-extensions.js +41 -0
  110. package/dist/src/skills/run.js +6 -0
  111. package/dist/src/skills/types.js +0 -8
  112. package/dist/src/skills/validator-resources.js +68 -0
  113. package/dist/src/skills/validator.js +6 -55
  114. package/dist/src/storage/cli-migrate-options.js +125 -0
  115. package/dist/src/storage/cli-migrate.js +111 -0
  116. package/dist/src/storage/cli.js +4 -279
  117. package/dist/src/storage/migration-adapter.js +79 -0
  118. package/dist/src/storage/migration-copy.js +108 -0
  119. package/dist/src/storage/migration-protocol.js +14 -197
  120. package/dist/src/storage/migration-records.js +186 -0
  121. package/dist/src/storage/migration-types.js +12 -0
  122. package/dist/src/tracker/forge-http.js +2 -1
  123. package/dist/src/tracker/issue-pages.js +110 -0
  124. package/package.json +1 -1
  125. package/schemas/mission-v1.schema.json +335 -0
  126. package/schemas/models/model-catalog.v1.schema.json +19 -1
  127. package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
  128. package/schemas/models/model-policy.v1.schema.json +1 -1
  129. package/tools/agents/providers/provider-paths-staging.mjs +35 -0
  130. package/tools/agents/providers/rule-binding-targets.mjs +146 -0
  131. package/tools/agents/providers/rule-delivery.mjs +7 -126
  132. package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
@@ -1,7 +1,10 @@
1
+ import { lstat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
1
3
  import { z } from 'zod';
2
4
  import { number } from '../../schema/zod-validation.mjs';
3
5
  import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
4
6
  import { streamBoundedJsonLines, } from '../readers.js';
7
+ import { HERMES_SNAPSHOT_LOCATOR_CLASS, HERMES_STATE_DB_FILENAME, hermesSnapshotStagingDir, snapshotHermesStateDb, } from './hermes-state-db.js';
5
8
  export const HERMES_ADAPTER_VERSION = '1.0.0';
6
9
  export const HERMES_EXPORT_SCHEMA_VERSION = '1.0.0';
7
10
  export const HERMES_NATIVE_SCHEMA_VERSION = '23.0.0';
@@ -64,14 +67,42 @@ export class HermesSessionAdapter {
64
67
  provider = 'hermes';
65
68
  adapterVersion = HERMES_ADAPTER_VERSION;
66
69
  disposition = 'implemented';
67
- supportedOperations = ['inspect', 'stream'];
70
+ supportedOperations = ['discover', 'inspect', 'stream'];
68
71
  acquisitionModes = ['jsonl', 'api', 'sqlite-snapshot'];
69
72
  constructor(limits, localApi) {
70
73
  this.limits = limits;
71
74
  this.localApi = localApi;
72
75
  }
73
- async *discover(_scope) {
74
- // Native exports and consistent snapshots require explicit selection.
76
+ /**
77
+ * Discover through a consistent `sqlite3.backup()` snapshot of the
78
+ * explicitly authorized `<root>/state.db`. The live database is never
79
+ * opened for writing and never streamed directly; matching sessions are
80
+ * projected to an owned staging snapshot the existing consistent-snapshot
81
+ * path already validates.
82
+ */
83
+ async *discover(scope) {
84
+ if (scope.allowedRoots.length === 0) {
85
+ throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Hermes discovery requires an explicitly authorized Hermes home; pass --hermes-root.');
86
+ }
87
+ const staging = hermesSnapshotStagingDir(scope.workspaceId);
88
+ for (const root of [...scope.allowedRoots].sort()) {
89
+ if (!(await isStateDbFile(join(root, HERMES_STATE_DB_FILENAME))))
90
+ continue;
91
+ const snapshot = await snapshotHermesStateDb({
92
+ hermesRoot: root,
93
+ stagingDir: staging,
94
+ allowedRoots: scope.allowedRoots,
95
+ workspaceId: scope.workspaceId,
96
+ limits: this.limits,
97
+ });
98
+ if (!snapshot)
99
+ continue;
100
+ yield {
101
+ provider: 'hermes',
102
+ locator: snapshot.projectionPath,
103
+ locatorClass: HERMES_SNAPSHOT_LOCATOR_CLASS,
104
+ };
105
+ }
75
106
  }
76
107
  async inspect(source) {
77
108
  if (source.locatorClass === 'hermes-export-jsonl'
@@ -284,6 +315,14 @@ function normalizeMessage(sessionId, message, index, line, locatorClass, common)
284
315
  }));
285
316
  return records;
286
317
  }
318
+ async function isStateDbFile(path) {
319
+ try {
320
+ return (await lstat(path)).isFile();
321
+ }
322
+ catch {
323
+ return false;
324
+ }
325
+ }
287
326
  function ended(value) {
288
327
  return Boolean(value.ended_at || value.provider_deleted_at || value.archived || value.inactive);
289
328
  }
@@ -50,7 +50,7 @@ export class WarpSessionAdapter {
50
50
  if (blocks.length === 0) {
51
51
  throw new SessionContractError('MALFORMED_SOURCE', 'Warp Markdown export contains no recognized user or assistant conversation blocks', schemaIssueDetail('headings'));
52
52
  }
53
- const stableSessionId = `manual:${createHash('sha256').update(value).digest('hex').slice(0, 32)}`;
53
+ const stableSessionId = source.nativeSessionId ?? `manual:${createHash('sha256').update(value).digest('hex').slice(0, 32)}`;
54
54
  const lifecycleEvidence = /<!--\s*warp-lifecycle:\s*complete\s*-->/i.test(value)
55
55
  ? 'completed-at-import' : 'unknown-at-import';
56
56
  const title = /^#\s+(.+)$/m.exec(value)?.[1]?.trim();
@@ -327,6 +327,16 @@ function providerProfile(provider, locatorClass) {
327
327
  return 'muse-native-session-log-v1';
328
328
  if (provider === 'grokbot')
329
329
  return 'grokbot-native-transcript-replica-v1';
330
+ if (provider === 'grok-build') {
331
+ return locatorClass === 'grok-build-native-chat-history'
332
+ ? 'grok-build-native-chat-history-v1'
333
+ : 'documented-cli-markdown-export';
334
+ }
335
+ if (provider === 'hermes') {
336
+ return locatorClass === 'hermes-consistent-snapshot-jsonl'
337
+ ? 'native-state-db-backup-snapshot-v1'
338
+ : 'native-schema-23-export';
339
+ }
330
340
  return 'manual-interchange';
331
341
  }
332
342
  function importErrorCode(error) {
@@ -76,7 +76,7 @@ export const SessionErrorCodeSchema = z.enum([
76
76
  'OPERATION_NOT_AUTHORIZED',
77
77
  'IMPORT_CONFLICT', 'IMPORT_INTERRUPTED', 'MALFORMED_SOURCE',
78
78
  'DUPLICATE_NATIVE_ID', 'AMBIGUOUS_TIMESTAMP', 'TRUNCATED_SOURCE',
79
- 'UNSUPPORTED_OPERATION',
79
+ 'UNSUPPORTED_OPERATION', 'UNSUPPORTED_PROVIDER',
80
80
  'INVALID_SEARCH_QUERY', 'INVALID_ARGUMENT',
81
81
  ]);
82
82
  const VersionSchema = z.string().regex(/^\d+\.\d+\.\d+(?:[-+].+)?$/);
@@ -0,0 +1,38 @@
1
+ const REQUIRED_FLAGS = {
2
+ claude: [],
3
+ codex: ['--codex-root'],
4
+ cursor: [],
5
+ factory: [],
6
+ pi: [],
7
+ omp: ['--omp-root'],
8
+ 'deepseek-harness': ['--dsh-root'],
9
+ muse: ['--muse-root'],
10
+ grokbot: ['--grokbot-root'],
11
+ 'grok-build': ['--grok-root'],
12
+ hermes: ['--hermes-root'],
13
+ };
14
+ const LIVE_DETECTION = {
15
+ 'grok-build': 'supported',
16
+ };
17
+ /**
18
+ * `discoverable` requires a wired `discover` operation on the loaded adapter,
19
+ * not merely an implemented ingest path; otherwise the provider stays
20
+ * `manual-export` (or `unsupported` when it has no ingest path at all).
21
+ */
22
+ export function providerDiscoveryCapability(provider, supportedOperations) {
23
+ if (supportedOperations.includes('discover')) {
24
+ return {
25
+ disposition: 'discoverable',
26
+ authorization: 'explicit-root',
27
+ requiredFlags: REQUIRED_FLAGS[provider] ?? [],
28
+ liveDetection: LIVE_DETECTION[provider] ?? 'unsupported',
29
+ };
30
+ }
31
+ return {
32
+ disposition: 'manual-export',
33
+ authorization: 'none',
34
+ requiredFlags: [],
35
+ liveDetection: 'unsupported',
36
+ };
37
+ }
38
+ //# sourceMappingURL=discovery-capability.js.map
@@ -1,10 +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';
4
- import { extractEventImages } from './image-blobs.js';
3
+ import { redactSessionValue, sanitizeNativeExtensions } from './policy.js';
5
4
  import { fingerprintSourcePrefix } from './readers.js';
6
- import { DEFAULT_INACTIVITY_THRESHOLD_MS } from './lifecycle.js';
7
- import { classifySessionEventOrigin, deriveSessionIntent, } from './origin.js';
5
+ import { normalizeSessionBatch, sourceGenerationDigest } from './normalization.js';
8
6
  export const DEFAULT_IMPORT_LIMITS = {
9
7
  maxRecords: 1_000_000,
10
8
  ...DEFAULT_IMPORT_BYTE_LIMITS,
@@ -100,7 +98,7 @@ export class IncrementalSessionImporter {
100
98
  batchStart, checkpoint.recordsRead,
101
99
  ...batchDigests,
102
100
  ].join('\0'));
103
- const normalized = normalizeBatch(request, batch, batchDigests, runId, sourceObservedAt);
101
+ const normalized = normalizeSessionBatch(request, batch, batchDigests, runId, sourceObservedAt);
104
102
  const run = {
105
103
  contractVersion: SESSION_CONTRACT_VERSION,
106
104
  importRunId: runId,
@@ -178,7 +176,10 @@ export class IncrementalSessionImporter {
178
176
  }
179
177
  else {
180
178
  checkpoint.bytesRead += bytes;
181
- 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);
182
183
  }
183
184
  if (batch.length >= limits.batchSize)
184
185
  flush();
@@ -232,250 +233,6 @@ function recordIdentity(record) {
232
233
  const serialized = JSON.stringify(record);
233
234
  return { bytes: Buffer.byteLength(serialized), digest: sha256(serialized) };
234
235
  }
235
- function normalizeBatch(request, records, digests, importRunId, sourceObservedAt) {
236
- const sessions = new Map();
237
- // Extract inline images before sanitization: provider image blocks in
238
- // extensions are redacted to markers below, so bytes must be lifted out
239
- // first while the raw record is still intact (#3265).
240
- const imageBlobs = new Map();
241
- const events = records.map((record, index) => {
242
- const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
243
- const native = sanitizeNativeExtensions(record.extensions ?? {});
244
- const lineage = request.source.provider === 'codex' && native.value.lineage
245
- ? { lineage: native.value.lineage } : {};
246
- const images = extractEventImages({
247
- searchableText: record.text,
248
- extensions: record.extensions,
249
- rawReference: record.rawReference,
250
- });
251
- for (const image of images.images) {
252
- if (!imageBlobs.has(image.digest))
253
- imageBlobs.set(image.digest, image);
254
- }
255
- const digest = digests[index];
256
- const origin = classifySessionEventOrigin(request.source.provider, record);
257
- const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
258
- const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
259
- const extensions = {
260
- [`native.${request.source.provider}`]: images.extensions,
261
- };
262
- const event = sanitizeSessionEvent(SessionEventSchema.parse({
263
- contractVersion: SESSION_CONTRACT_VERSION,
264
- eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
265
- sessionId, sourceId: request.source.sourceId, importRunId,
266
- nativeId: record.nativeEventId ?? null, sequence: record.sequence,
267
- kind: record.kind, role: record.role ?? null, occurredAt: record.occurredAt ?? null,
268
- activityBoundary: record.activityBoundary ?? null,
269
- activityBoundaryBasis: record.activityBoundaryBasis ?? null,
270
- activityBoundaryConfidence: record.activityBoundaryConfidence ?? null,
271
- origin: origin.origin,
272
- originRule: origin.rule,
273
- originClassifierVersion: origin.classifierVersion,
274
- participant: record.participant ?? null,
275
- toolName: record.toolName ?? null,
276
- toolCallId: record.toolCallId ?? null,
277
- model: record.model ?? null,
278
- entities: record.entities ?? [],
279
- extractionState: record.extractionState ?? null,
280
- searchableText: images.searchableText, imageRefs: images.imageRefs,
281
- digest, rawReference: record.rawReference,
282
- adapterVersion: request.adapter.adapterVersion,
283
- consistency: request.source.consistency,
284
- sensitivity: { classification: 'none', classes: [] },
285
- opaque: !isKnownEventKind(record.kind),
286
- extensions,
287
- }));
288
- if (!sessions.has(sessionId)) {
289
- sessions.set(sessionId, SessionSchema.parse({
290
- contractVersion: SESSION_CONTRACT_VERSION,
291
- sessionId, sourceId: request.source.sourceId, provider: request.source.provider,
292
- nativeSessionId: record.nativeSessionId, workspaceId: request.workspaceId,
293
- startedAt: record.occurredAt ?? null, updatedAt: record.occurredAt ?? null,
294
- consistency: request.source.consistency,
295
- lifecycle,
296
- sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
297
- extensions: {
298
- [`native.${request.source.provider}`]: {
299
- ...lineage,
300
- lifecycleEvidence,
301
- },
302
- },
303
- }));
304
- }
305
- else {
306
- const session = sessions.get(sessionId);
307
- session.startedAt = earlierTimestamp(session.startedAt, record.occurredAt ?? null);
308
- session.updatedAt = laterTimestamp(session.updatedAt, record.occurredAt ?? null);
309
- session.consistency = strongerConsistency(session.consistency, request.source.consistency);
310
- const nativeKey = `native.${request.source.provider}`;
311
- const nativeEnvelope = session.extensions[nativeKey];
312
- const nativeRecord = nativeEnvelope && typeof nativeEnvelope === 'object' && !Array.isArray(nativeEnvelope)
313
- ? nativeEnvelope
314
- : {};
315
- const selected = selectLifecycleTransition(session.lifecycle, nativeRecord.lifecycleEvidence, lifecycle, lifecycleEvidence);
316
- session.lifecycle = selected.lifecycle;
317
- session.extensions[nativeKey] = {
318
- ...nativeRecord,
319
- ...lineage,
320
- lifecycleEvidence: selected.evidence,
321
- };
322
- }
323
- return event;
324
- });
325
- for (const session of sessions.values()) {
326
- session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
327
- }
328
- return {
329
- sessions: redactSessionValue([...sessions.values()]).value,
330
- events,
331
- imageBlobs: [...imageBlobs.values()],
332
- };
333
- }
334
- const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
335
- function isKnownEventKind(kind) {
336
- const normalized = kind.toLowerCase();
337
- return KNOWN_EVENT_KINDS.has(normalized)
338
- || /^(?:tool-call|tool-result)(?:[._-]|$)/.test(normalized)
339
- || /^(?:sandbox|permission|approval|hitl|human|lifecycle)(?:[._-]|$)/.test(normalized);
340
- }
341
- function earlierTimestamp(left, right) {
342
- if (!left)
343
- return right;
344
- if (!right)
345
- return left;
346
- return Date.parse(left) <= Date.parse(right) ? left : right;
347
- }
348
- function laterTimestamp(left, right) {
349
- if (!left)
350
- return right;
351
- if (!right)
352
- return left;
353
- return Date.parse(left) >= Date.parse(right) ? left : right;
354
- }
355
- function strongerConsistency(left, right) {
356
- const rank = {
357
- provisional: 0,
358
- 'consistent-snapshot': 1,
359
- complete: 2,
360
- };
361
- return rank[left] >= rank[right] ? left : right;
362
- }
363
- function sessionLifecycle(request, record, sourceObservedAt) {
364
- const explicit = nativeLifecycle(record.extensions);
365
- if (explicit)
366
- return explicit;
367
- if (request.source.consistency === 'complete')
368
- return 'complete';
369
- const observedAt = record.occurredAt ?? sourceObservedAt;
370
- if (observedAt && isStaleHistoricalTimestamp(observedAt, inactivityThresholdMs(request)))
371
- return 'inactive';
372
- return 'active';
373
- }
374
- function sessionLifecycleEvidence(request, record, sourceObservedAt) {
375
- const observedAt = record.occurredAt ?? sourceObservedAt;
376
- const explicit = nativeLifecycle(record.extensions);
377
- if (explicit) {
378
- return {
379
- basis: 'provider-explicit-event',
380
- state: explicit,
381
- observedAt: observedAt ?? request.source.authorizedAt,
382
- confidence: 'high',
383
- };
384
- }
385
- if (request.source.consistency === 'complete') {
386
- return {
387
- basis: 'complete-source',
388
- state: 'complete',
389
- observedAt: observedAt ?? request.source.authorizedAt,
390
- confidence: 'high',
391
- };
392
- }
393
- const thresholdMs = inactivityThresholdMs(request);
394
- if (observedAt && isStaleHistoricalTimestamp(observedAt, thresholdMs)) {
395
- return {
396
- basis: 'inactivity-threshold',
397
- state: 'inactive',
398
- observedAt,
399
- confidence: 'medium',
400
- thresholdMs,
401
- };
402
- }
403
- return {
404
- basis: 'open-provisional-source',
405
- state: 'active',
406
- observedAt: observedAt ?? request.source.authorizedAt,
407
- confidence: 'provisional',
408
- thresholdMs,
409
- };
410
- }
411
- function nativeLifecycle(extensions) {
412
- const raw = typeof extensions?.lifecycle === 'string' ? extensions.lifecycle : undefined;
413
- if (!raw)
414
- return null;
415
- const normalized = {
416
- active: 'active',
417
- inactive: 'inactive',
418
- paused: 'paused',
419
- complete: 'complete',
420
- completed: 'complete',
421
- archived: 'archived',
422
- deleted: 'tombstoned',
423
- cancelled: 'interrupted',
424
- canceled: 'interrupted',
425
- failed: 'interrupted',
426
- interrupted: 'interrupted',
427
- unknown: 'unknown',
428
- 'unknown-at-import': 'unknown',
429
- 'completed-at-import': 'complete',
430
- };
431
- return normalized[raw] ?? null;
432
- }
433
- function selectLifecycleTransition(leftLifecycle, left, rightLifecycle, right) {
434
- const leftEvidence = asLifecycleEvidence(left);
435
- if (leftLifecycle === 'tombstoned') {
436
- return { lifecycle: leftLifecycle, evidence: leftEvidence ?? right };
437
- }
438
- if (!leftEvidence)
439
- return { lifecycle: rightLifecycle, evidence: right };
440
- const rank = {
441
- 'open-provisional-source': 1,
442
- 'inactivity-threshold': 1,
443
- 'complete-source': 2,
444
- 'provider-explicit-event': 3,
445
- };
446
- const leftRank = rank[String(leftEvidence.basis)] ?? 0;
447
- const rightRank = rank[String(right.basis)] ?? 0;
448
- const rightIsNewer = evidenceTimestamp(right) > evidenceTimestamp(leftEvidence);
449
- return rightRank > leftRank || (rightRank === leftRank && rightIsNewer)
450
- ? { lifecycle: rightLifecycle, evidence: right }
451
- : { lifecycle: leftLifecycle, evidence: leftEvidence };
452
- }
453
- function asLifecycleEvidence(value) {
454
- return value !== null && typeof value === 'object' && !Array.isArray(value)
455
- ? value
456
- : null;
457
- }
458
- function evidenceTimestamp(value) {
459
- const parsed = Date.parse(String(value.observedAt ?? ''));
460
- return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
461
- }
462
- function inactivityThresholdMs(request) {
463
- return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
464
- }
465
- function isStaleHistoricalTimestamp(value, thresholdMs) {
466
- const timestamp = Date.parse(value);
467
- return Number.isFinite(timestamp)
468
- && Date.now() - timestamp > thresholdMs;
469
- }
470
- function sourceGenerationDigest(request) {
471
- return sha256([
472
- request.source.sourceId,
473
- request.source.provider,
474
- request.selectedSource.locatorClass,
475
- request.source.sourceSchemaVersion,
476
- request.adapter.adapterVersion,
477
- ].join('\0'));
478
- }
479
236
  async function sourceContinuity(request, previous) {
480
237
  if (request.selectedSource.authorizedScope.allowedRoots.length === 0
481
238
  || /^[a-z][a-z0-9+.-]*:\/\//i.test(request.selectedSource.locator)
@@ -20,6 +20,7 @@ export * from './importer.js';
20
20
  export * from './import-lease.js';
21
21
  export * from './batch-contracts.js';
22
22
  export * from './batch-import.js';
23
+ export * from './intake-dir.js';
23
24
  export * from './host-catalog.js';
24
25
  export * from './workspace-discovery.js';
25
26
  export * from './timeline.js';
@@ -32,11 +33,13 @@ export * from './adapters/copilot.js';
32
33
  export * from './adapters/cursor.js';
33
34
  export * from './adapters/factory.js';
34
35
  export * from './adapters/hermes.js';
36
+ export * from './adapters/hermes-state-db.js';
35
37
  export * from './adapters/opencode.js';
36
38
  export * from './adapters/openclaw.js';
37
39
  export * from './adapters/openhuman.js';
38
40
  export * from './adapters/grokbot.js';
39
41
  export * from './adapters/grok-build.js';
42
+ export * from './adapters/grok-build-native.js';
40
43
  export * from './grok-build-cli.js';
41
44
  export * from './adapters/pi.js';
42
45
  export * from './adapters/deepseek-harness.js';
@@ -46,4 +49,5 @@ export * from './adapters/muse.js';
46
49
  export * from './adapters/omp.js';
47
50
  export * from './adapter-registry.js';
48
51
  export * from './coverage-preflight.js';
52
+ export * from './discovery-capability.js';
49
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