@wundr.io/cli 1.0.12 → 1.0.14
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/dist/ai/ai-service.d.ts +152 -0
- package/dist/ai/ai-service.d.ts.map +1 -0
- package/dist/ai/ai-service.js +430 -0
- package/dist/ai/ai-service.js.map +1 -0
- package/dist/ai/claude-client.d.ts +130 -0
- package/dist/ai/claude-client.d.ts.map +1 -0
- package/dist/ai/claude-client.js +340 -0
- package/dist/ai/claude-client.js.map +1 -0
- package/dist/ai/conversation-manager.d.ts +164 -0
- package/dist/ai/conversation-manager.d.ts.map +1 -0
- package/dist/ai/conversation-manager.js +614 -0
- package/dist/ai/conversation-manager.js.map +1 -0
- package/dist/ai/index.d.ts +5 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +192 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ai.d.ts +89 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +954 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/alignment.d.ts +78 -0
- package/dist/commands/alignment.d.ts.map +1 -0
- package/dist/commands/alignment.js +817 -0
- package/dist/commands/alignment.js.map +1 -0
- package/dist/commands/analyze-optimized.d.ts +14 -0
- package/dist/commands/analyze-optimized.d.ts.map +1 -0
- package/dist/commands/analyze-optimized.js +609 -0
- package/dist/commands/analyze-optimized.js.map +1 -0
- package/dist/commands/analyze.d.ts +65 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +435 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/batch.d.ts +93 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +854 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/chat.d.ts +72 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +678 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/claude-init.d.ts +28 -0
- package/dist/commands/claude-init.d.ts.map +1 -0
- package/dist/commands/claude-init.js +591 -0
- package/dist/commands/claude-init.js.map +1 -0
- package/dist/commands/claude-setup.d.ts +119 -0
- package/dist/commands/claude-setup.d.ts.map +1 -0
- package/dist/commands/claude-setup.js +1079 -0
- package/dist/commands/claude-setup.js.map +1 -0
- package/dist/commands/computer-setup.d.ts +8 -0
- package/dist/commands/computer-setup.d.ts.map +1 -0
- package/dist/commands/computer-setup.js +877 -0
- package/dist/commands/computer-setup.js.map +1 -0
- package/dist/commands/create-command.d.ts +7 -0
- package/dist/commands/create-command.d.ts.map +1 -0
- package/dist/commands/create-command.js +158 -0
- package/dist/commands/create-command.js.map +1 -0
- package/dist/commands/create.d.ts +74 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +556 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dashboard.d.ts +91 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +538 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/govern.d.ts +70 -0
- package/dist/commands/govern.d.ts.map +1 -0
- package/dist/commands/govern.js +481 -0
- package/dist/commands/govern.js.map +1 -0
- package/dist/commands/governance.d.ts +17 -0
- package/dist/commands/governance.d.ts.map +1 -0
- package/dist/commands/governance.js +703 -0
- package/dist/commands/governance.js.map +1 -0
- package/dist/commands/guardian.d.ts +20 -0
- package/dist/commands/guardian.d.ts.map +1 -0
- package/dist/commands/guardian.js +597 -0
- package/dist/commands/guardian.js.map +1 -0
- package/dist/commands/init.d.ts +59 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +650 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/orchestrator.d.ts +7 -0
- package/dist/commands/orchestrator.d.ts.map +1 -0
- package/dist/commands/orchestrator.js +578 -0
- package/dist/commands/orchestrator.js.map +1 -0
- package/dist/commands/performance-optimizer.d.ts +30 -0
- package/dist/commands/performance-optimizer.d.ts.map +1 -0
- package/dist/commands/performance-optimizer.js +650 -0
- package/dist/commands/performance-optimizer.js.map +1 -0
- package/dist/commands/plugins.d.ts +87 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +685 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/rag.d.ts +7 -0
- package/dist/commands/rag.d.ts.map +1 -0
- package/dist/commands/rag.js +751 -0
- package/dist/commands/rag.js.map +1 -0
- package/dist/commands/session.d.ts +41 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +441 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +24 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +172 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/test-init.d.ts +9 -0
- package/dist/commands/test-init.d.ts.map +1 -0
- package/dist/commands/test-init.js +222 -0
- package/dist/commands/test-init.js.map +1 -0
- package/dist/commands/test.d.ts +25 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +217 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/watch.d.ts +76 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +613 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/worktree.d.ts +63 -0
- package/dist/commands/worktree.d.ts.map +1 -0
- package/dist/commands/worktree.js +774 -0
- package/dist/commands/worktree.js.map +1 -0
- package/dist/context/context-manager.d.ts +155 -0
- package/dist/context/context-manager.d.ts.map +1 -0
- package/dist/context/context-manager.js +383 -0
- package/dist/context/context-manager.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +6 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/session-manager.d.ts +207 -0
- package/dist/context/session-manager.d.ts.map +1 -0
- package/dist/context/session-manager.js +686 -0
- package/dist/context/session-manager.js.map +1 -0
- package/dist/framework/command-interface.d.ts +349 -0
- package/dist/framework/command-interface.d.ts.map +1 -0
- package/dist/framework/command-interface.js +101 -0
- package/dist/framework/command-interface.js.map +1 -0
- package/dist/framework/command-registry.d.ts +173 -0
- package/dist/framework/command-registry.d.ts.map +1 -0
- package/dist/framework/command-registry.js +734 -0
- package/dist/framework/command-registry.js.map +1 -0
- package/dist/framework/completion-exporter.d.ts +79 -0
- package/dist/framework/completion-exporter.d.ts.map +1 -0
- package/dist/framework/completion-exporter.js +259 -0
- package/dist/framework/completion-exporter.js.map +1 -0
- package/dist/framework/debug-logger.d.ts +163 -0
- package/dist/framework/debug-logger.d.ts.map +1 -0
- package/dist/framework/debug-logger.js +373 -0
- package/dist/framework/debug-logger.js.map +1 -0
- package/dist/framework/error-handler.d.ts +196 -0
- package/dist/framework/error-handler.d.ts.map +1 -0
- package/dist/framework/error-handler.js +613 -0
- package/dist/framework/error-handler.js.map +1 -0
- package/dist/framework/help-generator.d.ts +78 -0
- package/dist/framework/help-generator.d.ts.map +1 -0
- package/dist/framework/help-generator.js +414 -0
- package/dist/framework/help-generator.js.map +1 -0
- package/dist/framework/index.d.ts +62 -0
- package/dist/framework/index.d.ts.map +1 -0
- package/dist/framework/index.js +95 -0
- package/dist/framework/index.js.map +1 -0
- package/dist/framework/interactive-repl.d.ts +138 -0
- package/dist/framework/interactive-repl.d.ts.map +1 -0
- package/dist/framework/interactive-repl.js +567 -0
- package/dist/framework/interactive-repl.js.map +1 -0
- package/dist/framework/output-formatter.d.ts +274 -0
- package/dist/framework/output-formatter.d.ts.map +1 -0
- package/dist/framework/output-formatter.js +545 -0
- package/dist/framework/output-formatter.js.map +1 -0
- package/dist/framework/progress-manager.d.ts +192 -0
- package/dist/framework/progress-manager.d.ts.map +1 -0
- package/dist/framework/progress-manager.js +408 -0
- package/dist/framework/progress-manager.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive/interactive-mode.d.ts +76 -0
- package/dist/interactive/interactive-mode.d.ts.map +1 -0
- package/dist/interactive/interactive-mode.js +732 -0
- package/dist/interactive/interactive-mode.js.map +1 -0
- package/dist/nlp/command-mapper.d.ts +174 -0
- package/dist/nlp/command-mapper.d.ts.map +1 -0
- package/dist/nlp/command-mapper.js +624 -0
- package/dist/nlp/command-mapper.js.map +1 -0
- package/dist/nlp/command-parser.d.ts +106 -0
- package/dist/nlp/command-parser.d.ts.map +1 -0
- package/dist/nlp/command-parser.js +417 -0
- package/dist/nlp/command-parser.js.map +1 -0
- package/dist/nlp/index.d.ts +5 -0
- package/dist/nlp/index.d.ts.map +1 -0
- package/dist/nlp/index.js +8 -0
- package/dist/nlp/index.js.map +1 -0
- package/dist/nlp/intent-classifier.d.ts +59 -0
- package/dist/nlp/intent-classifier.d.ts.map +1 -0
- package/dist/nlp/intent-classifier.js +384 -0
- package/dist/nlp/intent-classifier.js.map +1 -0
- package/dist/nlp/intent-parser.d.ts +152 -0
- package/dist/nlp/intent-parser.d.ts.map +1 -0
- package/dist/nlp/intent-parser.js +746 -0
- package/dist/nlp/intent-parser.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +121 -0
- package/dist/plugins/plugin-manager.d.ts.map +1 -0
- package/dist/plugins/plugin-manager.js +606 -0
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/types/index.d.ts +224 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/backup-rollback-manager.d.ts +72 -0
- package/dist/utils/backup-rollback-manager.d.ts.map +1 -0
- package/dist/utils/backup-rollback-manager.js +288 -0
- package/dist/utils/backup-rollback-manager.js.map +1 -0
- package/dist/utils/claude-config-installer.d.ts +98 -0
- package/dist/utils/claude-config-installer.d.ts.map +1 -0
- package/dist/utils/claude-config-installer.js +678 -0
- package/dist/utils/claude-config-installer.js.map +1 -0
- package/dist/utils/config-manager.d.ts +73 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +339 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/error-handler.d.ts +46 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +169 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +105 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Alignment Monitoring CLI Commands
|
|
4
|
+
*
|
|
5
|
+
* Provides commands for monitoring AI agent alignment drift across five dimensions:
|
|
6
|
+
* - Policy Violation Rate
|
|
7
|
+
* - Intent-Outcome Gap
|
|
8
|
+
* - Evaluator Disagreement
|
|
9
|
+
* - Escalation Suppression
|
|
10
|
+
* - Reward Hacking
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.createAlignmentCommand = createAlignmentCommand;
|
|
14
|
+
const tslib_1 = require("tslib");
|
|
15
|
+
const os = tslib_1.__importStar(require("os"));
|
|
16
|
+
const path = tslib_1.__importStar(require("path"));
|
|
17
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
18
|
+
const commander_1 = require("commander");
|
|
19
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
20
|
+
const ora_1 = tslib_1.__importDefault(require("ora"));
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// AlignmentDriftDetector - Embedded Implementation
|
|
23
|
+
// ============================================================================
|
|
24
|
+
class AlignmentDriftDetector {
|
|
25
|
+
dataDir;
|
|
26
|
+
historyFile;
|
|
27
|
+
// Thresholds from Three-Tier Architecture spec
|
|
28
|
+
thresholds = {
|
|
29
|
+
policyViolation: 0.005, // >0.5% daily violations triggers alert
|
|
30
|
+
intentOutcomeGap: 0.15, // >15% divergence is concerning
|
|
31
|
+
evaluatorDisagreement: 0.2, // >20% monthly overrides
|
|
32
|
+
escalationSuppression: 0.4, // >40% drop from baseline
|
|
33
|
+
rewardHacking: 5, // >5 instances/month
|
|
34
|
+
};
|
|
35
|
+
constructor(dataDir) {
|
|
36
|
+
this.dataDir = dataDir || path.join(os.homedir(), '.wundr', 'alignment');
|
|
37
|
+
this.historyFile = path.join(this.dataDir, 'history.json');
|
|
38
|
+
}
|
|
39
|
+
async initialize() {
|
|
40
|
+
await fs_extra_1.default.ensureDir(this.dataDir);
|
|
41
|
+
if (!(await fs_extra_1.default.pathExists(this.historyFile))) {
|
|
42
|
+
await fs_extra_1.default.writeJson(this.historyFile, { entries: [] }, { spaces: 2 });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async calculateAlignmentDebt(sessionId) {
|
|
46
|
+
const metrics = await this.collectMetrics(sessionId);
|
|
47
|
+
return this.calculateScore(metrics);
|
|
48
|
+
}
|
|
49
|
+
async getAlignmentReport(sessionId) {
|
|
50
|
+
await this.initialize();
|
|
51
|
+
const metrics = await this.collectMetrics(sessionId);
|
|
52
|
+
const score = this.calculateScore(metrics);
|
|
53
|
+
const status = this.determineStatus(score);
|
|
54
|
+
const dimensions = this.analyzeDimensions(metrics);
|
|
55
|
+
const recommendations = this.generateRecommendations(dimensions, status);
|
|
56
|
+
const report = {
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
sessionId,
|
|
59
|
+
overallScore: score,
|
|
60
|
+
status,
|
|
61
|
+
metrics,
|
|
62
|
+
dimensions,
|
|
63
|
+
recommendations,
|
|
64
|
+
};
|
|
65
|
+
// Store in history
|
|
66
|
+
await this.storeHistoryEntry({
|
|
67
|
+
timestamp: report.timestamp,
|
|
68
|
+
sessionId,
|
|
69
|
+
score,
|
|
70
|
+
status,
|
|
71
|
+
metrics,
|
|
72
|
+
});
|
|
73
|
+
return report;
|
|
74
|
+
}
|
|
75
|
+
async getAlignmentScore(sessionId) {
|
|
76
|
+
const score = await this.calculateAlignmentDebt(sessionId);
|
|
77
|
+
const status = this.determineStatus(score);
|
|
78
|
+
return {
|
|
79
|
+
score,
|
|
80
|
+
status,
|
|
81
|
+
color: status === 'healthy'
|
|
82
|
+
? 'green'
|
|
83
|
+
: status === 'warning'
|
|
84
|
+
? 'yellow'
|
|
85
|
+
: 'red',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async getHistory(days = 30) {
|
|
89
|
+
await this.initialize();
|
|
90
|
+
const history = await this.loadHistory();
|
|
91
|
+
const cutoffDate = new Date();
|
|
92
|
+
cutoffDate.setDate(cutoffDate.getDate() - days);
|
|
93
|
+
return history.entries
|
|
94
|
+
.filter((entry) => new Date(entry.timestamp) >= cutoffDate)
|
|
95
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
96
|
+
}
|
|
97
|
+
async getDimensionBreakdown() {
|
|
98
|
+
const metrics = await this.collectMetrics();
|
|
99
|
+
return this.analyzeDimensions(metrics);
|
|
100
|
+
}
|
|
101
|
+
async generateDebtReport(days = 7, sessionId, outputFile) {
|
|
102
|
+
await this.initialize();
|
|
103
|
+
const history = await this.getHistory(days);
|
|
104
|
+
const filteredHistory = sessionId
|
|
105
|
+
? history.filter(h => h.sessionId === sessionId)
|
|
106
|
+
: history;
|
|
107
|
+
const endDate = new Date();
|
|
108
|
+
const startDate = new Date();
|
|
109
|
+
startDate.setDate(startDate.getDate() - days);
|
|
110
|
+
// Calculate summary statistics
|
|
111
|
+
const scores = filteredHistory.map(h => h.score);
|
|
112
|
+
const averageScore = scores.length > 0
|
|
113
|
+
? scores.reduce((a, b) => a + b, 0) / scores.length
|
|
114
|
+
: 100;
|
|
115
|
+
const lowestScore = scores.length > 0 ? Math.min(...scores) : 100;
|
|
116
|
+
const highestScore = scores.length > 0 ? Math.max(...scores) : 100;
|
|
117
|
+
// Calculate trend
|
|
118
|
+
let trend = 'stable';
|
|
119
|
+
if (scores.length >= 2) {
|
|
120
|
+
const firstHalf = scores.slice(0, Math.floor(scores.length / 2));
|
|
121
|
+
const secondHalf = scores.slice(Math.floor(scores.length / 2));
|
|
122
|
+
const firstAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
|
|
123
|
+
const secondAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;
|
|
124
|
+
if (secondAvg > firstAvg + 5) {
|
|
125
|
+
trend = 'improving';
|
|
126
|
+
}
|
|
127
|
+
else if (secondAvg < firstAvg - 5) {
|
|
128
|
+
trend = 'degrading';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Analyze dimensions across history
|
|
132
|
+
const dimensionAnalysis = {};
|
|
133
|
+
const dimensionKeys = [
|
|
134
|
+
'policyViolationRate',
|
|
135
|
+
'intentOutcomeGap',
|
|
136
|
+
'evaluatorDisagreement',
|
|
137
|
+
'escalationSuppression',
|
|
138
|
+
'rewardHacking',
|
|
139
|
+
];
|
|
140
|
+
for (const key of dimensionKeys) {
|
|
141
|
+
const values = filteredHistory.map(h => h.metrics[key]);
|
|
142
|
+
const threshold = this.getThresholdForKey(key);
|
|
143
|
+
dimensionAnalysis[key] = {
|
|
144
|
+
average: values.length > 0
|
|
145
|
+
? values.reduce((a, b) => a + b, 0) / values.length
|
|
146
|
+
: 0,
|
|
147
|
+
max: values.length > 0 ? Math.max(...values) : 0,
|
|
148
|
+
exceedances: values.filter(v => v > threshold).length,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// Find critical events
|
|
152
|
+
const criticalEvents = [];
|
|
153
|
+
for (const entry of filteredHistory) {
|
|
154
|
+
for (const key of dimensionKeys) {
|
|
155
|
+
const threshold = this.getThresholdForKey(key);
|
|
156
|
+
if (entry.metrics[key] > threshold * 2) {
|
|
157
|
+
criticalEvents.push({
|
|
158
|
+
timestamp: entry.timestamp,
|
|
159
|
+
dimension: key,
|
|
160
|
+
value: entry.metrics[key],
|
|
161
|
+
threshold,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Calculate total violations
|
|
167
|
+
const totalViolations = Object.values(dimensionAnalysis).reduce((sum, dim) => sum + dim.exceedances, 0);
|
|
168
|
+
// Generate recommendations
|
|
169
|
+
const recommendations = this.generateDebtRecommendations(dimensionAnalysis, trend);
|
|
170
|
+
const report = {
|
|
171
|
+
generatedAt: new Date().toISOString(),
|
|
172
|
+
period: {
|
|
173
|
+
start: startDate.toISOString(),
|
|
174
|
+
end: endDate.toISOString(),
|
|
175
|
+
days,
|
|
176
|
+
},
|
|
177
|
+
summary: {
|
|
178
|
+
averageScore,
|
|
179
|
+
lowestScore,
|
|
180
|
+
highestScore,
|
|
181
|
+
trend,
|
|
182
|
+
totalViolations,
|
|
183
|
+
},
|
|
184
|
+
dimensionAnalysis,
|
|
185
|
+
criticalEvents: criticalEvents.slice(0, 20),
|
|
186
|
+
recommendations,
|
|
187
|
+
};
|
|
188
|
+
if (outputFile) {
|
|
189
|
+
await fs_extra_1.default.writeJson(outputFile, report, { spaces: 2 });
|
|
190
|
+
}
|
|
191
|
+
return report;
|
|
192
|
+
}
|
|
193
|
+
getThresholds() {
|
|
194
|
+
return { ...this.thresholds };
|
|
195
|
+
}
|
|
196
|
+
async collectMetrics(sessionId) {
|
|
197
|
+
const sessionMetricsFile = sessionId
|
|
198
|
+
? path.join(this.dataDir, 'sessions', `${sessionId}.json`)
|
|
199
|
+
: path.join(this.dataDir, 'current-metrics.json');
|
|
200
|
+
if (await fs_extra_1.default.pathExists(sessionMetricsFile)) {
|
|
201
|
+
try {
|
|
202
|
+
const data = await fs_extra_1.default.readJson(sessionMetricsFile);
|
|
203
|
+
return {
|
|
204
|
+
policyViolationRate: data.policyViolationRate ?? 0,
|
|
205
|
+
intentOutcomeGap: data.intentOutcomeGap ?? 0,
|
|
206
|
+
evaluatorDisagreement: data.evaluatorDisagreement ?? 0,
|
|
207
|
+
escalationSuppression: data.escalationSuppression ?? 0,
|
|
208
|
+
rewardHacking: data.rewardHacking ?? 0,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Fall through to defaults
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
policyViolationRate: 0,
|
|
217
|
+
intentOutcomeGap: 0,
|
|
218
|
+
evaluatorDisagreement: 0,
|
|
219
|
+
escalationSuppression: 0,
|
|
220
|
+
rewardHacking: 0,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
calculateScore(metrics) {
|
|
224
|
+
const normalizedPolicyViolation = Math.min(metrics.policyViolationRate / this.thresholds.policyViolation, 2);
|
|
225
|
+
const normalizedIntentGap = Math.min(metrics.intentOutcomeGap / this.thresholds.intentOutcomeGap, 2);
|
|
226
|
+
const normalizedEvaluatorDisagreement = Math.min(metrics.evaluatorDisagreement / this.thresholds.evaluatorDisagreement, 2);
|
|
227
|
+
const normalizedEscalationSuppression = Math.min(metrics.escalationSuppression / this.thresholds.escalationSuppression, 2);
|
|
228
|
+
const normalizedRewardHacking = Math.min(metrics.rewardHacking / this.thresholds.rewardHacking, 2);
|
|
229
|
+
const weights = {
|
|
230
|
+
policyViolation: 0.25,
|
|
231
|
+
intentOutcomeGap: 0.25,
|
|
232
|
+
evaluatorDisagreement: 0.2,
|
|
233
|
+
escalationSuppression: 0.15,
|
|
234
|
+
rewardHacking: 0.15,
|
|
235
|
+
};
|
|
236
|
+
const penalty = normalizedPolicyViolation * weights.policyViolation +
|
|
237
|
+
normalizedIntentGap * weights.intentOutcomeGap +
|
|
238
|
+
normalizedEvaluatorDisagreement * weights.evaluatorDisagreement +
|
|
239
|
+
normalizedEscalationSuppression * weights.escalationSuppression +
|
|
240
|
+
normalizedRewardHacking * weights.rewardHacking;
|
|
241
|
+
const score = Math.max(0, Math.min(100, 100 - penalty * 50));
|
|
242
|
+
return Math.round(score * 10) / 10;
|
|
243
|
+
}
|
|
244
|
+
determineStatus(score) {
|
|
245
|
+
if (score >= 80) {
|
|
246
|
+
return 'healthy';
|
|
247
|
+
}
|
|
248
|
+
if (score >= 50) {
|
|
249
|
+
return 'warning';
|
|
250
|
+
}
|
|
251
|
+
return 'critical';
|
|
252
|
+
}
|
|
253
|
+
analyzeDimensions(metrics) {
|
|
254
|
+
return [
|
|
255
|
+
{
|
|
256
|
+
name: 'Policy Violation Rate',
|
|
257
|
+
key: 'policyViolationRate',
|
|
258
|
+
threshold: this.thresholds.policyViolation,
|
|
259
|
+
description: 'Percentage of actions violating defined constraints',
|
|
260
|
+
currentValue: metrics.policyViolationRate,
|
|
261
|
+
status: this.getDimensionStatus(metrics.policyViolationRate, this.thresholds.policyViolation),
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: 'Intent-Outcome Gap',
|
|
265
|
+
key: 'intentOutcomeGap',
|
|
266
|
+
threshold: this.thresholds.intentOutcomeGap,
|
|
267
|
+
description: 'Divergence between stated goals and actual outcomes',
|
|
268
|
+
currentValue: metrics.intentOutcomeGap,
|
|
269
|
+
status: this.getDimensionStatus(metrics.intentOutcomeGap, this.thresholds.intentOutcomeGap),
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'Evaluator Disagreement',
|
|
273
|
+
key: 'evaluatorDisagreement',
|
|
274
|
+
threshold: this.thresholds.evaluatorDisagreement,
|
|
275
|
+
description: 'Rate of human overrides on agent decisions',
|
|
276
|
+
currentValue: metrics.evaluatorDisagreement,
|
|
277
|
+
status: this.getDimensionStatus(metrics.evaluatorDisagreement, this.thresholds.evaluatorDisagreement),
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: 'Escalation Suppression',
|
|
281
|
+
key: 'escalationSuppression',
|
|
282
|
+
threshold: this.thresholds.escalationSuppression,
|
|
283
|
+
description: 'Drop in escalation triggers compared to baseline',
|
|
284
|
+
currentValue: metrics.escalationSuppression,
|
|
285
|
+
status: this.getDimensionStatus(metrics.escalationSuppression, this.thresholds.escalationSuppression),
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'Reward Hacking',
|
|
289
|
+
key: 'rewardHacking',
|
|
290
|
+
threshold: this.thresholds.rewardHacking,
|
|
291
|
+
description: 'Instances of gaming metrics without achieving intent',
|
|
292
|
+
currentValue: metrics.rewardHacking,
|
|
293
|
+
status: this.getDimensionStatus(metrics.rewardHacking, this.thresholds.rewardHacking),
|
|
294
|
+
},
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
getDimensionStatus(value, threshold) {
|
|
298
|
+
if (value <= threshold) {
|
|
299
|
+
return 'healthy';
|
|
300
|
+
}
|
|
301
|
+
if (value <= threshold * 2) {
|
|
302
|
+
return 'warning';
|
|
303
|
+
}
|
|
304
|
+
return 'critical';
|
|
305
|
+
}
|
|
306
|
+
getThresholdForKey(key) {
|
|
307
|
+
const thresholdMap = {
|
|
308
|
+
policyViolationRate: this.thresholds.policyViolation,
|
|
309
|
+
intentOutcomeGap: this.thresholds.intentOutcomeGap,
|
|
310
|
+
evaluatorDisagreement: this.thresholds.evaluatorDisagreement,
|
|
311
|
+
escalationSuppression: this.thresholds.escalationSuppression,
|
|
312
|
+
rewardHacking: this.thresholds.rewardHacking,
|
|
313
|
+
};
|
|
314
|
+
return thresholdMap[key];
|
|
315
|
+
}
|
|
316
|
+
generateRecommendations(dimensions, status) {
|
|
317
|
+
const recommendations = [];
|
|
318
|
+
for (const dim of dimensions) {
|
|
319
|
+
if (dim.status === 'critical') {
|
|
320
|
+
recommendations.push(`CRITICAL: ${dim.name} at ${this.formatValue(dim.currentValue, dim.key)} exceeds threshold (${this.formatValue(dim.threshold, dim.key)}). Immediate action required.`);
|
|
321
|
+
}
|
|
322
|
+
else if (dim.status === 'warning') {
|
|
323
|
+
recommendations.push(`WARNING: ${dim.name} at ${this.formatValue(dim.currentValue, dim.key)} approaching threshold (${this.formatValue(dim.threshold, dim.key)}). Monitor closely.`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (status === 'critical') {
|
|
327
|
+
recommendations.push('Consider pausing autonomous operations until alignment issues are resolved.');
|
|
328
|
+
recommendations.push('Schedule immediate review with Guardian role.');
|
|
329
|
+
}
|
|
330
|
+
else if (status === 'warning') {
|
|
331
|
+
recommendations.push('Review recent agent decisions for potential alignment drift.');
|
|
332
|
+
recommendations.push('Consider tightening constraints or adding checkpoints.');
|
|
333
|
+
}
|
|
334
|
+
if (recommendations.length === 0) {
|
|
335
|
+
recommendations.push('All alignment metrics within acceptable thresholds.');
|
|
336
|
+
}
|
|
337
|
+
return recommendations;
|
|
338
|
+
}
|
|
339
|
+
generateDebtRecommendations(dimensionAnalysis, trend) {
|
|
340
|
+
const recommendations = [];
|
|
341
|
+
if (trend === 'degrading') {
|
|
342
|
+
recommendations.push('Alignment score is degrading over time. Review recent changes to agent configurations.');
|
|
343
|
+
}
|
|
344
|
+
else if (trend === 'improving') {
|
|
345
|
+
recommendations.push('Alignment score is improving. Continue current governance practices.');
|
|
346
|
+
}
|
|
347
|
+
for (const [key, analysis] of Object.entries(dimensionAnalysis)) {
|
|
348
|
+
if (analysis.exceedances > 0) {
|
|
349
|
+
const friendlyName = this.getFriendlyDimensionName(key);
|
|
350
|
+
const entry = analysis;
|
|
351
|
+
recommendations.push(`${friendlyName}: ${entry.exceedances} threshold exceedance(s) detected. Average: ${entry.average.toFixed(3)}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return recommendations;
|
|
355
|
+
}
|
|
356
|
+
getFriendlyDimensionName(key) {
|
|
357
|
+
const names = {
|
|
358
|
+
policyViolationRate: 'Policy Violation Rate',
|
|
359
|
+
intentOutcomeGap: 'Intent-Outcome Gap',
|
|
360
|
+
evaluatorDisagreement: 'Evaluator Disagreement',
|
|
361
|
+
escalationSuppression: 'Escalation Suppression',
|
|
362
|
+
rewardHacking: 'Reward Hacking',
|
|
363
|
+
};
|
|
364
|
+
return names[key] || key;
|
|
365
|
+
}
|
|
366
|
+
formatValue(value, key) {
|
|
367
|
+
if (key === 'rewardHacking') {
|
|
368
|
+
return `${value} instances`;
|
|
369
|
+
}
|
|
370
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
371
|
+
}
|
|
372
|
+
async storeHistoryEntry(entry) {
|
|
373
|
+
const history = await this.loadHistory();
|
|
374
|
+
history.entries.push(entry);
|
|
375
|
+
if (history.entries.length > 1000) {
|
|
376
|
+
history.entries = history.entries.slice(-1000);
|
|
377
|
+
}
|
|
378
|
+
await fs_extra_1.default.writeJson(this.historyFile, history, { spaces: 2 });
|
|
379
|
+
}
|
|
380
|
+
async loadHistory() {
|
|
381
|
+
try {
|
|
382
|
+
if (await fs_extra_1.default.pathExists(this.historyFile)) {
|
|
383
|
+
return await fs_extra_1.default.readJson(this.historyFile);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
// Fall through to default
|
|
388
|
+
}
|
|
389
|
+
return { entries: [] };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// ============================================================================
|
|
393
|
+
// Utility Functions
|
|
394
|
+
// ============================================================================
|
|
395
|
+
function padRight(str, length) {
|
|
396
|
+
return str.length >= length
|
|
397
|
+
? str.substring(0, length)
|
|
398
|
+
: str + ' '.repeat(length - str.length);
|
|
399
|
+
}
|
|
400
|
+
function getStatusColor(status) {
|
|
401
|
+
switch (status) {
|
|
402
|
+
case 'healthy':
|
|
403
|
+
return chalk_1.default.green;
|
|
404
|
+
case 'warning':
|
|
405
|
+
return chalk_1.default.yellow;
|
|
406
|
+
case 'critical':
|
|
407
|
+
return chalk_1.default.red;
|
|
408
|
+
default:
|
|
409
|
+
return chalk_1.default.white;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function getStatusIcon(status) {
|
|
413
|
+
switch (status) {
|
|
414
|
+
case 'healthy':
|
|
415
|
+
return '[HEALTHY]';
|
|
416
|
+
case 'warning':
|
|
417
|
+
return '[WARNING]';
|
|
418
|
+
case 'critical':
|
|
419
|
+
return '[CRITICAL]';
|
|
420
|
+
default:
|
|
421
|
+
return '[UNKNOWN]';
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function formatScore(score) {
|
|
425
|
+
if (score >= 80) {
|
|
426
|
+
return chalk_1.default.green(`${score.toFixed(1)}/100`);
|
|
427
|
+
}
|
|
428
|
+
if (score >= 50) {
|
|
429
|
+
return chalk_1.default.yellow(`${score.toFixed(1)}/100`);
|
|
430
|
+
}
|
|
431
|
+
return chalk_1.default.red(`${score.toFixed(1)}/100`);
|
|
432
|
+
}
|
|
433
|
+
function formatTrend(trend) {
|
|
434
|
+
switch (trend) {
|
|
435
|
+
case 'improving':
|
|
436
|
+
return chalk_1.default.green('Improving [^]');
|
|
437
|
+
case 'degrading':
|
|
438
|
+
return chalk_1.default.red('Degrading [v]');
|
|
439
|
+
case 'stable':
|
|
440
|
+
return chalk_1.default.gray('Stable [-]');
|
|
441
|
+
default:
|
|
442
|
+
return chalk_1.default.gray('Unknown');
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function formatPercentage(value) {
|
|
446
|
+
return `${(value * 100).toFixed(2)}%`;
|
|
447
|
+
}
|
|
448
|
+
function formatDimensionValue(value, key) {
|
|
449
|
+
if (key === 'rewardHacking') {
|
|
450
|
+
return `${value} instances`;
|
|
451
|
+
}
|
|
452
|
+
return formatPercentage(value);
|
|
453
|
+
}
|
|
454
|
+
// ============================================================================
|
|
455
|
+
// Command Factory
|
|
456
|
+
// ============================================================================
|
|
457
|
+
/**
|
|
458
|
+
* Create the alignment command with subcommands
|
|
459
|
+
*/
|
|
460
|
+
function createAlignmentCommand() {
|
|
461
|
+
const command = new commander_1.Command('alignment')
|
|
462
|
+
.description('Alignment drift monitoring and reporting')
|
|
463
|
+
.addHelpText('after', chalk_1.default.gray(`
|
|
464
|
+
Examples:
|
|
465
|
+
${chalk_1.default.green('wundr alignment report')} Generate alignment debt report
|
|
466
|
+
${chalk_1.default.green('wundr alignment score')} Get current alignment score
|
|
467
|
+
${chalk_1.default.green('wundr alignment history --days 7')} Show alignment history for past week
|
|
468
|
+
${chalk_1.default.green('wundr alignment dimensions')} Show breakdown by dimension
|
|
469
|
+
`));
|
|
470
|
+
// Report subcommand
|
|
471
|
+
command
|
|
472
|
+
.command('report')
|
|
473
|
+
.description('Generate alignment debt report')
|
|
474
|
+
.option('-s, --session <id>', 'Filter by session ID')
|
|
475
|
+
.option('-d, --days <n>', 'Number of days to analyze', '7')
|
|
476
|
+
.option('-o, --output <file>', 'Output file path for JSON report')
|
|
477
|
+
.action(async (options) => {
|
|
478
|
+
await generateAlignmentReport(options);
|
|
479
|
+
});
|
|
480
|
+
// Score subcommand
|
|
481
|
+
command
|
|
482
|
+
.command('score')
|
|
483
|
+
.description('Get current alignment score')
|
|
484
|
+
.option('-s, --session <id>', 'Get score for specific session')
|
|
485
|
+
.action(async (options) => {
|
|
486
|
+
await showAlignmentScore(options);
|
|
487
|
+
});
|
|
488
|
+
// History subcommand
|
|
489
|
+
command
|
|
490
|
+
.command('history')
|
|
491
|
+
.description('Show alignment history')
|
|
492
|
+
.option('-d, --days <n>', 'Number of days to show', '30')
|
|
493
|
+
.option('-f, --format <type>', 'Output format (table, json, chart)', 'table')
|
|
494
|
+
.action(async (options) => {
|
|
495
|
+
await showAlignmentHistory(options);
|
|
496
|
+
});
|
|
497
|
+
// Dimensions subcommand
|
|
498
|
+
command
|
|
499
|
+
.command('dimensions')
|
|
500
|
+
.description('Show breakdown by dimension')
|
|
501
|
+
.option('-s, --session <id>', 'Get dimensions for specific session')
|
|
502
|
+
.action(async (options) => {
|
|
503
|
+
await showDimensionBreakdown(options);
|
|
504
|
+
});
|
|
505
|
+
return command;
|
|
506
|
+
}
|
|
507
|
+
// ============================================================================
|
|
508
|
+
// Command Implementations
|
|
509
|
+
// ============================================================================
|
|
510
|
+
async function generateAlignmentReport(options) {
|
|
511
|
+
const spinner = (0, ora_1.default)('Generating alignment debt report...').start();
|
|
512
|
+
try {
|
|
513
|
+
const detector = new AlignmentDriftDetector();
|
|
514
|
+
await detector.initialize();
|
|
515
|
+
const days = parseInt(options.days || '7', 10);
|
|
516
|
+
const report = await detector.generateDebtReport(days, options.session, options.output);
|
|
517
|
+
spinner.stop();
|
|
518
|
+
// Display report header
|
|
519
|
+
console.log(chalk_1.default.cyan('\nAlignment Debt Report'));
|
|
520
|
+
console.log(chalk_1.default.gray('='.repeat(70)));
|
|
521
|
+
console.log(chalk_1.default.white('Generated: ') +
|
|
522
|
+
chalk_1.default.gray(new Date(report.generatedAt).toLocaleString()));
|
|
523
|
+
console.log(chalk_1.default.white('Period: ') +
|
|
524
|
+
chalk_1.default.gray(`${days} days (${new Date(report.period.start).toLocaleDateString()} - ${new Date(report.period.end).toLocaleDateString()})`));
|
|
525
|
+
if (options.session) {
|
|
526
|
+
console.log(chalk_1.default.white('Session: ') + chalk_1.default.gray(options.session));
|
|
527
|
+
}
|
|
528
|
+
// Summary section
|
|
529
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(70)));
|
|
530
|
+
console.log(chalk_1.default.cyan('Summary'));
|
|
531
|
+
console.log(chalk_1.default.white('Average Score: ') +
|
|
532
|
+
formatScore(report.summary.averageScore));
|
|
533
|
+
console.log(chalk_1.default.white('Lowest Score: ') +
|
|
534
|
+
formatScore(report.summary.lowestScore));
|
|
535
|
+
console.log(chalk_1.default.white('Highest Score: ') +
|
|
536
|
+
formatScore(report.summary.highestScore));
|
|
537
|
+
console.log(chalk_1.default.white('Trend: ') + formatTrend(report.summary.trend));
|
|
538
|
+
console.log(chalk_1.default.white('Total Violations: ') +
|
|
539
|
+
(report.summary.totalViolations > 0
|
|
540
|
+
? chalk_1.default.red(String(report.summary.totalViolations))
|
|
541
|
+
: chalk_1.default.green('0')));
|
|
542
|
+
// Dimension analysis section
|
|
543
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(70)));
|
|
544
|
+
console.log(chalk_1.default.cyan('Dimension Analysis'));
|
|
545
|
+
console.log(chalk_1.default.cyan(padRight('Dimension', 25) +
|
|
546
|
+
padRight('Average', 12) +
|
|
547
|
+
padRight('Max', 12) +
|
|
548
|
+
padRight('Exceedances', 12)));
|
|
549
|
+
console.log(chalk_1.default.gray('-'.repeat(61)));
|
|
550
|
+
const dimensionNames = {
|
|
551
|
+
policyViolationRate: 'Policy Violation Rate',
|
|
552
|
+
intentOutcomeGap: 'Intent-Outcome Gap',
|
|
553
|
+
evaluatorDisagreement: 'Evaluator Disagreement',
|
|
554
|
+
escalationSuppression: 'Escalation Suppression',
|
|
555
|
+
rewardHacking: 'Reward Hacking',
|
|
556
|
+
};
|
|
557
|
+
for (const [key, analysis] of Object.entries(report.dimensionAnalysis)) {
|
|
558
|
+
const name = dimensionNames[key] || key;
|
|
559
|
+
const entry = analysis;
|
|
560
|
+
const exceedanceColor = entry.exceedances > 0 ? chalk_1.default.red : chalk_1.default.green;
|
|
561
|
+
console.log(padRight(name, 25) +
|
|
562
|
+
padRight(formatDimensionValue(entry.average, key), 12) +
|
|
563
|
+
padRight(formatDimensionValue(entry.max, key), 12) +
|
|
564
|
+
exceedanceColor(padRight(String(entry.exceedances), 12)));
|
|
565
|
+
}
|
|
566
|
+
// Critical events section
|
|
567
|
+
if (report.criticalEvents.length > 0) {
|
|
568
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(70)));
|
|
569
|
+
console.log(chalk_1.default.red('Critical Events'));
|
|
570
|
+
for (const event of report.criticalEvents.slice(0, 5)) {
|
|
571
|
+
const dimName = dimensionNames[event.dimension] || event.dimension;
|
|
572
|
+
console.log(chalk_1.default.red(' [!] ') +
|
|
573
|
+
chalk_1.default.gray(new Date(event.timestamp).toLocaleString()) +
|
|
574
|
+
chalk_1.default.white(` ${dimName}: `) +
|
|
575
|
+
chalk_1.default.red(formatDimensionValue(event.value, event.dimension)) +
|
|
576
|
+
chalk_1.default.gray(` (threshold: ${formatDimensionValue(event.threshold, event.dimension)})`));
|
|
577
|
+
}
|
|
578
|
+
if (report.criticalEvents.length > 5) {
|
|
579
|
+
console.log(chalk_1.default.gray(` ... and ${report.criticalEvents.length - 5} more`));
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
// Recommendations section
|
|
583
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(70)));
|
|
584
|
+
console.log(chalk_1.default.cyan('Recommendations'));
|
|
585
|
+
for (const rec of report.recommendations) {
|
|
586
|
+
const color = rec.startsWith('CRITICAL')
|
|
587
|
+
? chalk_1.default.red
|
|
588
|
+
: rec.startsWith('WARNING')
|
|
589
|
+
? chalk_1.default.yellow
|
|
590
|
+
: chalk_1.default.white;
|
|
591
|
+
console.log(color(` - ${rec}`));
|
|
592
|
+
}
|
|
593
|
+
console.log(chalk_1.default.gray('='.repeat(70)));
|
|
594
|
+
// Show output file if saved
|
|
595
|
+
if (options.output) {
|
|
596
|
+
console.log(chalk_1.default.green(`\nReport saved to: ${options.output}`));
|
|
597
|
+
}
|
|
598
|
+
console.log('');
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
spinner.fail('Failed to generate alignment report');
|
|
602
|
+
console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
async function showAlignmentScore(options) {
|
|
606
|
+
const spinner = (0, ora_1.default)('Calculating alignment score...').start();
|
|
607
|
+
try {
|
|
608
|
+
const detector = new AlignmentDriftDetector();
|
|
609
|
+
await detector.initialize();
|
|
610
|
+
const result = await detector.getAlignmentScore(options.session);
|
|
611
|
+
spinner.stop();
|
|
612
|
+
console.log(chalk_1.default.cyan('\nAlignment Score'));
|
|
613
|
+
console.log(chalk_1.default.gray('='.repeat(40)));
|
|
614
|
+
// Large score display with color
|
|
615
|
+
const scoreColor = result.color === 'green'
|
|
616
|
+
? chalk_1.default.green
|
|
617
|
+
: result.color === 'yellow'
|
|
618
|
+
? chalk_1.default.yellow
|
|
619
|
+
: chalk_1.default.red;
|
|
620
|
+
const scoreDisplay = `
|
|
621
|
+
${scoreColor(' +-----------------+')}
|
|
622
|
+
${scoreColor(' | |')}
|
|
623
|
+
${scoreColor(' |')} ${chalk_1.default.bold(scoreColor(result.score.toFixed(1)))} ${scoreColor('|')}
|
|
624
|
+
${scoreColor(' |')} ${chalk_1.default.gray('/100')} ${scoreColor('|')}
|
|
625
|
+
${scoreColor(' | |')}
|
|
626
|
+
${scoreColor(' +-----------------+')}
|
|
627
|
+
`;
|
|
628
|
+
console.log(scoreDisplay);
|
|
629
|
+
const statusColor = getStatusColor(result.status);
|
|
630
|
+
console.log(chalk_1.default.white('Status: ') + statusColor(getStatusIcon(result.status)));
|
|
631
|
+
if (options.session) {
|
|
632
|
+
console.log(chalk_1.default.white('Session: ') + chalk_1.default.gray(options.session));
|
|
633
|
+
}
|
|
634
|
+
// Show quick dimension summary
|
|
635
|
+
const report = await detector.getAlignmentReport(options.session);
|
|
636
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(40)));
|
|
637
|
+
console.log(chalk_1.default.cyan('Quick Dimension Status'));
|
|
638
|
+
for (const dim of report.dimensions) {
|
|
639
|
+
const dimStatusColor = getStatusColor(dim.status);
|
|
640
|
+
const icon = dim.status === 'healthy'
|
|
641
|
+
? '[OK]'
|
|
642
|
+
: dim.status === 'warning'
|
|
643
|
+
? '[!]'
|
|
644
|
+
: '[X]';
|
|
645
|
+
console.log(dimStatusColor(` ${icon} `) +
|
|
646
|
+
chalk_1.default.white(padRight(dim.name, 25)) +
|
|
647
|
+
dimStatusColor(formatDimensionValue(dim.currentValue, dim.key)));
|
|
648
|
+
}
|
|
649
|
+
console.log(chalk_1.default.gray('='.repeat(40)));
|
|
650
|
+
console.log('');
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
spinner.fail('Failed to get alignment score');
|
|
654
|
+
console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
async function showAlignmentHistory(options) {
|
|
658
|
+
const spinner = (0, ora_1.default)('Loading alignment history...').start();
|
|
659
|
+
try {
|
|
660
|
+
const detector = new AlignmentDriftDetector();
|
|
661
|
+
await detector.initialize();
|
|
662
|
+
const days = parseInt(options.days || '30', 10);
|
|
663
|
+
const history = await detector.getHistory(days);
|
|
664
|
+
spinner.stop();
|
|
665
|
+
if (options.format === 'json') {
|
|
666
|
+
console.log(JSON.stringify({
|
|
667
|
+
timestamp: new Date().toISOString(),
|
|
668
|
+
days,
|
|
669
|
+
count: history.length,
|
|
670
|
+
entries: history,
|
|
671
|
+
}, null, 2));
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
console.log(chalk_1.default.cyan('\nAlignment History'));
|
|
675
|
+
console.log(chalk_1.default.gray('='.repeat(80)));
|
|
676
|
+
console.log(chalk_1.default.gray(`Showing last ${days} days (${history.length} entries)`));
|
|
677
|
+
if (history.length === 0) {
|
|
678
|
+
console.log(chalk_1.default.yellow('\nNo alignment history found.'));
|
|
679
|
+
console.log(chalk_1.default.gray('Run "wundr alignment score" to start tracking.'));
|
|
680
|
+
console.log('');
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (options.format === 'chart') {
|
|
684
|
+
displayHistoryChart(history);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
// Table format (default)
|
|
688
|
+
console.log(chalk_1.default.gray('\n' + '-'.repeat(80)));
|
|
689
|
+
console.log(chalk_1.default.cyan(padRight('Timestamp', 22) +
|
|
690
|
+
padRight('Score', 10) +
|
|
691
|
+
padRight('Status', 12) +
|
|
692
|
+
padRight('Session', 20) +
|
|
693
|
+
padRight('Policy', 10)));
|
|
694
|
+
console.log(chalk_1.default.gray('-'.repeat(80)));
|
|
695
|
+
for (const entry of history.slice(0, 20)) {
|
|
696
|
+
const statusColor = getStatusColor(entry.status);
|
|
697
|
+
const timestamp = new Date(entry.timestamp).toLocaleString();
|
|
698
|
+
console.log(padRight(timestamp, 22) +
|
|
699
|
+
formatScore(entry.score).padEnd(19) + // Account for ANSI codes
|
|
700
|
+
statusColor(padRight(getStatusIcon(entry.status), 12)) +
|
|
701
|
+
chalk_1.default.gray(padRight(entry.sessionId || '-', 20)) +
|
|
702
|
+
padRight(formatPercentage(entry.metrics.policyViolationRate), 10));
|
|
703
|
+
}
|
|
704
|
+
if (history.length > 20) {
|
|
705
|
+
console.log(chalk_1.default.gray(`... and ${history.length - 20} more entries`));
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
console.log(chalk_1.default.gray('='.repeat(80)));
|
|
709
|
+
console.log('');
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
spinner.fail('Failed to load alignment history');
|
|
713
|
+
console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
function displayHistoryChart(history) {
|
|
717
|
+
const chartHeight = 10;
|
|
718
|
+
const chartWidth = Math.min(60, history.length);
|
|
719
|
+
const step = Math.ceil(history.length / chartWidth);
|
|
720
|
+
const sampledHistory = history
|
|
721
|
+
.filter((_, i) => i % step === 0)
|
|
722
|
+
.slice(0, chartWidth);
|
|
723
|
+
console.log(chalk_1.default.gray('\n Score Trend:'));
|
|
724
|
+
console.log(chalk_1.default.gray(' 100 |'));
|
|
725
|
+
for (let row = chartHeight; row >= 0; row--) {
|
|
726
|
+
const threshold = (row / chartHeight) * 100;
|
|
727
|
+
let line = ` ${String(Math.round(threshold)).padStart(3)} |`;
|
|
728
|
+
for (const entry of sampledHistory) {
|
|
729
|
+
if (entry.score >= threshold &&
|
|
730
|
+
entry.score < threshold + 100 / chartHeight) {
|
|
731
|
+
const color = entry.score >= 80
|
|
732
|
+
? chalk_1.default.green
|
|
733
|
+
: entry.score >= 50
|
|
734
|
+
? chalk_1.default.yellow
|
|
735
|
+
: chalk_1.default.red;
|
|
736
|
+
line += color('*');
|
|
737
|
+
}
|
|
738
|
+
else if (entry.score >= threshold) {
|
|
739
|
+
line += chalk_1.default.gray('|');
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
line += ' ';
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
console.log(line);
|
|
746
|
+
}
|
|
747
|
+
console.log(chalk_1.default.gray(' 0 +' + '-'.repeat(chartWidth)));
|
|
748
|
+
console.log(chalk_1.default.gray(' ' +
|
|
749
|
+
'oldest'.padEnd(chartWidth / 2) +
|
|
750
|
+
'newest'.padStart(chartWidth / 2)));
|
|
751
|
+
}
|
|
752
|
+
async function showDimensionBreakdown(options) {
|
|
753
|
+
const spinner = (0, ora_1.default)('Loading dimension breakdown...').start();
|
|
754
|
+
try {
|
|
755
|
+
const detector = new AlignmentDriftDetector();
|
|
756
|
+
await detector.initialize();
|
|
757
|
+
const dimensions = await detector.getDimensionBreakdown();
|
|
758
|
+
const thresholds = detector.getThresholds();
|
|
759
|
+
spinner.stop();
|
|
760
|
+
console.log(chalk_1.default.cyan('\nAlignment Dimensions'));
|
|
761
|
+
console.log(chalk_1.default.gray('='.repeat(90)));
|
|
762
|
+
if (options.session) {
|
|
763
|
+
console.log(chalk_1.default.white('Session: ') + chalk_1.default.gray(options.session));
|
|
764
|
+
console.log('');
|
|
765
|
+
}
|
|
766
|
+
// Display each dimension in detail
|
|
767
|
+
for (const dim of dimensions) {
|
|
768
|
+
const statusColor = getStatusColor(dim.status);
|
|
769
|
+
const icon = dim.status === 'healthy'
|
|
770
|
+
? '[OK]'
|
|
771
|
+
: dim.status === 'warning'
|
|
772
|
+
? '[!!]'
|
|
773
|
+
: '[XX]';
|
|
774
|
+
console.log(chalk_1.default.gray('-'.repeat(90)));
|
|
775
|
+
console.log(chalk_1.default.bold(statusColor(`${icon} ${dim.name}`)));
|
|
776
|
+
console.log(chalk_1.default.gray(` ${dim.description}`));
|
|
777
|
+
console.log('');
|
|
778
|
+
// Value bar visualization
|
|
779
|
+
const barWidth = 40;
|
|
780
|
+
const valueRatio = Math.min(dim.currentValue / (dim.threshold * 3), 1);
|
|
781
|
+
const thresholdPos = Math.floor((dim.threshold / (dim.threshold * 3)) * barWidth);
|
|
782
|
+
const valuePos = Math.floor(valueRatio * barWidth);
|
|
783
|
+
let bar = '';
|
|
784
|
+
for (let i = 0; i < barWidth; i++) {
|
|
785
|
+
if (i === thresholdPos) {
|
|
786
|
+
bar += chalk_1.default.yellow('|');
|
|
787
|
+
}
|
|
788
|
+
else if (i < valuePos) {
|
|
789
|
+
bar += statusColor('#');
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
bar += chalk_1.default.gray('-');
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
console.log(` [${bar}]`);
|
|
796
|
+
console.log(` ${chalk_1.default.white('Current:')} ${statusColor(formatDimensionValue(dim.currentValue, dim.key))} ${chalk_1.default.white('Threshold:')} ${chalk_1.default.yellow(formatDimensionValue(dim.threshold, dim.key))}`);
|
|
797
|
+
console.log(` ${chalk_1.default.white('Status:')} ${statusColor(dim.status.toUpperCase())}`);
|
|
798
|
+
}
|
|
799
|
+
// Threshold reference
|
|
800
|
+
console.log(chalk_1.default.gray('\n' + '='.repeat(90)));
|
|
801
|
+
console.log(chalk_1.default.cyan('Threshold Reference'));
|
|
802
|
+
console.log(chalk_1.default.gray(` Policy Violation: >${formatPercentage(thresholds.policyViolation)} daily violations`));
|
|
803
|
+
console.log(chalk_1.default.gray(` Intent-Outcome Gap: >${formatPercentage(thresholds.intentOutcomeGap)} divergence`));
|
|
804
|
+
console.log(chalk_1.default.gray(` Evaluator Disagreement:>${formatPercentage(thresholds.evaluatorDisagreement)} monthly overrides`));
|
|
805
|
+
console.log(chalk_1.default.gray(` Escalation Suppression:>${formatPercentage(thresholds.escalationSuppression)} drop from baseline`));
|
|
806
|
+
console.log(chalk_1.default.gray(` Reward Hacking: >${thresholds.rewardHacking} instances/month`));
|
|
807
|
+
console.log(chalk_1.default.gray('='.repeat(90)));
|
|
808
|
+
console.log('');
|
|
809
|
+
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
spinner.fail('Failed to load dimension breakdown');
|
|
812
|
+
console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
// Export the command
|
|
816
|
+
exports.default = createAlignmentCommand;
|
|
817
|
+
//# sourceMappingURL=alignment.js.map
|