@aiwg/cli 2026.9.0 → 2026.9.2

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 (107) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +41 -0
  2. package/agentic/code/providers/model-capabilities.v1.json +11 -0
  3. package/agentic/code/providers/model-catalog.v1.json +8 -0
  4. package/agentic/code/providers/pi/aiwg-bridge.ts +26 -0
  5. package/bin/aiwg.mjs +15 -3
  6. package/dist/src/api/index.d.ts +3 -0
  7. package/dist/src/api/index.js +3 -0
  8. package/dist/src/auth/credential-store.js +6 -0
  9. package/dist/src/channel/manager.mjs +2 -2
  10. package/dist/src/cli/handlers/dataset.js +186 -0
  11. package/dist/src/cli/handlers/help.js +2 -1
  12. package/dist/src/cli/handlers/index.js +5 -1
  13. package/dist/src/cli/handlers/init.js +1 -0
  14. package/dist/src/cli/handlers/output-mode.js +18 -1
  15. package/dist/src/cli/handlers/run.js +11 -3
  16. package/dist/src/cli/handlers/schema.js +221 -0
  17. package/dist/src/cli/handlers/sessions.js +30 -12
  18. package/dist/src/cli/handlers/steward.js +11 -1
  19. package/dist/src/cli/handlers/use.js +6 -2
  20. package/dist/src/cli/hooks/builtin/activity-log-hook.js +6 -0
  21. package/dist/src/cli/router.js +1 -1
  22. package/dist/src/cli/scope-resolver.js +22 -0
  23. package/dist/src/dataset/adapter-sdk.d.ts +41 -0
  24. package/dist/src/dataset/adapter-sdk.js +147 -0
  25. package/dist/src/dataset/adapter-types.d.ts +179 -0
  26. package/dist/src/dataset/adapter-types.js +2 -0
  27. package/dist/src/dataset/adapters.d.ts +104 -0
  28. package/dist/src/dataset/adapters.js +518 -0
  29. package/dist/src/dataset/conformance-types.d.ts +84 -0
  30. package/dist/src/dataset/conformance-types.js +3 -0
  31. package/dist/src/dataset/conformance.d.ts +13 -0
  32. package/dist/src/dataset/conformance.js +90 -0
  33. package/dist/src/dataset/contracts.d.ts +17 -0
  34. package/dist/src/dataset/contracts.js +236 -0
  35. package/dist/src/dataset/file-orchestration-repository.d.ts +19 -0
  36. package/dist/src/dataset/file-orchestration-repository.js +68 -0
  37. package/dist/src/dataset/fortemi-execution-bridge.d.ts +33 -0
  38. package/dist/src/dataset/fortemi-execution-bridge.js +35 -0
  39. package/dist/src/dataset/index.d.ts +21 -0
  40. package/dist/src/dataset/index.js +21 -0
  41. package/dist/src/dataset/ledger-types.d.ts +141 -0
  42. package/dist/src/dataset/ledger-types.js +2 -0
  43. package/dist/src/dataset/ledger.d.ts +27 -0
  44. package/dist/src/dataset/ledger.js +100 -0
  45. package/dist/src/dataset/local-execution-backend.d.ts +10 -0
  46. package/dist/src/dataset/local-execution-backend.js +32 -0
  47. package/dist/src/dataset/orchestration-repository.d.ts +29 -0
  48. package/dist/src/dataset/orchestration-repository.js +34 -0
  49. package/dist/src/dataset/orchestration-service.d.ts +56 -0
  50. package/dist/src/dataset/orchestration-service.js +466 -0
  51. package/dist/src/dataset/orchestration-types.d.ts +83 -0
  52. package/dist/src/dataset/orchestration-types.js +2 -0
  53. package/dist/src/dataset/presentation.d.ts +3 -0
  54. package/dist/src/dataset/presentation.js +8 -0
  55. package/dist/src/dataset/projections.d.ts +42 -0
  56. package/dist/src/dataset/projections.js +192 -0
  57. package/dist/src/dataset/schema-governance.d.ts +71 -0
  58. package/dist/src/dataset/schema-governance.js +135 -0
  59. package/dist/src/dataset/standards-types.d.ts +66 -0
  60. package/dist/src/dataset/standards-types.js +10 -0
  61. package/dist/src/dataset/standards.d.ts +13 -0
  62. package/dist/src/dataset/standards.js +291 -0
  63. package/dist/src/dataset/types.d.ts +258 -0
  64. package/dist/src/dataset/types.js +2 -0
  65. package/dist/src/extensions/commands/definitions.js +27 -1
  66. package/dist/src/installation/manager.mjs +5 -1
  67. package/dist/src/models/model-capabilities.v1.json +11 -0
  68. package/dist/src/models/model-catalog.v1.json +8 -0
  69. package/dist/src/models/model-discovery.js +32 -0
  70. package/dist/src/models/provider-policy.js +3 -2
  71. package/dist/src/output-modes/index.js +4 -0
  72. package/dist/src/output-modes/registry.js +68 -24
  73. package/dist/src/output-modes/runtime.js +10 -8
  74. package/dist/src/plugin/skill-command-translator.js +1 -0
  75. package/dist/src/providers/capability-matrix.yaml +41 -0
  76. package/dist/src/providers/provider-definitions.js +72 -0
  77. package/dist/src/providers/provider-inventory.js +1 -0
  78. package/dist/src/schema/catalog.js +234 -0
  79. package/dist/src/schema/compatibility.js +42 -0
  80. package/dist/src/schema/diagnostics.js +36 -0
  81. package/dist/src/schema/index.js +8 -0
  82. package/dist/src/schema/policy.js +58 -0
  83. package/dist/src/schema/resolver.js +76 -0
  84. package/dist/src/schema/types.js +2 -0
  85. package/dist/src/schema/validator.js +82 -0
  86. package/dist/src/sessions/adapters/pi.js +141 -0
  87. package/dist/src/sessions/contracts.js +1 -1
  88. package/dist/src/sessions/index.js +1 -0
  89. package/dist/src/sessions/workspace-discovery.js +10 -0
  90. package/dist/src/storage/backends/fortemi.js +6 -0
  91. package/dist/src/storage/config.js +18 -4
  92. package/dist/src/storage/fortemi-qualification.js +106 -0
  93. package/dist/src/storage/index.js +1 -0
  94. package/dist/src/storage/types.js +1 -1
  95. package/package.json +3 -1
  96. package/schemas/dataset/conformance-manifest.v1.schema.json +35 -0
  97. package/schemas/dataset/conformance-receipt.v1.schema.json +22 -0
  98. package/schemas/dataset/dataset-contracts.v1.schema.json +117 -0
  99. package/schemas/dataset/dataset-deprecations.v1.schema.json +37 -0
  100. package/schemas/dataset/dataset-schema-governance.v1.schema.json +92 -0
  101. package/schemas/dataset/dataset-standards-exchange.v1.schema.json +59 -0
  102. package/schemas/dataset/profiles/openlineage-1.0.0.schema.json +15 -0
  103. package/schemas/dataset/profiles/prov-json-20130430.schema.json +12 -0
  104. package/schemas/dataset/run-ledger.v1.schema.json +39 -0
  105. package/schemas/dataset/source-adapter.v1.schema.json +112 -0
  106. package/tools/agents/deploy-agents.mjs +9 -3
  107. package/tools/agents/providers/pi.mjs +176 -0
