@aiwg/cli 2026.9.24 → 2026.10.1
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/capability-matrix.yaml +2 -1
- package/dist/src/artifacts/discovery-shadow-evaluator.js +177 -0
- package/dist/src/artifacts/discovery-shadow.js +195 -0
- package/dist/src/artifacts/index-builder.js +47 -9
- package/dist/src/artifacts/query-engine.js +94 -1
- package/dist/src/artifacts/types.js +1 -0
- package/dist/src/cli/handlers/decision.js +177 -0
- package/dist/src/cli/handlers/gates.js +154 -0
- package/dist/src/cli/handlers/index.js +5 -1
- package/dist/src/cli/handlers/sessions.js +10 -7
- package/dist/src/cli/handlers/utilities.js +20 -0
- package/dist/src/config/aiwg-config.js +15 -2
- package/dist/src/decision/acceptance.js +25 -0
- package/dist/src/decision/adapters/jev.js +29 -3
- package/dist/src/decision/ask.js +352 -0
- package/dist/src/decision/calibration/registry.js +9 -0
- package/dist/src/decision/compose.js +74 -15
- package/dist/src/decision/context-live-promotion.js +344 -0
- package/dist/src/decision/context-live-qualification.js +591 -0
- package/dist/src/decision/context-pruning.js +847 -0
- package/dist/src/decision/driver.js +432 -0
- package/dist/src/decision/egress-live-qualification.js +874 -0
- package/dist/src/decision/ensemble/contract.js +64 -1
- package/dist/src/decision/ensemble/index.js +1 -0
- package/dist/src/decision/ensemble/report.js +8 -42
- package/dist/src/decision/ensemble/runtime.js +571 -0
- package/dist/src/decision/ensemble-study/artifacts.js +85 -0
- package/dist/src/decision/ensemble-study/calibration.js +443 -0
- package/dist/src/decision/ensemble-study/corpus.js +229 -0
- package/dist/src/decision/ensemble-study/multifact-artifacts.js +23 -0
- package/dist/src/decision/ensemble-study/multifact-study.js +596 -0
- package/dist/src/decision/ensemble-study/multifact.js +241 -0
- package/dist/src/decision/ensemble-study/protocol.js +77 -0
- package/dist/src/decision/ensemble-study/score.js +462 -0
- package/dist/src/decision/ensemble-study/staged.js +87 -0
- package/dist/src/decision/ensemble-study/statistics.js +84 -0
- package/dist/src/decision/evaluate.js +227 -14
- package/dist/src/decision/export.js +4 -0
- package/dist/src/decision/feature-export.js +1074 -0
- package/dist/src/decision/graph-index.js +16 -0
- package/dist/src/decision/graph-live-qualification.js +1041 -0
- package/dist/src/decision/graph-live-workload.js +245 -0
- package/dist/src/decision/graph-skill-bridge.js +21 -3
- package/dist/src/decision/heldout/calibration.js +140 -0
- package/dist/src/decision/heldout/collector.js +430 -0
- package/dist/src/decision/heldout/contract.js +309 -0
- package/dist/src/decision/heldout/d29-generator-ids.js +12 -0
- package/dist/src/decision/heldout/d29-passage-baseline-v2.js +93 -0
- package/dist/src/decision/heldout/d29-passage-baseline-v3.js +100 -0
- package/dist/src/decision/heldout/d29-passage-baseline.js +66 -0
- package/dist/src/decision/heldout/d29-pools-v8.js +575 -0
- package/dist/src/decision/heldout/d29-pools.js +288 -0
- package/dist/src/decision/heldout/d29-v6.js +169 -0
- package/dist/src/decision/heldout/d29-v7.js +202 -0
- package/dist/src/decision/heldout/d29-v8.js +586 -0
- package/dist/src/decision/heldout/generator-registry.js +67 -0
- package/dist/src/decision/heldout/generators.js +696 -0
- package/dist/src/decision/heldout/index.js +8 -0
- package/dist/src/decision/heldout/journal.js +346 -0
- package/dist/src/decision/heldout/study-generators.js +64 -0
- package/dist/src/decision/heldout/types.js +2 -0
- package/dist/src/decision/host-policy.js +61 -0
- package/dist/src/decision/index.js +13 -0
- package/dist/src/decision/interop-profile.v1.json +112 -0
- package/dist/src/decision/interop.js +653 -0
- package/dist/src/decision/issue-triage/index.js +3 -0
- package/dist/src/decision/issue-triage/runtime.js +1069 -0
- package/dist/src/decision/issue-triage/types.js +2 -0
- package/dist/src/decision/jev-credentials.js +121 -0
- package/dist/src/decision/patterns/catalog.js +28 -8
- package/dist/src/decision/patterns/playground.js +28 -11
- package/dist/src/decision/patterns/specs.js +19 -10
- package/dist/src/decision/preprocessed-evidence.js +724 -0
- package/dist/src/decision/qualification/capture.js +8 -2
- package/dist/src/decision/qualification/gate-evidence.js +19 -4
- package/dist/src/decision/qualification/quality.js +57 -49
- package/dist/src/decision/qualification/release.js +76 -3
- package/dist/src/decision/qualification/runner.js +5 -2
- package/dist/src/decision/routing/contract.js +175 -0
- package/dist/src/decision/routing/index.js +5 -0
- package/dist/src/decision/routing/report.js +216 -0
- package/dist/src/decision/routing/runtime.js +685 -0
- package/dist/src/decision/routing/types.js +2 -0
- package/dist/src/decision/sdlc-screening.js +1157 -0
- package/dist/src/decision/sensitivity/comparative.js +154 -0
- package/dist/src/decision/sensitivity/contract.js +218 -0
- package/dist/src/decision/sensitivity/index.js +5 -0
- package/dist/src/decision/sensitivity/runtime.js +912 -0
- package/dist/src/decision/sensitivity/types.js +2 -0
- package/dist/src/decision/validate.js +26 -0
- package/dist/src/extensions/commands/definitions.js +38 -0
- package/dist/src/extensions/manifest.js +44 -0
- package/dist/src/gates/discovery.js +315 -0
- package/dist/src/gates/driver.js +388 -0
- package/dist/src/gates/evaluate.js +719 -0
- package/dist/src/gates/floors.js +255 -0
- package/dist/src/gates/index.js +17 -0
- package/dist/src/gates/providers/evidence.js +38 -0
- package/dist/src/gates/providers/index.js +21 -0
- package/dist/src/gates/providers/isolated-child-source.js +446 -0
- package/dist/src/gates/providers/loader.js +1069 -0
- package/dist/src/gates/providers/paired.js +52 -0
- package/dist/src/gates/providers/proportion.js +60 -0
- package/dist/src/gates/providers/registry.js +40 -0
- package/dist/src/gates/providers/scalar.js +41 -0
- package/dist/src/gates/providers/screening.js +53 -0
- package/dist/src/gates/providers/types.js +25 -0
- package/dist/src/gates/registry.js +1003 -0
- package/dist/src/gates/report.js +102 -0
- package/dist/src/gates/schema.js +56 -0
- package/dist/src/gates/stats/binomial.js +26 -0
- package/dist/src/gates/stats/bootstrap.js +62 -0
- package/dist/src/gates/stats/clopper-pearson.js +95 -0
- package/dist/src/gates/stats/digest.js +26 -0
- package/dist/src/gates/stats/error.js +5 -0
- package/dist/src/gates/stats/index.js +9 -0
- package/dist/src/gates/stats/normal.js +35 -0
- package/dist/src/gates/stats/paired.js +120 -0
- package/dist/src/gates/stats/splits.js +30 -0
- package/dist/src/gates/types.js +8 -0
- package/dist/src/governance/redaction.js +14 -4
- package/dist/src/mcp/muse-native-config.mjs +123 -0
- package/dist/src/mcp/tools/decision.mjs +228 -0
- package/dist/src/mcp/tools/subsystems.mjs +2 -0
- package/dist/src/providers/capability-matrix.yaml +2 -1
- package/dist/src/providers/provider-definitions.js +2 -1
- package/dist/src/sessions/adapters/muse.js +336 -39
- package/dist/src/sessions/batch-import.js +7 -0
- package/dist/src/sessions/workspace-discovery.js +13 -2
- package/package.json +1 -1
- package/schemas/decision/ConformalFrozenOpenData.v2.schema.json +371 -0
- package/schemas/decision/ConformalOpenDataReport.v2.schema.json +421 -0
- package/schemas/decision/ConformalPreregistration.v2.schema.json +529 -0
- package/schemas/decision/ContextPruningCandidate.v1.schema.json +47 -0
- package/schemas/decision/ContextPruningEvaluationReport.v1.schema.json +758 -0
- package/schemas/decision/ContextPruningPreregistration.v1.schema.json +175 -0
- package/schemas/decision/ContextPruningReceipt.v1.schema.json +72 -0
- package/schemas/decision/D17Multifact.v1.schema.json +1851 -0
- package/schemas/decision/D17StudyAnalysis.v1.schema.json +42 -0
- package/schemas/decision/D17StudyAnalysis.v2.schema.json +51 -0
- package/schemas/decision/D17StudyCalibration.v1.schema.json +819 -0
- package/schemas/decision/D17StudyDryRun.v1.schema.json +169 -0
- package/schemas/decision/D17StudyDryRun.v2.schema.json +239 -0
- package/schemas/decision/D17StudyGold.v1.schema.json +108 -0
- package/schemas/decision/D17StudyGuide.v1.schema.json +63 -0
- package/schemas/decision/D17StudyNativeTemplates.v1.schema.json +619 -0
- package/schemas/decision/D17StudyProtocol.v1.schema.json +241 -0
- package/schemas/decision/D17StudyReport.v1.schema.json +902 -0
- package/schemas/decision/D17StudyReport.v2.schema.json +1319 -0
- package/schemas/decision/D17StudyReview.v1.schema.json +175 -0
- package/schemas/decision/D17StudySplits.v1.schema.json +217 -0
- package/schemas/decision/D29Study.v1.schema.json +1903 -0
- package/schemas/decision/D29Study.v2.schema.json +1344 -0
- package/schemas/decision/D29Study.v3.schema.json +609 -0
- package/schemas/decision/D29Study.v4.schema.json +1133 -0
- package/schemas/decision/D29Study.v6.schema.json +1205 -0
- package/schemas/decision/D29Study.v7.schema.json +1471 -0
- package/schemas/decision/D29Study.v8.schema.json +671 -0
- package/schemas/decision/D29Study.v9.schema.json +778 -0
- package/schemas/decision/DecisionComparativeReplayAuditSample.v1.schema.json +137 -0
- package/schemas/decision/DecisionComparativeReplayCorpus.v1.schema.json +258 -0
- package/schemas/decision/DecisionComparativeReplayFreeze.v1.schema.json +74 -0
- package/schemas/decision/DecisionComparativeReplayGold.v1.schema.json +50 -0
- package/schemas/decision/DecisionComparativeReplayGoldAsset.v1.schema.json +37 -0
- package/schemas/decision/DecisionComparativeReplayIntegrity.v1.schema.json +81 -0
- package/schemas/decision/DecisionComparativeReplayMembers.v1.schema.json +52 -0
- package/schemas/decision/DecisionComparativeReplayPreregistration.v1.schema.json +113 -0
- package/schemas/decision/DecisionComparativeReplayReport.v1.schema.json +407 -0
- package/schemas/decision/DecisionComparativeReplayReviewPackets.v1.schema.json +260 -0
- package/schemas/decision/DecisionComparativeReplaySplit.v1.schema.json +84 -0
- package/schemas/decision/DecisionFeatureObservation.v1.schema.json +564 -0
- package/schemas/decision/DecisionFeatureSet.v1.schema.json +155 -0
- package/schemas/decision/DecisionInteropMapping.v1.schema.json +85 -0
- package/schemas/decision/DecisionIssueTriageEvaluationManifest.v1.schema.json +174 -0
- package/schemas/decision/DecisionIssueTriageEvaluationReport.v1.schema.json +280 -0
- package/schemas/decision/DecisionIssueTriagePilotPack.v1.schema.json +114 -0
- package/schemas/decision/DecisionRouteReceipt.v1.schema.json +155 -0
- package/schemas/decision/DecisionRoutingPolicy.v1.schema.json +132 -0
- package/schemas/decision/DecisionRoutingShadowReport.v1.schema.json +170 -0
- package/schemas/decision/DecisionRoutingTask.v1.schema.json +49 -0
- package/schemas/decision/DecisionRuleset.schema.json +8 -2
- package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +8 -2
- package/schemas/decision/DecisionSensitivityPlan.v1.schema.json +191 -0
- package/schemas/decision/DecisionSensitivityReport.v1.schema.json +163 -0
- package/schemas/decision/HeldoutApproval.v1.schema.json +312 -0
- package/schemas/decision/HeldoutAttempt.v1.schema.json +211 -0
- package/schemas/decision/HeldoutBaseline.v1.schema.json +90 -0
- package/schemas/decision/HeldoutCalibrationPhase.v1.schema.json +87 -0
- package/schemas/decision/HeldoutCorpus.v1.schema.json +167 -0
- package/schemas/decision/HeldoutEvent.v1.schema.json +41 -0
- package/schemas/decision/HeldoutFrozen.v1.schema.json +142 -0
- package/schemas/decision/HeldoutPreregistration.v1.schema.json +222 -0
- package/schemas/decision/HeldoutSpendEvent.v1.schema.json +122 -0
- package/schemas/decision/HeldoutSpendHead.v1.schema.json +25 -0
- package/schemas/decision/HeldoutSpendHead.v2.schema.json +46 -0
- package/schemas/decision/HeldoutSummary.v1.schema.json +101 -0
- package/schemas/decision/OpaDecisionLogExport.v1.schema.json +65 -0
- package/schemas/decision/PreprocessedEvidence.v1.schema.json +306 -0
- package/schemas/decision/RulesetResult.v1alpha2.schema.json +175 -0
- package/schemas/decision/SdlcEvidenceScreening.v1.schema.json +499 -0
- package/schemas/decision/SdlcScreeningPreregistration.v1.schema.json +132 -0
- package/schemas/decision/SdlcScreeningPreregistration.v2.schema.json +138 -0
- package/schemas/decision/SdlcScreeningRelease.v1.schema.json +654 -0
- package/schemas/decision/SdlcScreeningRelease.v2.schema.json +654 -0
- package/tools/agents/deploy-agents.mjs +1 -1
- package/tools/agents/providers/base.mjs +40 -18
- package/tools/agents/providers/factory.mjs +10 -2
- package/tools/agents/providers/muse-hooks.mjs +1 -29
- package/tools/agents/providers/muse.mjs +6 -3
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
import { askDecision, setupJev, DecisionAskUsageError, readDecisionContextFile, validateDecisionAskInput, } from './ask.js';
|
|
6
|
+
import { assertDecisionEvaluateDispatcherConfig, decisionPatternPacks, getDecisionPatternPack, governedPatternArtifacts, listDecisionPatterns, patternInputSchema, patternOutputSchema, planLiveDecisionPattern, runOfflineDecisionPattern, validateAgainstSchema, validateDecisionDocument, validateDefinition, validateRuleset, } from './index.js';
|
|
7
|
+
export { askDecision, setupJev, readDecisionContextFile, validateDecisionAskInput, DecisionAskUsageError, };
|
|
8
|
+
const DECISION_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
const VALIDATION_TARGETS = ['request', 'definition', 'ruleset', 'binding'];
|
|
10
|
+
const OFFLINE_ADAPTER = 'agentic/code/addons/decision-engine/examples/fixture-jev-adapter.mjs';
|
|
11
|
+
function getPackageRoot(start = DECISION_ROOT) {
|
|
12
|
+
let current = start;
|
|
13
|
+
while (true) {
|
|
14
|
+
if (existsSync(path.join(current, 'package.json')) && existsSync(path.join(current, 'agentic/code/addons/decision-engine'))) {
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
const parent = path.dirname(current);
|
|
18
|
+
if (parent === current)
|
|
19
|
+
return path.dirname(DECISION_ROOT);
|
|
20
|
+
current = parent;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
function driverEnv(options) {
|
|
27
|
+
return { ...process.env, ...(options.env ?? {}) };
|
|
28
|
+
}
|
|
29
|
+
function frameworkRoot(options) {
|
|
30
|
+
return path.resolve(options.frameworkRoot ?? getPackageRoot());
|
|
31
|
+
}
|
|
32
|
+
function resolvePath(candidate, base) {
|
|
33
|
+
if (!candidate)
|
|
34
|
+
throw new Error('Path is required');
|
|
35
|
+
return path.resolve(base, candidate);
|
|
36
|
+
}
|
|
37
|
+
function isSafeHostReference(value) {
|
|
38
|
+
return /^[A-Za-z0-9_.-]+$/.test(value) && value !== '.' && value !== '..' && !value.includes('..');
|
|
39
|
+
}
|
|
40
|
+
function isEnvironmentReference(value) {
|
|
41
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
42
|
+
}
|
|
43
|
+
function validateHostReferenceMap(value, field, valueLabel, validateValue) {
|
|
44
|
+
if (!isRecord(value))
|
|
45
|
+
return [`${field} must be an object of safe logical references to ${valueLabel}`];
|
|
46
|
+
const errors = [];
|
|
47
|
+
for (const [key, candidate] of Object.entries(value)) {
|
|
48
|
+
if (!isSafeHostReference(key))
|
|
49
|
+
errors.push(`${field} keys must be safe logical references`);
|
|
50
|
+
if (typeof candidate !== 'string' || !candidate || !validateValue(candidate))
|
|
51
|
+
errors.push(`${field} values must be ${valueLabel}`);
|
|
52
|
+
}
|
|
53
|
+
return [...new Set(errors)];
|
|
54
|
+
}
|
|
55
|
+
async function readJson(filePath) {
|
|
56
|
+
try {
|
|
57
|
+
return { value: JSON.parse(await readFile(filePath, 'utf8')) };
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof SyntaxError)
|
|
61
|
+
return { error: 'invalid-json' };
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function requestSchemaErrors(value) {
|
|
66
|
+
const errors = [];
|
|
67
|
+
if (!isRecord(value))
|
|
68
|
+
return ['request must be an object'];
|
|
69
|
+
try {
|
|
70
|
+
assertDecisionEvaluateDispatcherConfig(value);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
errors.push(error instanceof Error ? error.message : 'invalid-request-config');
|
|
74
|
+
}
|
|
75
|
+
for (const key of ['rulesetPath', 'bindingPath', 'inputPath']) {
|
|
76
|
+
if (typeof value[key] !== 'string' || !value[key])
|
|
77
|
+
errors.push(`${key} must be a non-empty string`);
|
|
78
|
+
}
|
|
79
|
+
if (value.definitionPaths !== undefined
|
|
80
|
+
&& (!Array.isArray(value.definitionPaths) || value.definitionPaths.some(item => typeof item !== 'string' || !item))) {
|
|
81
|
+
errors.push('definitionPaths must be an array of non-empty strings');
|
|
82
|
+
}
|
|
83
|
+
if (value.adapterModules !== undefined)
|
|
84
|
+
errors.push(...validateHostReferenceMap(value.adapterModules, 'adapterModules', 'non-empty module paths', candidate => Boolean(candidate)));
|
|
85
|
+
if (value.credentials !== undefined)
|
|
86
|
+
errors.push(...validateHostReferenceMap(value.credentials, 'credentials', 'environment variable names', isEnvironmentReference));
|
|
87
|
+
if (value.receiptIntegrityKeyRef !== undefined
|
|
88
|
+
&& (typeof value.receiptIntegrityKeyRef !== 'string' || !isSafeHostReference(value.receiptIntegrityKeyRef))) {
|
|
89
|
+
errors.push('receiptIntegrityKeyRef must be a safe logical reference');
|
|
90
|
+
}
|
|
91
|
+
if (value.receiptIntegrityKeyRef !== undefined && isRecord(value.credentials)
|
|
92
|
+
&& typeof value.receiptIntegrityKeyRef === 'string' && !Object.hasOwn(value.credentials, value.receiptIntegrityKeyRef)) {
|
|
93
|
+
errors.push('receiptIntegrityKeyRef must refer to a configured credential logical reference');
|
|
94
|
+
}
|
|
95
|
+
return errors;
|
|
96
|
+
}
|
|
97
|
+
function normalizeDecisionStatus(status, reason) {
|
|
98
|
+
if (status === 'success')
|
|
99
|
+
return 'success';
|
|
100
|
+
if (status === 'abstained')
|
|
101
|
+
return 'abstained';
|
|
102
|
+
if (status === 'cancelled')
|
|
103
|
+
return 'cancelled';
|
|
104
|
+
if (reason === 'data-boundary-denied' || reason === 'unauthorized' || reason === 'authentication')
|
|
105
|
+
return 'denied';
|
|
106
|
+
if (reason === 'executor-unavailable' || reason === 'unsupported-capability' || status === 'unsupported')
|
|
107
|
+
return 'unavailable';
|
|
108
|
+
return 'error';
|
|
109
|
+
}
|
|
110
|
+
function normalizeRulesetStatus(status, reason, evaluations = []) {
|
|
111
|
+
if (status === 'completed' || status === 'defaulted') {
|
|
112
|
+
if (evaluations.some(value => value === 'success'))
|
|
113
|
+
return 'success';
|
|
114
|
+
if (evaluations.some(value => value === 'denied'))
|
|
115
|
+
return 'denied';
|
|
116
|
+
if (evaluations.some(value => value === 'unavailable'))
|
|
117
|
+
return 'unavailable';
|
|
118
|
+
if (evaluations.some(value => value === 'abstained'))
|
|
119
|
+
return 'abstained';
|
|
120
|
+
if (evaluations.length > 0)
|
|
121
|
+
return 'error';
|
|
122
|
+
return 'success';
|
|
123
|
+
}
|
|
124
|
+
if (status === 'review')
|
|
125
|
+
return 'abstained';
|
|
126
|
+
if (status === 'cancelled')
|
|
127
|
+
return 'cancelled';
|
|
128
|
+
if (reason === 'data-boundary-denied' || reason === 'unauthorized' || reason === 'authentication')
|
|
129
|
+
return 'denied';
|
|
130
|
+
if (reason === 'executor-unavailable' || reason === 'unsupported-capability')
|
|
131
|
+
return 'unavailable';
|
|
132
|
+
return 'error';
|
|
133
|
+
}
|
|
134
|
+
function compactRulesetResult(result) {
|
|
135
|
+
const evaluationStatuses = [];
|
|
136
|
+
const evaluations = Object.fromEntries(Object.entries(result.spec.evaluations).map(([alias, evaluation]) => [
|
|
137
|
+
alias,
|
|
138
|
+
(() => {
|
|
139
|
+
const status = normalizeDecisionStatus(evaluation.spec.status, evaluation.spec.reason);
|
|
140
|
+
evaluationStatuses.push(status);
|
|
141
|
+
return {
|
|
142
|
+
status,
|
|
143
|
+
reason: evaluation.spec.reason,
|
|
144
|
+
attempts: evaluation.spec.attempts.length,
|
|
145
|
+
value: evaluation.spec.value ?? null,
|
|
146
|
+
};
|
|
147
|
+
})(),
|
|
148
|
+
]));
|
|
149
|
+
return {
|
|
150
|
+
status: normalizeRulesetStatus(result.spec.status, result.spec.reason, evaluationStatuses),
|
|
151
|
+
rulesetStatus: result.spec.status,
|
|
152
|
+
reason: result.spec.reason,
|
|
153
|
+
matchedRules: [...result.spec.matchedRules],
|
|
154
|
+
evaluations,
|
|
155
|
+
outcome: result.spec.outcome ?? null,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function compactPatternReceipt(receipt) {
|
|
159
|
+
return {
|
|
160
|
+
status: receipt.route === 'accept' ? 'success' : receipt.route === 'review' ? 'abstained' : 'denied',
|
|
161
|
+
route: receipt.route,
|
|
162
|
+
reason: receipt.reason,
|
|
163
|
+
pattern: receipt.pattern,
|
|
164
|
+
fixtureId: receipt.fixtureId,
|
|
165
|
+
attempts: receipt.attempts,
|
|
166
|
+
transportCalls: receipt.runtime.transportCalls,
|
|
167
|
+
usage: receipt.usage,
|
|
168
|
+
checks: receipt.checks,
|
|
169
|
+
evaluations: receipt.evaluations.map(item => ({
|
|
170
|
+
alias: item.alias,
|
|
171
|
+
primitive: item.primitive,
|
|
172
|
+
status: item.status,
|
|
173
|
+
reason: item.reason,
|
|
174
|
+
attempts: item.attempts,
|
|
175
|
+
value: item.value,
|
|
176
|
+
})),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function parseMcpRequestProfiles(raw, cwd) {
|
|
180
|
+
if (!raw || !raw.trim())
|
|
181
|
+
return [];
|
|
182
|
+
let parsed;
|
|
183
|
+
try {
|
|
184
|
+
parsed = JSON.parse(raw);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
parsed = Object.fromEntries(raw.split(',').filter(Boolean).map(entry => {
|
|
188
|
+
const index = entry.indexOf('=');
|
|
189
|
+
if (index < 1)
|
|
190
|
+
throw new Error('AIWG_DECISION_MCP_REQUESTS must be JSON or comma-separated name=path entries');
|
|
191
|
+
return [entry.slice(0, index).trim(), entry.slice(index + 1).trim()];
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
if (!isRecord(parsed))
|
|
195
|
+
throw new Error('AIWG_DECISION_MCP_REQUESTS must resolve to an object');
|
|
196
|
+
return Object.entries(parsed).map(([name, value]) => {
|
|
197
|
+
const requestPath = typeof value === 'string' ? value : isRecord(value) && typeof value.requestPath === 'string' ? value.requestPath : null;
|
|
198
|
+
const hostPolicyModulePath = isRecord(value) && typeof value.hostPolicyModulePath === 'string' ? value.hostPolicyModulePath : undefined;
|
|
199
|
+
if (!requestPath || !/^[A-Za-z0-9_.-]+$/.test(name))
|
|
200
|
+
throw new Error('Invalid decision MCP request profile');
|
|
201
|
+
if (isRecord(value) && 'hostPolicyModulePath' in value && !hostPolicyModulePath)
|
|
202
|
+
throw new Error('Invalid decision MCP request profile');
|
|
203
|
+
return {
|
|
204
|
+
name,
|
|
205
|
+
requestPath: resolvePath(requestPath, cwd),
|
|
206
|
+
...(hostPolicyModulePath ? { hostPolicyModulePath: resolvePath(hostPolicyModulePath, cwd) } : {}),
|
|
207
|
+
};
|
|
208
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
209
|
+
}
|
|
210
|
+
async function loadDispatcher(options) {
|
|
211
|
+
if (options.dispatcher)
|
|
212
|
+
return options.dispatcher;
|
|
213
|
+
const moduleUrl = pathToFileURL(path.join(getPackageRoot(), 'agentic/code/addons/decision-engine/skills/decision-evaluate/scripts/decision-evaluate-core.mjs'));
|
|
214
|
+
return await import(moduleUrl.href);
|
|
215
|
+
}
|
|
216
|
+
async function loadRuntime(options) {
|
|
217
|
+
if (options.runtime)
|
|
218
|
+
return options.runtime;
|
|
219
|
+
return await import('./index.js');
|
|
220
|
+
}
|
|
221
|
+
export function decisionCapabilities(options = {}) {
|
|
222
|
+
const env = driverEnv(options);
|
|
223
|
+
const profiles = parseMcpRequestProfiles(env.AIWG_DECISION_MCP_REQUESTS, options.cwd ?? process.cwd());
|
|
224
|
+
const packs = decisionPatternPacks;
|
|
225
|
+
return {
|
|
226
|
+
schema: 'aiwg-decision-driver-capabilities/v1',
|
|
227
|
+
enabled: env.AIWG_DECISION_ENABLED === '1',
|
|
228
|
+
offlineReady: true,
|
|
229
|
+
primitives: [...new Set(packs.map(pack => pack.primitive))].sort(),
|
|
230
|
+
patterns: {
|
|
231
|
+
total: packs.length,
|
|
232
|
+
supported: packs.filter(pack => pack.status === 'supported').length,
|
|
233
|
+
experimental: packs.filter(pack => pack.status === 'experimental').length,
|
|
234
|
+
unavailable: packs.filter(pack => pack.status === 'unavailable').length,
|
|
235
|
+
},
|
|
236
|
+
features: {
|
|
237
|
+
patterns: ['list', 'show', 'offline-run', 'live-plan'],
|
|
238
|
+
validation: [...VALIDATION_TARGETS],
|
|
239
|
+
evaluate: { requiresEnv: 'AIWG_DECISION_ENABLED=1', mcpRequiresOptIn: true, mcpProfiles: profiles.map(profile => profile.name) },
|
|
240
|
+
setup: ['synthetic-classification'],
|
|
241
|
+
experimental: packs.filter(pack => pack.status === 'experimental').map(pack => pack.id),
|
|
242
|
+
},
|
|
243
|
+
backend: {
|
|
244
|
+
configured: env.AIWG_DECISION_ENABLED === '1',
|
|
245
|
+
probed: false,
|
|
246
|
+
status: 'not-probed',
|
|
247
|
+
note: 'Capabilities do not infer credential, network, dispatcher, or backend readiness.',
|
|
248
|
+
},
|
|
249
|
+
configuration: {
|
|
250
|
+
env: {
|
|
251
|
+
AIWG_DECISION_ENABLED: env.AIWG_DECISION_ENABLED === '1' ? 'set' : 'unset',
|
|
252
|
+
AIWG_DECISION_MCP_REQUESTS: profiles.length ? 'configured' : 'unset',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
export function listPatterns() {
|
|
258
|
+
return { schema: 'aiwg-decision-pattern-list/v1', patterns: listDecisionPatterns() };
|
|
259
|
+
}
|
|
260
|
+
export function showPattern(id) {
|
|
261
|
+
const pack = getDecisionPatternPack(id);
|
|
262
|
+
return {
|
|
263
|
+
schema: 'aiwg-decision-pattern-show/v1',
|
|
264
|
+
pack,
|
|
265
|
+
inputSchema: patternInputSchema(id),
|
|
266
|
+
outputSchema: patternOutputSchema(id),
|
|
267
|
+
livePlan: planLiveDecisionPattern(id, { explicitOptIn: false, credentialResolved: false, egressApproved: false }),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export async function runOfflinePattern(id, fixtureId) {
|
|
271
|
+
const receipt = await runOfflineDecisionPattern(id, fixtureId);
|
|
272
|
+
return { schema: 'aiwg-decision-offline-run/v1', ...compactPatternReceipt(receipt), receipt };
|
|
273
|
+
}
|
|
274
|
+
export function livePlan(id, options = {}) {
|
|
275
|
+
return planLiveDecisionPattern(id, {
|
|
276
|
+
explicitOptIn: options.explicitOptIn === true,
|
|
277
|
+
credentialResolved: options.credentialResolved === true,
|
|
278
|
+
egressApproved: options.egressApproved === true,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function documentSummary(value) {
|
|
282
|
+
if (!isRecord(value))
|
|
283
|
+
return {};
|
|
284
|
+
const metadata = isRecord(value.metadata) ? value.metadata : {};
|
|
285
|
+
return {
|
|
286
|
+
kind: typeof value.kind === 'string' ? value.kind : null,
|
|
287
|
+
apiVersion: typeof value.apiVersion === 'string' ? value.apiVersion : null,
|
|
288
|
+
id: typeof metadata.id === 'string' ? metadata.id : null,
|
|
289
|
+
version: typeof metadata.version === 'string' ? metadata.version : null,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
export function validateDecisionValue(target, value, source = 'inline') {
|
|
293
|
+
const errors = [];
|
|
294
|
+
try {
|
|
295
|
+
if (target === 'request')
|
|
296
|
+
errors.push(...requestSchemaErrors(value));
|
|
297
|
+
else if (target === 'definition')
|
|
298
|
+
validateDefinition(value);
|
|
299
|
+
else if (target === 'ruleset')
|
|
300
|
+
validateRuleset(value);
|
|
301
|
+
else if (target === 'binding') {
|
|
302
|
+
if (!isRecord(value) || value.kind !== 'DecisionBinding')
|
|
303
|
+
errors.push('binding kind must be DecisionBinding');
|
|
304
|
+
else
|
|
305
|
+
validateDecisionDocument(value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
errors.push(error instanceof Error ? error.message.replace(/:\s*["'`].*$/s, '') : 'validation-failed');
|
|
310
|
+
}
|
|
311
|
+
return { schema: 'aiwg-decision-validation/v1', target, source, valid: errors.length === 0, summary: documentSummary(value), errors };
|
|
312
|
+
}
|
|
313
|
+
export async function validateDecisionInput(target, filePath, options = {}) {
|
|
314
|
+
const resolved = resolvePath(filePath, options.cwd ?? process.cwd());
|
|
315
|
+
const loaded = await readJson(resolved);
|
|
316
|
+
if (loaded.error) {
|
|
317
|
+
return { schema: 'aiwg-decision-validation/v1', target, source: 'path', valid: false, summary: {}, errors: [loaded.error] };
|
|
318
|
+
}
|
|
319
|
+
return validateDecisionValue(target, loaded.value, 'path');
|
|
320
|
+
}
|
|
321
|
+
export async function evaluateRequestPath(requestPath, options = {}, evaluateOptions = {}) {
|
|
322
|
+
const env = driverEnv(options);
|
|
323
|
+
const resolved = resolvePath(requestPath, options.cwd ?? process.cwd());
|
|
324
|
+
if (env.AIWG_DECISION_ENABLED !== '1') {
|
|
325
|
+
return { schema: 'aiwg-decision-evaluate/v1', status: 'denied', reason: 'explicit-enable-required', exitCode: 2, result: null };
|
|
326
|
+
}
|
|
327
|
+
const validation = await validateDecisionInput('request', resolved, options);
|
|
328
|
+
if (!validation.valid)
|
|
329
|
+
return { schema: 'aiwg-decision-evaluate/v1', status: 'error', reason: 'invalid-request', exitCode: 2, validation, result: null };
|
|
330
|
+
const dispatcher = await loadDispatcher(options);
|
|
331
|
+
const runtime = await loadRuntime(options);
|
|
332
|
+
let stdout = '';
|
|
333
|
+
let stderr = '';
|
|
334
|
+
const argv = ['--request', resolved];
|
|
335
|
+
if (evaluateOptions.hostPolicyModulePath)
|
|
336
|
+
argv.push('--host-policy-module', resolvePath(evaluateOptions.hostPolicyModulePath, options.cwd ?? process.cwd()));
|
|
337
|
+
const exitCode = await dispatcher.runDecisionEvaluate({
|
|
338
|
+
argv,
|
|
339
|
+
env,
|
|
340
|
+
runtime,
|
|
341
|
+
stdout: { write(chunk) { stdout += String(chunk); return true; } },
|
|
342
|
+
stderr: { write(chunk) { stderr += String(chunk); return true; } },
|
|
343
|
+
});
|
|
344
|
+
let parsed = null;
|
|
345
|
+
try {
|
|
346
|
+
parsed = JSON.parse(stdout);
|
|
347
|
+
if (!isRecord(parsed) || parsed.kind !== 'RulesetResult')
|
|
348
|
+
throw new Error('dispatcher output must be a RulesetResult');
|
|
349
|
+
validateDecisionDocument(parsed);
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
parsed = null;
|
|
353
|
+
}
|
|
354
|
+
const compact = parsed ? compactRulesetResult(parsed) : null;
|
|
355
|
+
return {
|
|
356
|
+
schema: 'aiwg-decision-evaluate/v1',
|
|
357
|
+
status: compact?.status ?? (exitCode === 2 ? 'denied' : 'error'),
|
|
358
|
+
reason: parsed?.spec.reason ?? (stderr.trim() || 'dispatcher-output-unavailable'),
|
|
359
|
+
exitCode,
|
|
360
|
+
stderr: stderr.trim(),
|
|
361
|
+
compact,
|
|
362
|
+
result: parsed,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
export async function evaluateMcpProfile(profileName, optIn, options = {}) {
|
|
366
|
+
if (!optIn)
|
|
367
|
+
return { schema: 'aiwg-decision-evaluate/v1', status: 'denied', reason: 'per-call-opt-in-required', exitCode: 2, result: null };
|
|
368
|
+
const profiles = parseMcpRequestProfiles(driverEnv(options).AIWG_DECISION_MCP_REQUESTS, options.cwd ?? process.cwd());
|
|
369
|
+
const profile = profiles.find(candidate => candidate.name === profileName);
|
|
370
|
+
if (!profile)
|
|
371
|
+
return { schema: 'aiwg-decision-evaluate/v1', status: 'unavailable', reason: 'unknown-request-profile', exitCode: 2, result: null };
|
|
372
|
+
return evaluateRequestPath(profile.requestPath, options, { hostPolicyModulePath: profile.hostPolicyModulePath });
|
|
373
|
+
}
|
|
374
|
+
export function syntheticClassificationSetup(options = {}, driverOptions = {}) {
|
|
375
|
+
const id = 'bounded-classification';
|
|
376
|
+
const artifacts = governedPatternArtifacts(id, '1.0.0');
|
|
377
|
+
const definition = artifacts.definitions['pattern.bounded-classification.category'];
|
|
378
|
+
const answer = definition?.spec.answer;
|
|
379
|
+
const pinnedOptions = answer?.kind === 'choice' ? answer.options.map(option => option.id) : [];
|
|
380
|
+
const allowedOptions = options.allowedOptions === undefined ? ['bug', 'feature', 'none'] : options.allowedOptions;
|
|
381
|
+
if (allowedOptions.length === 0)
|
|
382
|
+
throw new Error('allowedOptions must not be empty');
|
|
383
|
+
if (new Set(allowedOptions).size !== allowedOptions.length)
|
|
384
|
+
throw new Error('allowedOptions must not contain duplicates');
|
|
385
|
+
if (allowedOptions.some(option => !option.trim()))
|
|
386
|
+
throw new Error('allowedOptions must not contain blank values');
|
|
387
|
+
const unknown = allowedOptions.filter(option => !pinnedOptions.includes(option));
|
|
388
|
+
if (unknown.length)
|
|
389
|
+
throw new Error(`allowedOptions must be selected from the pinned definition options: ${pinnedOptions.join(', ')}`);
|
|
390
|
+
const text = options.text ?? 'Synthetic ticket: app crashes after saving settings.';
|
|
391
|
+
if (!text.trim())
|
|
392
|
+
throw new Error('text must not be blank');
|
|
393
|
+
const input = { allowedOptions, text };
|
|
394
|
+
validateAgainstSchema(patternInputSchema(id), input, 'synthetic classification input');
|
|
395
|
+
const root = frameworkRoot(driverOptions);
|
|
396
|
+
const files = {
|
|
397
|
+
'definition-category.json': artifacts.definitions['pattern.bounded-classification.category'],
|
|
398
|
+
'ruleset.json': artifacts.ruleset,
|
|
399
|
+
'binding.json': artifacts.offlineBinding,
|
|
400
|
+
'input.json': input,
|
|
401
|
+
'dispatcher-request.json': {
|
|
402
|
+
rulesetPath: 'ruleset.json',
|
|
403
|
+
bindingPath: 'binding.json',
|
|
404
|
+
inputPath: 'input.json',
|
|
405
|
+
definitionPaths: ['definition-category.json'],
|
|
406
|
+
adapterModules: { jev: path.join(root, OFFLINE_ADAPTER) },
|
|
407
|
+
runId: 'synthetic-classification',
|
|
408
|
+
invocationId: 'synthetic-classification-1',
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
return { schema: 'aiwg-decision-synthetic-setup/v1', pattern: { id, version: '1.0.0' }, files };
|
|
412
|
+
}
|
|
413
|
+
export async function materializeSyntheticClassificationSetup(outputDir, options = {}, driverOptions = {}) {
|
|
414
|
+
const resolved = resolvePath(outputDir, driverOptions.cwd ?? process.cwd());
|
|
415
|
+
const setup = syntheticClassificationSetup(options, driverOptions);
|
|
416
|
+
await mkdir(resolved, { recursive: true });
|
|
417
|
+
const written = {};
|
|
418
|
+
for (const [filename, content] of Object.entries(setup.files)) {
|
|
419
|
+
const destination = path.join(resolved, filename);
|
|
420
|
+
try {
|
|
421
|
+
await writeFile(destination, `${JSON.stringify(content, null, 2)}\n`, { flag: 'wx' });
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
if (error.code === 'EEXIST')
|
|
425
|
+
throw new Error(`Refusing to overwrite ${destination}`);
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
written[filename] = destination;
|
|
429
|
+
}
|
|
430
|
+
return { schema: 'aiwg-decision-synthetic-setup-materialized/v1', outputDir: resolved, files: written };
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=driver.js.map
|