@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.
- package/agentic/code/providers/model-catalog.v1.json +62 -12
- package/dist/src/artifacts/binding-target-identity.js +51 -0
- package/dist/src/artifacts/checksum-manifest.js +12 -0
- package/dist/src/artifacts/index-builder.js +11 -13
- package/dist/src/artifacts/query-engine.js +5 -11
- package/dist/src/cli/handlers/doctor-help.js +32 -0
- package/dist/src/cli/handlers/gates.js +19 -18
- package/dist/src/cli/handlers/models-help.js +7 -1
- package/dist/src/cli/handlers/models.js +3 -3
- package/dist/src/cli/handlers/script-runner.js +8 -5
- package/dist/src/cli/handlers/sessions-intake.js +104 -0
- package/dist/src/cli/handlers/sessions-tail.js +172 -0
- package/dist/src/cli/handlers/sessions.js +90 -17
- package/dist/src/cli/handlers/skill-lint.js +10 -3
- package/dist/src/cli/handlers/steward-format.js +100 -0
- package/dist/src/cli/handlers/steward-models.js +167 -0
- package/dist/src/cli/handlers/steward.js +14 -248
- package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
- package/dist/src/cli/handlers/use.js +6 -24
- package/dist/src/cli/handlers/utilities.js +1 -24
- package/dist/src/config/aiwg-config.js +7 -0
- package/dist/src/config/authorization-cli.js +89 -0
- package/dist/src/config/cli-help.js +1 -0
- package/dist/src/config/cli.js +10 -1
- package/dist/src/decision/context-pruning.js +3 -2
- package/dist/src/decision/ensemble/contract.js +15 -4
- package/dist/src/decision/ensemble-study/artifacts.js +5 -0
- package/dist/src/decision/ensemble-study/score.js +4 -3
- package/dist/src/decision/feature-export.js +3 -9
- package/dist/src/decision/heldout/collector.js +2 -2
- package/dist/src/decision/issue-triage/runtime.js +3 -9
- package/dist/src/decision/qualification/gates.js +2 -1
- package/dist/src/decision/qualification/release.js +2 -3
- package/dist/src/decision/routing/report.js +2 -0
- package/dist/src/decision/sdlc-screening.js +3 -5
- package/dist/src/decision/sensitivity/comparative.js +5 -3
- package/dist/src/gates/driver.js +6 -77
- package/dist/src/gates/evaluate.js +4 -11
- package/dist/src/gates/floors.js +4 -4
- package/dist/src/gates/index.js +3 -3
- package/dist/src/gates/lattice.js +26 -0
- package/dist/src/gates/registry.js +2 -1
- package/dist/src/gates/report.js +19 -7
- package/dist/src/issues/audit-cli.js +120 -0
- package/dist/src/issues/audit-contract.js +64 -0
- package/dist/src/issues/audit-local.js +82 -0
- package/dist/src/issues/audit.js +220 -0
- package/dist/src/lint/rule-activation.js +15 -1
- package/dist/src/mission-protocol/canonical-codecs.js +270 -0
- package/dist/src/mission-protocol/codecs.js +22 -550
- package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
- package/dist/src/mission-protocol/health-trace-types.js +43 -0
- package/dist/src/mission-protocol/types.js +2 -42
- package/dist/src/mission-protocol/worker-contract-json.js +10 -0
- package/dist/src/mission-protocol/worker-review-gate.js +100 -0
- package/dist/src/mission-protocol/worker-review-types.js +2 -0
- package/dist/src/models/catalog-policy.js +280 -0
- package/dist/src/models/index.js +1 -1
- package/dist/src/models/model-catalog.v1.json +62 -12
- package/dist/src/models/policy-resources.js +28 -0
- package/dist/src/models/provider-policy.js +10 -546
- package/dist/src/models/resolver.js +26 -8
- package/dist/src/models/router.js +15 -2
- package/dist/src/models/tiers.js +13 -0
- package/dist/src/models/types.js +0 -6
- package/dist/src/models/worker-ceilings.js +59 -0
- package/dist/src/models/worker-invocation-policy.js +243 -0
- package/dist/src/models/worker-plan.js +16 -20
- package/dist/src/models/worker-review-lineage.js +55 -0
- package/dist/src/models/worker-selection-policy.js +1 -1
- package/dist/src/models/wrapper-route.js +6 -3
- package/dist/src/policy/authorization.js +1 -0
- package/dist/src/policy/hitl-config.js +63 -0
- package/dist/src/policy/hitl-receipt.js +57 -0
- package/dist/src/policy/hitl-types.js +4 -0
- package/dist/src/policy/hitl-validation.js +39 -0
- package/dist/src/policy/hitl.js +117 -0
- package/dist/src/rules/activation.d.mts +1 -1
- package/dist/src/rules/activation.mjs +0 -2
- package/dist/src/rules/gate-coverage.js +51 -0
- package/dist/src/rules/gate-references.js +16 -0
- package/dist/src/rules/rule-frontmatter.schema.json +7 -1
- package/dist/src/serve/worker-command-request.js +21 -4
- package/dist/src/serve/worker-invocation-preparation.js +3 -1
- package/dist/src/serve/worker-invocation.js +21 -10
- package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
- package/dist/src/sessions/adapters/grok-build-native.js +269 -0
- package/dist/src/sessions/adapters/grok-build.js +57 -15
- package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
- package/dist/src/sessions/adapters/hermes.js +42 -3
- package/dist/src/sessions/adapters/warp.js +1 -1
- package/dist/src/sessions/batch-import.js +10 -0
- package/dist/src/sessions/contracts.js +1 -1
- package/dist/src/sessions/discovery-capability.js +38 -0
- package/dist/src/sessions/importer.js +8 -251
- package/dist/src/sessions/index.js +4 -0
- package/dist/src/sessions/intake-dir.js +71 -0
- package/dist/src/sessions/normalization.js +251 -0
- package/dist/src/sessions/tail.js +91 -0
- package/dist/src/sessions/workspace-discovery.js +83 -7
- package/dist/src/skills/agent-skill-sidecar.js +28 -0
- package/dist/src/skills/agent-skills.js +4 -23
- package/dist/src/skills/claude-surface-projection.js +25 -0
- package/dist/src/skills/deployer.js +8 -288
- package/dist/src/skills/deployment-policy.js +114 -0
- package/dist/src/skills/deployment-projection.js +152 -0
- package/dist/src/skills/deployment-types.js +20 -0
- package/dist/src/skills/exporter.js +8 -31
- package/dist/src/skills/provider-extensions.js +41 -0
- package/dist/src/skills/run.js +6 -0
- package/dist/src/skills/types.js +0 -8
- package/dist/src/skills/validator-resources.js +68 -0
- package/dist/src/skills/validator.js +6 -55
- package/dist/src/storage/cli-migrate-options.js +125 -0
- package/dist/src/storage/cli-migrate.js +111 -0
- package/dist/src/storage/cli.js +4 -279
- package/dist/src/storage/migration-adapter.js +79 -0
- package/dist/src/storage/migration-copy.js +108 -0
- package/dist/src/storage/migration-protocol.js +14 -197
- package/dist/src/storage/migration-records.js +186 -0
- package/dist/src/storage/migration-types.js +12 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/tracker/issue-pages.js +110 -0
- package/package.json +1 -1
- package/schemas/mission-v1.schema.json +335 -0
- package/schemas/models/model-catalog.v1.schema.json +19 -1
- package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
- package/schemas/models/model-policy.v1.schema.json +1 -1
- package/tools/agents/providers/provider-paths-staging.mjs +35 -0
- package/tools/agents/providers/rule-binding-targets.mjs +146 -0
- package/tools/agents/providers/rule-delivery.mjs +7 -126
- 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
|
-
|
|
74
|
-
|
|
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,
|
|
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,
|
|
4
|
-
import { extractEventImages } from './image-blobs.js';
|
|
3
|
+
import { redactSessionValue, sanitizeNativeExtensions } from './policy.js';
|
|
5
4
|
import { fingerprintSourcePrefix } from './readers.js';
|
|
6
|
-
import {
|
|
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 =
|
|
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
|
-
|
|
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
|