@@ -0,0 +1,90 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { DATASET_CONFORMANCE_CONTRACT } from './conformance-types.js';
3
+ const SHA256 = /^sha256:[0-9a-f]{64}$/u;
4
+ const SECRET = /(?:(?:password|passwd|api[-_]?key|authorization)\s*[:=]\s*[^\s"}]+|bearer\s+[a-z0-9._~+/-]+|-----BEGIN [A-Z ]+PRIVATE KEY-----)/iu;
5
+ export function canonicalConformanceJson(value) {
6
+ if (value === null || typeof value !== 'object')
7
+ return JSON.stringify(value);
8
+ if (Array.isArray(value))
9
+ return `[${value.map(canonicalConformanceJson).join(',')}]`;
10
+ return `{${Object.entries(value)
11
+ .filter(([, item]) => item !== undefined)
12
+ .sort(([left], [right]) => left.localeCompare(right))
13
+ .map(([key, item]) => `${JSON.stringify(key)}:${canonicalConformanceJson(item)}`).join(',')}}`;
14
+ }
15
+ export function conformanceDigest(value) {
16
+ return `sha256:${createHash('sha256').update(canonicalConformanceJson(value)).digest('hex')}`;
17
+ }
18
+ export function resultDigest(results) {
19
+ return conformanceDigest([...results].sort((a, b) => a.cellId.localeCompare(b.cellId)).map(result => ({
20
+ cellId: result.cellId,
21
+ status: result.status,
22
+ diagnostic: result.diagnostic,
23
+ evidence: [...result.evidence].sort((a, b) => `${a.kind}:${a.reference}`.localeCompare(`${b.kind}:${b.reference}`)),
24
+ observed: result.observed,
25
+ })));
26
+ }
27
+ export function validateConformanceManifest(manifest) {
28
+ const diagnostics = [];
29
+ if (manifest.contract !== DATASET_CONFORMANCE_CONTRACT || !/^1\./u.test(manifest.schemaVersion) || !manifest.corpusVersion) {
30
+ diagnostics.push({ code: 'CONFORMANCE_MANIFEST_INVALID', path: '/', message: 'Unsupported contract, schema version, or empty corpus version.' });
31
+ }
32
+ const seen = new Set();
33
+ manifest.cells.forEach((cell, index) => {
34
+ const path = `/cells/${index}`;
35
+ if (!cell.id || seen.has(cell.id))
36
+ diagnostics.push({ code: 'CONFORMANCE_CELL_DUPLICATE', path: `${path}/id`, message: `Cell id ${cell.id || '<empty>'} is not unique.` });
37
+ seen.add(cell.id);
38
+ if (!SHA256.test(cell.fixture.digest))
39
+ diagnostics.push({ code: 'CONFORMANCE_MANIFEST_INVALID', path: `${path}/fixture/digest`, message: 'Fixture digest must be sha256.' });
40
+ if (!cell.resourceEnvelope || cell.resourceEnvelope.maxBytes < 1 || cell.resourceEnvelope.maxRecords < 1 || cell.resourceEnvelope.maxDurationMs < 1) {
41
+ diagnostics.push({ code: 'CONFORMANCE_RESOURCE_ENVELOPE_MISSING', path: `${path}/resourceEnvelope`, message: 'Every cell requires positive byte, record, and duration bounds.' });
42
+ }
43
+ if (cell.maturity === 'stable' && !cell.evidence.some(kind => kind === 'real-source' || kind === 'cross-repo' || kind === 'live-qualification')) {
44
+ diagnostics.push({ code: 'CONFORMANCE_MOCK_ONLY_STABLE', path: `${path}/evidence`, message: 'Stable cells require non-fixture evidence.' });
45
+ }
46
+ if (cell.runtimeClass === 'fortemi-server' && cell.maturity === 'stable' && !cell.liveAuthorizationRequired) {
47
+ diagnostics.push({ code: 'CONFORMANCE_MANIFEST_INVALID', path: `${path}/liveAuthorizationRequired`, message: 'Stable server cells must declare the live authorization gate.' });
48
+ }
49
+ });
50
+ return diagnostics;
51
+ }
52
+ export function summarizeConformance(manifest, results) {
53
+ const passed = results.filter(result => result.status === 'passed').length;
54
+ const failed = results.filter(result => result.status === 'failed').length;
55
+ const pending = results.filter(result => result.status === 'pending').length;
56
+ const releaseIds = new Set(manifest.cells.filter(cell => cell.maturity !== 'experimental').map(cell => cell.id));
57
+ const stableEligible = failed === 0 && [...releaseIds].every(id => results.some(result => result.cellId === id && result.status === 'passed'));
58
+ return { passed, failed, pending, stableEligible };
59
+ }
60
+ export function verifyConformanceReceipt(manifest, receipt) {
61
+ const diagnostics = validateConformanceManifest(manifest);
62
+ if (receipt.manifestDigest !== conformanceDigest(manifest) || receipt.corpusVersion !== manifest.corpusVersion) {
63
+ diagnostics.push({ code: 'CONFORMANCE_RECEIPT_STALE', path: '/manifestDigest', message: 'Receipt does not bind the current manifest and corpus.' });
64
+ }
65
+ if (receipt.resultDigest !== resultDigest(receipt.results))
66
+ diagnostics.push({ code: 'CONFORMANCE_RESULT_DIGEST_MISMATCH', path: '/resultDigest', message: 'Result digest does not match canonical results.' });
67
+ if (!SHA256.test(receipt.bindings.aiwgCommit) && !/^[0-9a-f]{40}$/u.test(receipt.bindings.aiwgCommit))
68
+ diagnostics.push({ code: 'CONFORMANCE_RECEIPT_UNVERIFIABLE', path: '/bindings/aiwgCommit', message: 'AIWG commit binding is invalid.' });
69
+ if (Object.keys(receipt.bindings.packageDigests).length === 0 || Object.keys(receipt.bindings.schemaDigests).length === 0)
70
+ diagnostics.push({ code: 'CONFORMANCE_RECEIPT_UNVERIFIABLE', path: '/bindings', message: 'Package and schema digest bindings are required.' });
71
+ const resultById = new Map(receipt.results.map(result => [result.cellId, result]));
72
+ manifest.cells.forEach(cell => {
73
+ const result = resultById.get(cell.id);
74
+ if (!result)
75
+ diagnostics.push({ code: 'CONFORMANCE_REQUIRED_CELL_MISSING', path: `/results/${cell.id}`, message: `Required cell ${cell.id} is missing.` });
76
+ else if (result.status === 'failed')
77
+ diagnostics.push({ code: 'CONFORMANCE_RESULT_FAILED', path: `/results/${cell.id}`, message: `Cell ${cell.id} failed: ${result.diagnostic ?? 'no diagnostic'}.` });
78
+ else if (result.status === 'pending' && cell.maturity === 'stable')
79
+ diagnostics.push({ code: 'CONFORMANCE_PENDING_STABLE_CELL', path: `/results/${cell.id}`, message: `Stable cell ${cell.id} cannot be pending.` });
80
+ else if (result.status === 'passed' && cell.evidence.some(required => !result.evidence.some(item => item.kind === required)))
81
+ diagnostics.push({ code: 'CONFORMANCE_EVIDENCE_WEAKENED', path: `/results/${cell.id}/evidence`, message: `Cell ${cell.id} lacks a required evidence kind.` });
82
+ });
83
+ if (SECRET.test(JSON.stringify(receipt)))
84
+ diagnostics.push({ code: 'CONFORMANCE_SENSITIVE_VALUE', path: '/', message: 'Receipt contains a secret-like value.' });
85
+ const summary = summarizeConformance(manifest, receipt.results);
86
+ if (canonicalConformanceJson(summary) !== canonicalConformanceJson(receipt.summary))
87
+ diagnostics.push({ code: 'CONFORMANCE_RECEIPT_UNVERIFIABLE', path: '/summary', message: 'Receipt summary is inconsistent with results.' });
88
+ return diagnostics;
89
+ }
90
+ //# sourceMappingURL=conformance.js.map
@@ -0,0 +1,17 @@
1
+ import { type CapabilityNegotiationReceipt, type CapabilityProfile, type Checkpoint, type AvailableDatasetCapability, type DatasetContract, type DatasetDiagnostic, type DatasetValidationResult, type Digest, type ProcessingPlan, type RunReceipt } from './types.js';
2
+ export declare function validateDatasetContract(value: unknown): DatasetValidationResult;
3
+ export declare function canonicalDatasetJson(value: unknown): string;
4
+ export declare function datasetDigest(value: unknown): Digest;
5
+ export declare function computeProcessingPlanDigest(plan: ProcessingPlan): Digest;
6
+ export declare function verifyProcessingPlanDigest(plan: ProcessingPlan): boolean;
7
+ export declare function computeRunReceiptDigest(receipt: RunReceipt): Digest;
8
+ export declare function verifyRunReceiptDigest(receipt: RunReceipt): boolean;
9
+ export declare function negotiateDatasetCapabilities(profile: CapabilityProfile, available: readonly (string | AvailableDatasetCapability)[]): CapabilityNegotiationReceipt;
10
+ /** Validate identity references across a complete contract bundle. */
11
+ export declare function validateDatasetContractSet(contracts: readonly DatasetContract[]): DatasetDiagnostic[];
12
+ export declare function validateCheckpointAncestry(checkpoint: Checkpoint, prior?: RunReceipt): DatasetDiagnostic[];
13
+ export declare class DatasetContractError extends Error {
14
+ readonly code: string;
15
+ constructor(code: string, message: string);
16
+ }
17
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1,236 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import Ajv2020 from 'ajv/dist/2020.js';
6
+ import addFormats from 'ajv-formats';
7
+ import { DATASET_CONTRACT_VERSION, } from './types.js';
8
+ const CONTRACT_KINDS = new Set([
9
+ 'DatasetSource', 'Dataset', 'DatasetRevision', 'Distribution',
10
+ 'CapabilityProfile', 'ProcessingPlan', 'ProcessingRun', 'DerivedArtifact',
11
+ 'ProvenanceAssertion', 'Relationship', 'Checkpoint', 'RunReceipt',
12
+ ]);
13
+ const RUN_OUTCOMES = new Set(['preview', 'attempted', 'committed', 'rejected', 'cancelled', 'failed']);
14
+ const SECRET_KEYS = /^(?:password|passwd|secret|token|api[-_]?key|private[-_]?key|credential)s?$/i;
15
+ function packageRoot(start) {
16
+ let current = resolve(start);
17
+ for (;;) {
18
+ try {
19
+ const packageJson = JSON.parse(readFileSync(join(current, 'package.json'), 'utf8'));
20
+ // The source tree is named `aiwg`; the release packager rewrites the
21
+ // installed distribution to `@aiwg/cli`. Both layouts contain the same
22
+ // governed schemas, so package discovery must recognize both identities.
23
+ if (packageJson.name === 'aiwg' || packageJson.name === '@aiwg/cli')
24
+ return current;
25
+ }
26
+ catch {
27
+ // Keep walking; source and compiled modules have different depths.
28
+ }
29
+ const parent = dirname(current);
30
+ if (parent === current)
31
+ throw new Error('dataset contracts: could not locate the aiwg package root');
32
+ current = parent;
33
+ }
34
+ }
35
+ const contractSchemaPath = join(packageRoot(dirname(fileURLToPath(import.meta.url))), 'schemas/dataset/dataset-contracts.v1.schema.json');
36
+ const contractSchema = JSON.parse(readFileSync(contractSchemaPath, 'utf8'));
37
+ const contractAjv = new Ajv2020({ strict: true, allErrors: true });
38
+ addFormats(contractAjv);
39
+ const validateSerializedContract = contractAjv.compile(contractSchema);
40
+ function isRecord(value) {
41
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
42
+ }
43
+ function diagnostic(code, message, path) {
44
+ return { code, message, ...(path === undefined ? {} : { path }) };
45
+ }
46
+ function detectEmbeddedSecrets(value, path = '') {
47
+ if (Array.isArray(value))
48
+ return value.flatMap((item, index) => detectEmbeddedSecrets(item, `${path}/${index}`));
49
+ if (!isRecord(value))
50
+ return [];
51
+ return Object.entries(value).flatMap(([key, nested]) => SECRET_KEYS.test(key)
52
+ ? [diagnostic('DATASET_EMBEDDED_CREDENTIAL', `credential material is forbidden in contract field ${key}`, `${path}/${key}`)]
53
+ : detectEmbeddedSecrets(nested, `${path}/${key}`));
54
+ }
55
+ function requiredString(record, key, diagnostics) {
56
+ if (typeof record[key] !== 'string' || record[key].length === 0)
57
+ diagnostics.push(diagnostic('DATASET_REQUIRED_FIELD', `${key} must be a non-empty string`, `/${key}`));
58
+ }
59
+ export function validateDatasetContract(value) {
60
+ if (!isRecord(value))
61
+ return { valid: false, diagnostics: [diagnostic('DATASET_CONTRACT_INVALID', 'contract must be an object')] };
62
+ validateSerializedContract(value);
63
+ const diagnostics = (validateSerializedContract.errors ?? []).map((error) => diagnostic('DATASET_SCHEMA_INVALID', error.message ?? 'schema validation failed', error.instancePath || '/'));
64
+ diagnostics.push(...detectEmbeddedSecrets(value));
65
+ requiredString(value, 'contractVersion', diagnostics);
66
+ requiredString(value, 'kind', diagnostics);
67
+ requiredString(value, 'id', diagnostics);
68
+ if (value.contractVersion !== DATASET_CONTRACT_VERSION)
69
+ diagnostics.push(diagnostic('DATASET_CONTRACT_VERSION_UNSUPPORTED', `unsupported contract version ${String(value.contractVersion)}; expected ${DATASET_CONTRACT_VERSION}`, '/contractVersion'));
70
+ if (typeof value.kind !== 'string' || !CONTRACT_KINDS.has(value.kind))
71
+ diagnostics.push(diagnostic('DATASET_CONTRACT_KIND_UNKNOWN', `unknown contract kind ${String(value.kind)}`, '/kind'));
72
+ if (value.kind === 'Dataset' && value.id !== value.logicalId)
73
+ diagnostics.push(diagnostic('DATASET_LOGICAL_ID_MISMATCH', 'Dataset id must equal its stable logicalId', '/logicalId'));
74
+ if (value.kind === 'DatasetRevision') {
75
+ if (value.id === value.datasetId)
76
+ diagnostics.push(diagnostic('DATASET_IDENTITY_CONFLATED', 'revision identity must differ from logical dataset identity', '/id'));
77
+ if (value.id !== value.revisionId)
78
+ diagnostics.push(diagnostic('DATASET_REVISION_ID_MISMATCH', 'DatasetRevision id must equal revisionId', '/revisionId'));
79
+ }
80
+ if (value.kind === 'ProcessingPlan') {
81
+ if (!Array.isArray(value.steps) || value.steps.length === 0)
82
+ diagnostics.push(diagnostic('DATASET_PLAN_EMPTY', 'processing plan requires at least one step', '/steps'));
83
+ }
84
+ if (value.kind === 'ProcessingRun' || value.kind === 'RunReceipt') {
85
+ if (!RUN_OUTCOMES.has(String(value.outcome)))
86
+ diagnostics.push(diagnostic('DATASET_RUN_OUTCOME_INVALID', 'run outcome is invalid', '/outcome'));
87
+ }
88
+ if (value.kind === 'RunReceipt') {
89
+ const committed = value.committed === true;
90
+ if (committed !== (value.outcome === 'committed'))
91
+ diagnostics.push(diagnostic('DATASET_RECEIPT_OUTCOME_CONFLICT', 'committed is true exactly when outcome is committed', '/committed'));
92
+ if (typeof value.committedRecords === 'number' && typeof value.attemptedRecords === 'number' && value.committedRecords > value.attemptedRecords)
93
+ diagnostics.push(diagnostic('DATASET_RECEIPT_COUNT_INVALID', 'committedRecords cannot exceed attemptedRecords', '/committedRecords'));
94
+ if (typeof value.rejectedRecords === 'number' && typeof value.attemptedRecords === 'number' && value.rejectedRecords > value.attemptedRecords)
95
+ diagnostics.push(diagnostic('DATASET_RECEIPT_COUNT_INVALID', 'rejectedRecords cannot exceed attemptedRecords', '/rejectedRecords'));
96
+ }
97
+ if ((value.kind === 'Relationship' || value.kind === 'ProvenanceAssertion') && value.basis === 'observed' && typeof value.runId !== 'string')
98
+ diagnostics.push(diagnostic('DATASET_OBSERVED_LINEAGE_RUN_REQUIRED', 'observed lineage requires runId', '/runId'));
99
+ return diagnostics.length ? { valid: false, diagnostics } : { valid: true, value: value, diagnostics: [] };
100
+ }
101
+ export function canonicalDatasetJson(value) {
102
+ const visit = (item) => {
103
+ if (Array.isArray(item))
104
+ return item.map(visit);
105
+ if (!isRecord(item))
106
+ return item;
107
+ return Object.fromEntries(Object.keys(item).sort().map((key) => [key, visit(item[key])]));
108
+ };
109
+ return JSON.stringify(visit(value));
110
+ }
111
+ export function datasetDigest(value) {
112
+ return { algorithm: 'sha256', value: createHash('sha256').update(canonicalDatasetJson(value)).digest('hex') };
113
+ }
114
+ function withoutDigest(plan) {
115
+ const { planDigest: _planDigest, ...declaration } = plan;
116
+ return declaration;
117
+ }
118
+ function receiptWithoutDigest(receipt) {
119
+ const { receiptDigest: _receiptDigest, ...observation } = receipt;
120
+ return observation;
121
+ }
122
+ export function computeProcessingPlanDigest(plan) {
123
+ return datasetDigest(withoutDigest(plan));
124
+ }
125
+ export function verifyProcessingPlanDigest(plan) {
126
+ return plan.planDigest.algorithm === 'sha256' && plan.planDigest.value === computeProcessingPlanDigest(plan).value;
127
+ }
128
+ export function computeRunReceiptDigest(receipt) {
129
+ return datasetDigest(receiptWithoutDigest(receipt));
130
+ }
131
+ export function verifyRunReceiptDigest(receipt) {
132
+ return receipt.receiptDigest.algorithm === 'sha256' && receipt.receiptDigest.value === computeRunReceiptDigest(receipt).value;
133
+ }
134
+ export function negotiateDatasetCapabilities(profile, available) {
135
+ const offered = new Map(available.map((capability) => typeof capability === 'string' ? [capability, undefined] : [capability.name, capability.version]));
136
+ const satisfied = [];
137
+ const degraded = [];
138
+ for (const capability of profile.capabilities) {
139
+ const offeredVersion = offered.get(capability.name);
140
+ const versionAccepted = !capability.acceptedVersions?.length || (offeredVersion !== undefined && capability.acceptedVersions.includes(offeredVersion));
141
+ if (offered.has(capability.name) && versionAccepted) {
142
+ satisfied.push(capability.name);
143
+ continue;
144
+ }
145
+ if (capability.requirement === 'required' || capability.degradation.action === 'fail')
146
+ throw new DatasetContractError('DATASET_REQUIRED_CAPABILITY_UNSUPPORTED', `required capability is unavailable: ${capability.name}`);
147
+ const action = capability.degradation.action;
148
+ if (action === 'disable')
149
+ degraded.push({ capability: capability.name, action });
150
+ else
151
+ degraded.push({ capability: capability.name, action, ...(capability.degradation.fallbackCapability ? { fallbackCapability: capability.degradation.fallbackCapability } : {}) });
152
+ }
153
+ return { contractVersion: DATASET_CONTRACT_VERSION, satisfied: satisfied.sort(), degraded: degraded.sort((a, b) => a.capability.localeCompare(b.capability)) };
154
+ }
155
+ /** Validate identity references across a complete contract bundle. */
156
+ export function validateDatasetContractSet(contracts) {
157
+ const diagnostics = [];
158
+ const ids = new Set();
159
+ for (const contract of contracts) {
160
+ if (ids.has(contract.id))
161
+ diagnostics.push(diagnostic('DATASET_ID_DUPLICATE', `duplicate contract identity ${contract.id}`));
162
+ ids.add(contract.id);
163
+ }
164
+ const requireReference = (owner, target, field) => {
165
+ if (target && !ids.has(target))
166
+ diagnostics.push(diagnostic('DATASET_REFERENCE_DANGLING', `${owner.kind} ${owner.id} references unknown identity ${target}`, `/${field}`));
167
+ };
168
+ for (const contract of contracts) {
169
+ switch (contract.kind) {
170
+ case 'DatasetRevision':
171
+ requireReference(contract, contract.datasetId, 'datasetId');
172
+ for (const sourceId of contract.sourceIds)
173
+ requireReference(contract, sourceId, 'sourceIds');
174
+ break;
175
+ case 'Distribution':
176
+ requireReference(contract, contract.datasetRevisionId, 'datasetRevisionId');
177
+ break;
178
+ case 'ProcessingPlan':
179
+ requireReference(contract, contract.datasetRevisionId, 'datasetRevisionId');
180
+ requireReference(contract, contract.capabilityProfileId, 'capabilityProfileId');
181
+ break;
182
+ case 'ProcessingRun':
183
+ requireReference(contract, contract.planId, 'planId');
184
+ break;
185
+ case 'DerivedArtifact':
186
+ requireReference(contract, contract.sourceRevisionId, 'sourceRevisionId');
187
+ requireReference(contract, contract.runId, 'runId');
188
+ break;
189
+ case 'ProvenanceAssertion':
190
+ requireReference(contract, contract.subjectId, 'subjectId');
191
+ requireReference(contract, contract.objectId, 'objectId');
192
+ requireReference(contract, contract.sourceRevisionId, 'sourceRevisionId');
193
+ requireReference(contract, contract.runId, 'runId');
194
+ break;
195
+ case 'Relationship':
196
+ requireReference(contract, contract.sourceId, 'sourceId');
197
+ requireReference(contract, contract.targetId, 'targetId');
198
+ requireReference(contract, contract.sourceRevisionId, 'sourceRevisionId');
199
+ requireReference(contract, contract.runId, 'runId');
200
+ break;
201
+ case 'Checkpoint':
202
+ requireReference(contract, contract.sourceId, 'sourceId');
203
+ requireReference(contract, contract.priorCommittedReceiptId, 'priorCommittedReceiptId');
204
+ break;
205
+ case 'RunReceipt':
206
+ requireReference(contract, contract.runId, 'runId');
207
+ requireReference(contract, contract.planId, 'planId');
208
+ requireReference(contract, contract.checkpointBeforeId, 'checkpointBeforeId');
209
+ requireReference(contract, contract.checkpointAfterId, 'checkpointAfterId');
210
+ requireReference(contract, contract.priorCommittedReceiptId, 'priorCommittedReceiptId');
211
+ break;
212
+ default: break;
213
+ }
214
+ }
215
+ return diagnostics;
216
+ }
217
+ export function validateCheckpointAncestry(checkpoint, prior) {
218
+ if (!checkpoint.priorCommittedReceiptId)
219
+ return [];
220
+ if (!prior || prior.id !== checkpoint.priorCommittedReceiptId)
221
+ return [diagnostic('DATASET_CHECKPOINT_ANCESTRY_MISSING', 'checkpoint prior committed receipt is unavailable', '/priorCommittedReceiptId')];
222
+ if (!prior.committed || prior.outcome !== 'committed')
223
+ return [diagnostic('DATASET_CHECKPOINT_ANCESTRY_UNCOMMITTED', 'checkpoint ancestry must reference a committed receipt', '/priorCommittedReceiptId')];
224
+ if (prior.planDigest.value !== checkpoint.planDigest.value)
225
+ return [diagnostic('DATASET_CHECKPOINT_PLAN_MISMATCH', 'checkpoint and prior receipt plan digests differ', '/planDigest')];
226
+ return [];
227
+ }
228
+ export class DatasetContractError extends Error {
229
+ code;
230
+ constructor(code, message) {
231
+ super(message);
232
+ this.code = code;
233
+ this.name = 'DatasetContractError';
234
+ }
235
+ }
236
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1,19 @@
1
+ import type { ProcessingPlan } from "./types.js";
2
+ import type { DatasetRunState, RegisteredSource } from "./orchestration-types.js";
3
+ import type { DatasetOrchestrationRepository } from "./orchestration-repository.js";
4
+ export declare class FileDatasetOrchestrationRepository implements DatasetOrchestrationRepository {
5
+ readonly path: string;
6
+ constructor(root: string);
7
+ private read;
8
+ private update;
9
+ getSource(id: string): Promise<RegisteredSource>;
10
+ putSource(v: RegisteredSource): Promise<void>;
11
+ getPlan(id: string): Promise<ProcessingPlan>;
12
+ putPlan(v: ProcessingPlan): Promise<void>;
13
+ getRun(id: string): Promise<DatasetRunState>;
14
+ getRunByIdempotency(k: string): Promise<DatasetRunState | undefined>;
15
+ putRun(v: DatasetRunState): Promise<void>;
16
+ listArtifactRecords(id: string): Promise<readonly unknown[]>;
17
+ putArtifactRecords(id: string, v: readonly unknown[]): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=file-orchestration-repository.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ const empty = () => ({
4
+ sources: {},
5
+ plans: {},
6
+ runs: {},
7
+ artifacts: {},
8
+ });
9
+ export class FileDatasetOrchestrationRepository {
10
+ path;
11
+ constructor(root) {
12
+ this.path = join(resolve(root), ".aiwg", "dataset", "state.v1.json");
13
+ }
14
+ async read() {
15
+ try {
16
+ return JSON.parse(await readFile(this.path, "utf8"));
17
+ }
18
+ catch (e) {
19
+ if (e.code === "ENOENT")
20
+ return empty();
21
+ throw e;
22
+ }
23
+ }
24
+ async update(fn) {
25
+ const s = await this.read();
26
+ fn(s);
27
+ await mkdir(dirname(this.path), { recursive: true });
28
+ const tmp = `${this.path}.${process.pid}.tmp`;
29
+ await writeFile(tmp, JSON.stringify(s, null, 2) + "\n", { mode: 0o600 });
30
+ await rename(tmp, this.path);
31
+ }
32
+ async getSource(id) {
33
+ return (await this.read()).sources[id];
34
+ }
35
+ async putSource(v) {
36
+ await this.update((s) => {
37
+ s.sources[v.id] = v;
38
+ });
39
+ }
40
+ async getPlan(id) {
41
+ return (await this.read()).plans[id];
42
+ }
43
+ async putPlan(v) {
44
+ await this.update((s) => {
45
+ s.plans[v.id] = v;
46
+ });
47
+ }
48
+ async getRun(id) {
49
+ return (await this.read()).runs[id];
50
+ }
51
+ async getRunByIdempotency(k) {
52
+ return Object.values((await this.read()).runs).find((v) => v.idempotencyKey === k);
53
+ }
54
+ async putRun(v) {
55
+ await this.update((s) => {
56
+ s.runs[v.runId] = v;
57
+ });
58
+ }
59
+ async listArtifactRecords(id) {
60
+ return (await this.read()).artifacts[id] ?? [];
61
+ }
62
+ async putArtifactRecords(id, v) {
63
+ await this.update((s) => {
64
+ s.artifacts[id] = v;
65
+ });
66
+ }
67
+ }
68
+ //# sourceMappingURL=file-orchestration-repository.js.map
@@ -0,0 +1,33 @@
1
+ import type { DatasetExecutionBackend, ExecutionRequest, ExecutionResult } from "./orchestration-types.js";
2
+ import type { RunReceipt } from "./types.js";
3
+ export interface FortemiTransport {
4
+ capabilities(): Promise<readonly {
5
+ name: string;
6
+ version: string;
7
+ }[]>;
8
+ execute(request: {
9
+ plan: unknown;
10
+ records: readonly unknown[];
11
+ signal?: AbortSignal;
12
+ }): Promise<{
13
+ result: ExecutionResult;
14
+ receipt: RunReceipt;
15
+ }>;
16
+ }
17
+ export declare class FortemiExecutionBridge implements DatasetExecutionBackend {
18
+ private readonly transport?;
19
+ readonly id = "fortemi-core";
20
+ private offered;
21
+ constructor(transport?: FortemiTransport | undefined);
22
+ capabilities(): readonly {
23
+ name: string;
24
+ version: string;
25
+ }[];
26
+ negotiate(): Promise<readonly {
27
+ name: string;
28
+ version: string;
29
+ }[]>;
30
+ execute(r: ExecutionRequest): Promise<ExecutionResult>;
31
+ }
32
+ export declare function sealFortemiFixtureReceipt(receipt: RunReceipt): RunReceipt;
33
+ //# sourceMappingURL=fortemi-execution-bridge.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { computeRunReceiptDigest, verifyRunReceiptDigest, } from "./contracts.js";
2
+ export class FortemiExecutionBridge {
3
+ transport;
4
+ id = "fortemi-core";
5
+ offered = [];
6
+ constructor(transport) {
7
+ this.transport = transport;
8
+ }
9
+ capabilities() {
10
+ return this.offered;
11
+ }
12
+ async negotiate() {
13
+ if (!this.transport)
14
+ throw new Error("DATASET_FORTEMI_UNAVAILABLE: injected Fortemi transport required");
15
+ this.offered = await this.transport.capabilities();
16
+ return this.offered;
17
+ }
18
+ async execute(r) {
19
+ if (!this.transport)
20
+ throw new Error("DATASET_FORTEMI_UNAVAILABLE: injected Fortemi transport required");
21
+ const response = await this.transport.execute({
22
+ plan: r.plan,
23
+ records: r.records,
24
+ signal: r.signal,
25
+ });
26
+ if (response.receipt.planDigest.value !== r.plan.planDigest.value ||
27
+ !verifyRunReceiptDigest(response.receipt))
28
+ throw new Error("DATASET_FORTEMI_RECEIPT_INVALID");
29
+ return response.result;
30
+ }
31
+ }
32
+ export function sealFortemiFixtureReceipt(receipt) {
33
+ return { ...receipt, receiptDigest: computeRunReceiptDigest(receipt) };
34
+ }
35
+ //# sourceMappingURL=fortemi-execution-bridge.js.map
@@ -0,0 +1,21 @@
1
+ export * from './types.js';
2
+ export * from './contracts.js';
3
+ export * from './schema-governance.js';
4
+ export * from './ledger-types.js';
5
+ export * from './ledger.js';
6
+ export * from './projections.js';
7
+ export * from './standards-types.js';
8
+ export * from './standards.js';
9
+ export * from './adapter-types.js';
10
+ export * from './adapter-sdk.js';
11
+ export * from './adapters.js';
12
+ export * from './orchestration-types.js';
13
+ export * from './orchestration-repository.js';
14
+ export * from './file-orchestration-repository.js';
15
+ export * from './local-execution-backend.js';
16
+ export * from './fortemi-execution-bridge.js';
17
+ export * from './orchestration-service.js';
18
+ export * from './presentation.js';
19
+ export * from './conformance-types.js';
20
+ export * from './conformance.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,21 @@
1
+ export * from './types.js';
2
+ export * from './contracts.js';
3
+ export * from './schema-governance.js';
4
+ export * from './ledger-types.js';
5
+ export * from './ledger.js';
6
+ export * from './projections.js';
7
+ export * from './standards-types.js';
8
+ export * from './standards.js';
9
+ export * from './adapter-types.js';
10
+ export * from './adapter-sdk.js';
11
+ export * from './adapters.js';
12
+ export * from './orchestration-types.js';
13
+ export * from './orchestration-repository.js';
14
+ export * from './file-orchestration-repository.js';
15
+ export * from './local-execution-backend.js';
16
+ export * from './fortemi-execution-bridge.js';
17
+ export * from './orchestration-service.js';
18
+ export * from './presentation.js';
19
+ export * from './conformance-types.js';
20
+ export * from './conformance.js';
21
+ //# sourceMappingURL=index.js.map