0xray 4.0.35 → 4.0.37
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/.grok-plugin/plugin.json +1 -1
- package/.xray/features.json +1 -1
- package/dist/CHANGELOG.md +25 -0
- package/dist/analytics/emerging-pattern-detector.d.ts +12 -1
- package/dist/analytics/emerging-pattern-detector.js +37 -12
- package/dist/analytics/pattern-learning-engine.js +1 -9
- package/dist/analytics/predictive-analytics.js +51 -33
- package/dist/analytics/prompt-pattern-analyzer.d.ts +1 -0
- package/dist/analytics/prompt-pattern-analyzer.js +39 -20
- package/dist/analytics/routing-performance-analyzer.d.ts +2 -0
- package/dist/analytics/routing-performance-analyzer.js +89 -37
- package/dist/analytics/simple-pattern-analyzer.d.ts +4 -0
- package/dist/analytics/simple-pattern-analyzer.js +66 -28
- package/dist/architect/architect-tools.d.ts +3 -0
- package/dist/architect/architect-tools.js +22 -0
- package/dist/cli/commands/grok-install.js +1 -1
- package/dist/cli/commands/hermes-install.js +11 -5
- package/dist/cli/commands/openclaw-install.js +13 -7
- package/dist/cli/commands/opencode-install.js +7 -4
- package/dist/cli/commands/suit-monitor.d.ts +30 -0
- package/dist/cli/commands/suit-monitor.js +128 -0
- package/dist/cli/index.js +52 -15
- package/dist/cli/suit-pulse.d.ts +29 -0
- package/dist/cli/suit-pulse.js +270 -0
- package/dist/delegation/agent-delegator.d.ts +4 -2
- package/dist/delegation/agent-delegator.js +46 -27
- package/dist/delegation/agent-expertise.js +2 -1
- package/dist/delegation/analytics/outcome-tracker.d.ts +6 -0
- package/dist/delegation/analytics/outcome-tracker.js +17 -3
- package/dist/delegation/ast-code-parser.d.ts +5 -0
- package/dist/delegation/ast-code-parser.js +53 -48
- package/dist/delegation/codebase-context-analyzer.d.ts +3 -7
- package/dist/delegation/codebase-context-analyzer.js +188 -159
- package/dist/delegation/session-coordinator.js +3 -2
- package/dist/enforcement/loaders/codex-loader.js +18 -14
- package/dist/enforcement/validators/architecture-validators.js +115 -9
- package/dist/governance/codex-policy.service.d.ts +12 -2
- package/dist/governance/codex-policy.service.js +91 -16
- package/dist/integrations/grok/hooks/session-start.js +6 -6
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +6 -6
- package/dist/integrations/hooks/goggles-mcp.mjs +10 -3
- package/dist/integrations/hooks/goggles-pipeline.mjs +221 -44
- package/dist/integrations/hooks/goggles-planes.json +172 -8
- package/dist/integrations/hooks/plates.cjs +138 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +63 -5
- package/dist/integrations/hooks/write-home.cjs +59 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/architect-tools.server.d.ts +6 -0
- package/dist/mcps/architect-tools.server.js +19 -18
- package/dist/mcps/orchestrator/server.d.ts +4 -3
- package/dist/mcps/orchestrator/server.js +29 -17
- package/dist/memory-routing/lookup-cache.d.ts +8 -0
- package/dist/memory-routing/lookup-cache.js +72 -0
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +26 -0
- package/dist/memory-routing/provider-loader.js +3 -0
- package/dist/metrics/agent-metrics.d.ts +14 -5
- package/dist/metrics/agent-metrics.js +362 -224
- package/dist/nucleus/synthesis-consult-receipt.js +38 -16
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.d.ts +5 -0
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.js +9 -0
- package/dist/orchestrator/multi-agent-orchestration-coordinator.js +1 -2
- package/dist/orchestrator/orchestrator.js +1 -2
- package/dist/processors/implementations/agents-md-validation-processor.d.ts +0 -1
- package/dist/processors/implementations/agents-md-validation-processor.js +0 -11
- package/dist/processors/implementations/console-log-guard-processor.js +39 -50
- package/dist/processors/implementations/performance-budget-processor.d.ts +0 -5
- package/dist/processors/implementations/performance-budget-processor.js +29 -38
- package/dist/processors/implementations/storytelling-trigger-processor.d.ts +5 -0
- package/dist/processors/implementations/storytelling-trigger-processor.js +69 -16
- package/dist/processors/implementations/test-auto-creation-processor.js +39 -36
- package/dist/reporting/framework-reporting-system.d.ts +3 -0
- package/dist/reporting/framework-reporting-system.js +61 -8
- package/dist/reporting/log-parser.js +188 -105
- package/dist/reporting/metrics.js +42 -18
- package/dist/security/prompt-security-validator.js +8 -7
- package/dist/security/security-auditor.d.ts +4 -0
- package/dist/security/security-auditor.js +132 -57
- package/dist/security/security-hardener.d.ts +2 -0
- package/dist/security/security-hardener.js +31 -6
- package/dist/security/security-headers.d.ts +2 -0
- package/dist/security/security-headers.js +23 -21
- package/dist/security/security-scanner.js +18 -4
- package/dist/session/session-cleanup-manager.d.ts +2 -0
- package/dist/session/session-cleanup-manager.js +29 -8
- package/dist/session/session-monitor.d.ts +14 -4
- package/dist/session/session-monitor.js +208 -106
- package/dist/session/session-state-manager.d.ts +11 -0
- package/dist/session/session-state-manager.js +90 -8
- package/docs-site/docs/plates/activity-log.md +38 -0
- package/docs-site/docs/plates/cursor-compact.md +35 -0
- package/docs-site/docs/plates/grok-compact.md +35 -0
- package/docs-site/docs/plates/index.md +25 -3
- package/docs-site/docs/plates/inference-files.md +35 -0
- package/docs-site/docs/plates/kept-line.md +35 -0
- package/docs-site/docs/plates/lens-gate.md +35 -0
- package/docs-site/docs/plates/lens-page.md +35 -0
- package/docs-site/docs/plates/notes-page.md +35 -0
- package/docs-site/docs/plates/package-face.md +35 -0
- package/docs-site/docs/plates/payload-heat.md +35 -0
- package/docs-site/docs/plates/pickup-stamp.md +35 -0
- package/docs-site/docs/plates/pre-tool.md +35 -0
- package/docs-site/docs/plates/record-map.md +41 -0
- package/docs-site/docs/plates/reflection-page.md +35 -0
- package/docs-site/docs/plates/review.md +57 -0
- package/docs-site/docs/plates/session-capture.md +38 -0
- package/docs-site/docs/plates/site-manual.md +35 -0
- package/docs-site/docs/plates/stamp-plate.md +35 -0
- package/docs-site/docs/plates/station-card.md +35 -0
- package/docs-site/docs/plates/station-heat.md +35 -0
- package/docs-site/docs/plates/suit-organs.md +38 -0
- package/docs-site/docs/plates/suit-settings.md +35 -0
- package/docs-site/docs/plates/suit-wear.md +37 -0
- package/docs-site/docs/plates/trail-state.md +35 -0
- package/docs-site/docs/plates/work-fresh.md +35 -0
- package/docs-site/docs/plates/write-home.md +38 -0
- package/package.json +4 -2
- package/scripts/mjs/run-grok-hook.mjs +50 -0
- package/scripts/node/install-bridges.cjs +305 -81
- package/scripts/node/postinstall.cjs +14 -3
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +6 -6
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/architect-tools.server.ts +25 -20
- package/src/mcps/orchestrator/server.ts +33 -19
- package/xray/features.json +1 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { getComprehensiveLogs, filterLogsByConfig, frameworkLogToParsedEntry, } from "./log-parser.js";
|
|
5
6
|
import { calculateTimeRange, calculateMetrics, calculatePeakActivity, calculateHealthScore, generateInsights, generateRecommendations, generateAlerts, } from "./metrics.js";
|
|
6
7
|
import { formatReport } from "./report-formatter.js";
|
|
@@ -11,11 +12,11 @@ export class FrameworkReportingSystem {
|
|
|
11
12
|
const reportId = this.generateReportId(config);
|
|
12
13
|
const cached = this.getCachedReport(reportId);
|
|
13
14
|
if (cached && this.isCacheValid(cached.timestamp)) {
|
|
14
|
-
return
|
|
15
|
+
return cached.formatted;
|
|
15
16
|
}
|
|
16
17
|
const reportData = await this.collectReportData(config);
|
|
17
|
-
this.cacheReport(reportId, reportData);
|
|
18
18
|
const formattedReport = formatReport(reportData, config.outputFormat);
|
|
19
|
+
this.cacheReport(reportId, reportData, formattedReport);
|
|
19
20
|
if (config.outputPath) {
|
|
20
21
|
await this.saveReportToFile(formattedReport, config.outputPath);
|
|
21
22
|
}
|
|
@@ -49,8 +50,14 @@ export class FrameworkReportingSystem {
|
|
|
49
50
|
...new Set(recentLogs.map((log) => log.component)),
|
|
50
51
|
];
|
|
51
52
|
const recentActivity = parsedLogs.slice(0, 10);
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
let errorCount = 0;
|
|
54
|
+
let successCount = 0;
|
|
55
|
+
for (const log of recentLogs) {
|
|
56
|
+
if (log.status === "error")
|
|
57
|
+
errorCount++;
|
|
58
|
+
else if (log.status === "success")
|
|
59
|
+
successCount++;
|
|
60
|
+
}
|
|
54
61
|
const healthScore = recentLogs.length > 0
|
|
55
62
|
? (successCount / (successCount + errorCount)) * 100
|
|
56
63
|
: 100;
|
|
@@ -82,8 +89,50 @@ const report = await reportingSystem.generateCustomReport('${template.name}');
|
|
|
82
89
|
`;
|
|
83
90
|
}
|
|
84
91
|
generateReportId(config) {
|
|
85
|
-
const
|
|
86
|
-
|
|
92
|
+
const range = config.timeRange;
|
|
93
|
+
const file = this.currentLogStamp();
|
|
94
|
+
return JSON.stringify([
|
|
95
|
+
config.type,
|
|
96
|
+
config.outputFormat,
|
|
97
|
+
range?.lastHours ?? null,
|
|
98
|
+
range?.start?.toISOString() ?? null,
|
|
99
|
+
range?.end?.toISOString() ?? null,
|
|
100
|
+
config.sessionId ?? null,
|
|
101
|
+
config.jobId ?? null,
|
|
102
|
+
file.size,
|
|
103
|
+
file.mtimeMs,
|
|
104
|
+
this.memoryLogStamp(),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
// Same activity.log path readCurrentLogFile rebuilds from size and mtime.
|
|
108
|
+
activityLogFile() {
|
|
109
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
110
|
+
const projectRoot = path.resolve(path.dirname(currentFilePath), "../../");
|
|
111
|
+
return path.join(projectRoot, "logs", "framework", "activity.log");
|
|
112
|
+
}
|
|
113
|
+
currentLogStamp() {
|
|
114
|
+
try {
|
|
115
|
+
const stat = fs.statSync(this.activityLogFile());
|
|
116
|
+
return { size: stat.size, mtimeMs: stat.mtimeMs };
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return { size: -1, mtimeMs: -1 };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
memoryLogStamp() {
|
|
123
|
+
const recent = frameworkLogger.getRecentLogs(1000);
|
|
124
|
+
const last = recent[recent.length - 1];
|
|
125
|
+
if (!last)
|
|
126
|
+
return "0";
|
|
127
|
+
return [
|
|
128
|
+
recent.length,
|
|
129
|
+
last.timestamp,
|
|
130
|
+
last.component,
|
|
131
|
+
last.action,
|
|
132
|
+
last.status,
|
|
133
|
+
last.sessionId ?? "",
|
|
134
|
+
last.jobId ?? "",
|
|
135
|
+
].join("\0");
|
|
87
136
|
}
|
|
88
137
|
getCachedReport(reportId) {
|
|
89
138
|
return this.reportCache.get(reportId) || null;
|
|
@@ -93,8 +142,12 @@ const report = await reportingSystem.generateCustomReport('${template.name}');
|
|
|
93
142
|
const maxCacheAgeMs = 5 * 60 * 1000;
|
|
94
143
|
return cacheAgeMs < maxCacheAgeMs;
|
|
95
144
|
}
|
|
96
|
-
cacheReport(reportId, data) {
|
|
97
|
-
this.reportCache.set(reportId, {
|
|
145
|
+
cacheReport(reportId, data, formatted) {
|
|
146
|
+
this.reportCache.set(reportId, {
|
|
147
|
+
data,
|
|
148
|
+
formatted,
|
|
149
|
+
timestamp: new Date(),
|
|
150
|
+
});
|
|
98
151
|
if (this.reportCache.size > 10) {
|
|
99
152
|
const keys = Array.from(this.reportCache.keys());
|
|
100
153
|
if (keys.length > 0) {
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
+
import { createGunzip } from "zlib";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
6
|
+
const LOG_LINE_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)$/;
|
|
7
|
+
const LOG_LINE_FALLBACK_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)$/;
|
|
8
|
+
// Parsed rows stay cached while size and mtime stay the same.
|
|
9
|
+
let currentLogCache = null;
|
|
10
|
+
const rotatedLogCache = new Map();
|
|
5
11
|
export function levelToStatus(level) {
|
|
6
12
|
switch (level.toUpperCase()) {
|
|
7
13
|
case "ERROR":
|
|
@@ -37,8 +43,7 @@ export function inferAgent(component) {
|
|
|
37
43
|
return "system";
|
|
38
44
|
}
|
|
39
45
|
export function parseLogLine(line) {
|
|
40
|
-
const
|
|
41
|
-
const match = line.match(logRegex);
|
|
46
|
+
const match = line.match(LOG_LINE_RE);
|
|
42
47
|
if (match && match[1] && match[2] && match[3] && match[4] && match[5]) {
|
|
43
48
|
const timestamp = match[1];
|
|
44
49
|
const jobId = match[2];
|
|
@@ -60,8 +65,7 @@ export function parseLogLine(line) {
|
|
|
60
65
|
agent: inferAgent(component),
|
|
61
66
|
};
|
|
62
67
|
}
|
|
63
|
-
const
|
|
64
|
-
const fallbackMatch = line.match(fallbackRegex);
|
|
68
|
+
const fallbackMatch = line.match(LOG_LINE_FALLBACK_RE);
|
|
65
69
|
if (fallbackMatch &&
|
|
66
70
|
fallbackMatch[1] &&
|
|
67
71
|
fallbackMatch[2] &&
|
|
@@ -102,86 +106,154 @@ export function frameworkLogToParsedEntry(entry) {
|
|
|
102
106
|
details: entry.details,
|
|
103
107
|
};
|
|
104
108
|
}
|
|
105
|
-
|
|
109
|
+
function parseLogContent(content) {
|
|
106
110
|
const logs = [];
|
|
111
|
+
const lines = content.split("\n");
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
if (!line.trim())
|
|
114
|
+
continue;
|
|
115
|
+
try {
|
|
116
|
+
const logEntry = parseLogLine(line);
|
|
117
|
+
if (logEntry)
|
|
118
|
+
logs.push(logEntry);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Continue processing other lines
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return logs;
|
|
125
|
+
}
|
|
126
|
+
function windowOf(timeRange) {
|
|
127
|
+
const startTime = timeRange?.start?.getTime() ??
|
|
128
|
+
(timeRange?.lastHours
|
|
129
|
+
? Date.now() - timeRange.lastHours * 60 * 60 * 1000
|
|
130
|
+
: 0);
|
|
131
|
+
const endTime = timeRange?.end?.getTime() ?? Date.now();
|
|
132
|
+
return { startTime, endTime };
|
|
133
|
+
}
|
|
134
|
+
function withinWindow(logs, startTime, endTime) {
|
|
135
|
+
const filtered = [];
|
|
136
|
+
for (const log of logs) {
|
|
137
|
+
if (log.timestamp >= startTime && log.timestamp <= endTime) {
|
|
138
|
+
filtered.push(log);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return filtered;
|
|
142
|
+
}
|
|
143
|
+
// Length prefixes keep the first timestamp + component + action row.
|
|
144
|
+
function eventKey(log) {
|
|
145
|
+
const component = log.component;
|
|
146
|
+
const action = log.action;
|
|
147
|
+
return `${log.timestamp}\0${component.length}\0${component}\0${action.length}\0${action}`;
|
|
148
|
+
}
|
|
149
|
+
function uniqueSorted(logs) {
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
const unique = [];
|
|
152
|
+
for (const log of logs) {
|
|
153
|
+
const key = eventKey(log);
|
|
154
|
+
if (seen.has(key))
|
|
155
|
+
continue;
|
|
156
|
+
seen.add(key);
|
|
157
|
+
unique.push(log);
|
|
158
|
+
}
|
|
159
|
+
unique.sort((a, b) => a.timestamp - b.timestamp);
|
|
160
|
+
return unique;
|
|
161
|
+
}
|
|
162
|
+
export async function readCurrentLogFile(timeRange) {
|
|
107
163
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
108
164
|
const projectRoot = path.resolve(path.dirname(currentFilePath), "../../");
|
|
109
|
-
const
|
|
110
|
-
const logFile = path.join(logDir, "activity.log");
|
|
165
|
+
const logFile = path.join(projectRoot, "logs", "framework", "activity.log");
|
|
111
166
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return
|
|
167
|
+
if (!fs.existsSync(logFile)) {
|
|
168
|
+
currentLogCache = null;
|
|
169
|
+
return [];
|
|
115
170
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
// Continue processing other lines
|
|
135
|
-
}
|
|
171
|
+
const before = fs.statSync(logFile);
|
|
172
|
+
let entries;
|
|
173
|
+
const hit = currentLogCache;
|
|
174
|
+
if (hit && hit.mtimeMs === before.mtimeMs && hit.size === before.size) {
|
|
175
|
+
entries = hit.entries;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const content = fs.readFileSync(logFile, "utf8");
|
|
179
|
+
const after = fs.statSync(logFile);
|
|
180
|
+
const parsed = parseLogContent(content);
|
|
181
|
+
if (before.mtimeMs === after.mtimeMs && before.size === after.size) {
|
|
182
|
+
currentLogCache = {
|
|
183
|
+
mtimeMs: after.mtimeMs,
|
|
184
|
+
size: after.size,
|
|
185
|
+
entries: parsed,
|
|
186
|
+
};
|
|
136
187
|
}
|
|
188
|
+
else {
|
|
189
|
+
currentLogCache = null;
|
|
190
|
+
}
|
|
191
|
+
entries = parsed;
|
|
137
192
|
}
|
|
193
|
+
const { startTime, endTime } = windowOf(timeRange);
|
|
194
|
+
return withinWindow(entries, startTime, endTime);
|
|
138
195
|
}
|
|
139
196
|
catch (error) {
|
|
140
197
|
await frameworkLogger.log("framework-reporting-system", "current-log-read-failed", "warning", { error: String(error) });
|
|
141
198
|
}
|
|
142
|
-
return
|
|
199
|
+
return [];
|
|
143
200
|
}
|
|
144
201
|
export async function parseCompressedLogFile(filePath, startTime, endTime) {
|
|
145
202
|
return new Promise((resolve, reject) => {
|
|
146
203
|
const logs = [];
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (logEntry &&
|
|
165
|
-
logEntry.timestamp >= startTime &&
|
|
166
|
-
logEntry.timestamp <= endTime) {
|
|
167
|
-
logs.push(logEntry);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
// Skip malformed lines
|
|
204
|
+
let buffer = "";
|
|
205
|
+
try {
|
|
206
|
+
const readStream = fs.createReadStream(filePath);
|
|
207
|
+
readStream
|
|
208
|
+
.pipe(createGunzip())
|
|
209
|
+
.on("data", (chunk) => {
|
|
210
|
+
buffer += chunk.toString();
|
|
211
|
+
const lines = buffer.split("\n");
|
|
212
|
+
buffer = lines.pop() || "";
|
|
213
|
+
for (const line of lines) {
|
|
214
|
+
if (line.trim()) {
|
|
215
|
+
try {
|
|
216
|
+
const logEntry = parseLogLine(line);
|
|
217
|
+
if (logEntry &&
|
|
218
|
+
logEntry.timestamp >= startTime &&
|
|
219
|
+
logEntry.timestamp <= endTime) {
|
|
220
|
+
logs.push(logEntry);
|
|
172
221
|
}
|
|
173
222
|
}
|
|
223
|
+
catch {
|
|
224
|
+
// Skip malformed lines
|
|
225
|
+
}
|
|
174
226
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
.on("end", () => resolve(logs))
|
|
230
|
+
.on("error", reject);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
reject(error);
|
|
234
|
+
}
|
|
183
235
|
});
|
|
184
236
|
}
|
|
237
|
+
async function cachedRotatedEntries(filePath) {
|
|
238
|
+
const before = fs.statSync(filePath);
|
|
239
|
+
const hit = rotatedLogCache.get(filePath);
|
|
240
|
+
if (hit && hit.mtimeMs === before.mtimeMs && hit.size === before.size) {
|
|
241
|
+
return hit.entries;
|
|
242
|
+
}
|
|
243
|
+
const entries = await parseCompressedLogFile(filePath, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);
|
|
244
|
+
const after = fs.statSync(filePath);
|
|
245
|
+
if (before.mtimeMs === after.mtimeMs && before.size === after.size) {
|
|
246
|
+
rotatedLogCache.set(filePath, {
|
|
247
|
+
mtimeMs: after.mtimeMs,
|
|
248
|
+
size: after.size,
|
|
249
|
+
entries,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
rotatedLogCache.delete(filePath);
|
|
254
|
+
}
|
|
255
|
+
return entries;
|
|
256
|
+
}
|
|
185
257
|
export async function readRotatedLogFiles(timeRange) {
|
|
186
258
|
const logs = [];
|
|
187
259
|
const logDir = path.join(process.cwd(), "logs", "framework");
|
|
@@ -193,15 +265,18 @@ export async function readRotatedLogFiles(timeRange) {
|
|
|
193
265
|
.filter((file) => file.startsWith("framework-activity-") && file.endsWith(".log.gz"))
|
|
194
266
|
.sort()
|
|
195
267
|
.reverse();
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
268
|
+
const keep = new Set(files.slice(0, 3).map((file) => path.join(logDir, file)));
|
|
269
|
+
for (const key of rotatedLogCache.keys()) {
|
|
270
|
+
if (!keep.has(key))
|
|
271
|
+
rotatedLogCache.delete(key);
|
|
272
|
+
}
|
|
273
|
+
const { startTime, endTime } = windowOf(timeRange);
|
|
201
274
|
for (const file of files.slice(0, 3)) {
|
|
275
|
+
const filePath = path.join(logDir, file);
|
|
202
276
|
try {
|
|
203
|
-
const fileLogs = await
|
|
204
|
-
|
|
277
|
+
const fileLogs = withinWindow(await cachedRotatedEntries(filePath), startTime, endTime);
|
|
278
|
+
for (const entry of fileLogs)
|
|
279
|
+
logs.push(entry);
|
|
205
280
|
if (logs.length > 5000)
|
|
206
281
|
break;
|
|
207
282
|
}
|
|
@@ -216,12 +291,15 @@ export async function readRotatedLogFiles(timeRange) {
|
|
|
216
291
|
return logs;
|
|
217
292
|
}
|
|
218
293
|
export async function getComprehensiveLogs(config) {
|
|
294
|
+
const allLogs = [];
|
|
219
295
|
const recentLogs = frameworkLogger.getRecentLogs(1000);
|
|
220
|
-
const
|
|
221
|
-
|
|
296
|
+
for (const entry of recentLogs) {
|
|
297
|
+
allLogs.push(frameworkLogToParsedEntry(entry));
|
|
298
|
+
}
|
|
222
299
|
try {
|
|
223
300
|
const currentLogs = await readCurrentLogFile(config.timeRange);
|
|
224
|
-
|
|
301
|
+
for (const entry of currentLogs)
|
|
302
|
+
allLogs.push(entry);
|
|
225
303
|
}
|
|
226
304
|
catch (error) {
|
|
227
305
|
await frameworkLogger.log("framework-reporting-system", "current-log-read-failed", "warning", { error: String(error) });
|
|
@@ -234,48 +312,53 @@ export async function getComprehensiveLogs(config) {
|
|
|
234
312
|
24 * 60 * 60 * 1000))) {
|
|
235
313
|
try {
|
|
236
314
|
const rotatedLogs = await readRotatedLogFiles(config.timeRange);
|
|
237
|
-
|
|
315
|
+
for (const entry of rotatedLogs)
|
|
316
|
+
allLogs.push(entry);
|
|
238
317
|
}
|
|
239
318
|
catch (error) {
|
|
240
319
|
await frameworkLogger.log("framework-reporting-system", "rotated-logs-read-failed", "warning", { error: String(error) });
|
|
241
320
|
}
|
|
242
321
|
}
|
|
243
|
-
|
|
244
|
-
self.findIndex((l) => l.timestamp === log.timestamp &&
|
|
245
|
-
l.component === log.component &&
|
|
246
|
-
l.action === log.action));
|
|
247
|
-
return uniqueLogs.sort((a, b) => a.timestamp - b.timestamp);
|
|
322
|
+
return uniqueSorted(allLogs);
|
|
248
323
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (config.sessionId) {
|
|
252
|
-
filtered = filtered.filter((log) => log.sessionId === config.sessionId);
|
|
253
|
-
}
|
|
254
|
-
if (config.jobId) {
|
|
255
|
-
filtered = filtered.filter((log) => log.jobId === config.jobId);
|
|
256
|
-
}
|
|
257
|
-
if (config.timeRange) {
|
|
258
|
-
const startTime = config.timeRange.start?.getTime() ??
|
|
259
|
-
(config.timeRange.lastHours
|
|
260
|
-
? Date.now() - config.timeRange.lastHours * 60 * 60 * 1000
|
|
261
|
-
: 0);
|
|
262
|
-
const endTime = config.timeRange.end?.getTime() ?? Date.now();
|
|
263
|
-
filtered = filtered.filter((log) => log.timestamp >= startTime && log.timestamp <= endTime);
|
|
264
|
-
}
|
|
265
|
-
switch (config.type) {
|
|
324
|
+
function matchesReportType(log, type) {
|
|
325
|
+
switch (type) {
|
|
266
326
|
case "orchestration":
|
|
267
|
-
|
|
327
|
+
return (log.component === "agent-delegator" ||
|
|
268
328
|
log.action.includes("delegation"));
|
|
269
|
-
break;
|
|
270
329
|
case "agent-usage":
|
|
271
|
-
|
|
272
|
-
break;
|
|
330
|
+
return Boolean(log.agent) || log.component.includes("agent");
|
|
273
331
|
case "context-awareness":
|
|
274
|
-
|
|
275
|
-
break;
|
|
332
|
+
return (log.component.includes("context") || log.component.includes("ast"));
|
|
276
333
|
case "performance":
|
|
277
|
-
|
|
278
|
-
|
|
334
|
+
return (log.action.includes("complete") || log.action.includes("failed"));
|
|
335
|
+
default:
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
export function filterLogsByConfig(logs, config) {
|
|
340
|
+
const sessionId = config.sessionId;
|
|
341
|
+
const jobId = config.jobId;
|
|
342
|
+
let startTime = 0;
|
|
343
|
+
let endTime = 0;
|
|
344
|
+
const hasTime = Boolean(config.timeRange);
|
|
345
|
+
if (config.timeRange) {
|
|
346
|
+
const window = windowOf(config.timeRange);
|
|
347
|
+
startTime = window.startTime;
|
|
348
|
+
endTime = window.endTime;
|
|
349
|
+
}
|
|
350
|
+
const filtered = [];
|
|
351
|
+
for (const log of logs) {
|
|
352
|
+
if (sessionId && log.sessionId !== sessionId)
|
|
353
|
+
continue;
|
|
354
|
+
if (jobId && log.jobId !== jobId)
|
|
355
|
+
continue;
|
|
356
|
+
if (hasTime && (log.timestamp < startTime || log.timestamp > endTime)) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (!matchesReportType(log, config.type))
|
|
360
|
+
continue;
|
|
361
|
+
filtered.push(log);
|
|
279
362
|
}
|
|
280
363
|
return filtered;
|
|
281
364
|
}
|
|
@@ -2,10 +2,21 @@ export function calculateTimeRange(logs, timeRange) {
|
|
|
2
2
|
if (logs.length === 0) {
|
|
3
3
|
return { start: new Date(), end: new Date() };
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
let min = Infinity;
|
|
6
|
+
let max = -Infinity;
|
|
7
|
+
for (const log of logs) {
|
|
8
|
+
const ts = log.timestamp;
|
|
9
|
+
if (Number.isNaN(ts)) {
|
|
10
|
+
return { start: new Date(NaN), end: new Date(NaN) };
|
|
11
|
+
}
|
|
12
|
+
if (ts < min)
|
|
13
|
+
min = ts;
|
|
14
|
+
if (ts > max)
|
|
15
|
+
max = ts;
|
|
16
|
+
}
|
|
6
17
|
return {
|
|
7
|
-
start: new Date(
|
|
8
|
-
end: new Date(
|
|
18
|
+
start: new Date(min),
|
|
19
|
+
end: new Date(max),
|
|
9
20
|
};
|
|
10
21
|
}
|
|
11
22
|
export function calculateMetrics(logs) {
|
|
@@ -22,8 +33,11 @@ export function calculateMetrics(logs) {
|
|
|
22
33
|
let terminalOperations = 0;
|
|
23
34
|
let analysisOperations = 0;
|
|
24
35
|
let orchestrationOperations = 0;
|
|
36
|
+
let successCount = 0;
|
|
25
37
|
const responseTimes = [];
|
|
26
38
|
for (const log of logs) {
|
|
39
|
+
if (log.status === "success")
|
|
40
|
+
successCount++;
|
|
27
41
|
if (log.agent) {
|
|
28
42
|
agentUsage.set(log.agent, (agentUsage.get(log.agent) || 0) + 1);
|
|
29
43
|
}
|
|
@@ -52,8 +66,6 @@ export function calculateMetrics(logs) {
|
|
|
52
66
|
if (log.status === "success") {
|
|
53
67
|
toolStats.success++;
|
|
54
68
|
}
|
|
55
|
-
toolStats.rate =
|
|
56
|
-
toolStats.total > 0 ? (toolStats.success / toolStats.total) * 100 : 0;
|
|
57
69
|
if (["write", "edit", "read"].includes(toolName)) {
|
|
58
70
|
fileOperations++;
|
|
59
71
|
}
|
|
@@ -72,9 +84,7 @@ export function calculateMetrics(logs) {
|
|
|
72
84
|
toolSuccessRate.forEach((stats) => {
|
|
73
85
|
stats.rate = stats.total > 0 ? (stats.success / stats.total) * 100 : 0;
|
|
74
86
|
});
|
|
75
|
-
const
|
|
76
|
-
const errorLogs = logs.filter((log) => log.status === "error");
|
|
77
|
-
const successRate = logs.length > 0 ? (successLogs.length / logs.length) * 100 : 100;
|
|
87
|
+
const successRate = logs.length > 0 ? (successCount / logs.length) * 100 : 100;
|
|
78
88
|
const enhancementSuccessRate = enhancementSuccesses + enhancementFailures > 0
|
|
79
89
|
? (enhancementSuccesses /
|
|
80
90
|
(enhancementSuccesses + enhancementFailures)) *
|
|
@@ -117,25 +127,36 @@ export function calculateMetrics(logs) {
|
|
|
117
127
|
export function calculatePeakActivity(logs) {
|
|
118
128
|
const minuteGroups = new Map();
|
|
119
129
|
for (const log of logs) {
|
|
120
|
-
const
|
|
130
|
+
const ts = log.timestamp;
|
|
131
|
+
const minute = Number.isFinite(ts)
|
|
132
|
+
? Math.floor(ts / 60000) * 60000
|
|
133
|
+
: new Date(new Date(ts).toISOString().slice(0, 16) + ":00Z").getTime();
|
|
121
134
|
minuteGroups.set(minute, (minuteGroups.get(minute) || 0) + 1);
|
|
122
135
|
}
|
|
123
|
-
let peakMinute =
|
|
136
|
+
let peakMinute = 0;
|
|
124
137
|
let peakCount = 0;
|
|
138
|
+
let found = false;
|
|
125
139
|
for (const [minute, count] of minuteGroups) {
|
|
126
140
|
if (count > peakCount) {
|
|
127
141
|
peakCount = count;
|
|
128
142
|
peakMinute = minute;
|
|
143
|
+
found = true;
|
|
129
144
|
}
|
|
130
145
|
}
|
|
131
146
|
return {
|
|
132
|
-
timestamp:
|
|
147
|
+
timestamp: found ? new Date(peakMinute) : new Date(),
|
|
133
148
|
eventsPerMinute: peakCount,
|
|
134
149
|
};
|
|
135
150
|
}
|
|
136
151
|
export function calculateHealthScore(logs) {
|
|
137
|
-
|
|
138
|
-
|
|
152
|
+
let successCount = 0;
|
|
153
|
+
let errorCount = 0;
|
|
154
|
+
for (const log of logs) {
|
|
155
|
+
if (log.status === "success")
|
|
156
|
+
successCount++;
|
|
157
|
+
else if (log.status === "error")
|
|
158
|
+
errorCount++;
|
|
159
|
+
}
|
|
139
160
|
if (successCount + errorCount === 0)
|
|
140
161
|
return 100;
|
|
141
162
|
return (successCount / (successCount + errorCount)) * 100;
|
|
@@ -175,11 +196,14 @@ export function generateRecommendations(metrics) {
|
|
|
175
196
|
}
|
|
176
197
|
export function generateAlerts(logs) {
|
|
177
198
|
const alerts = [];
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
.
|
|
181
|
-
|
|
182
|
-
alerts.push(`${
|
|
199
|
+
let errorsKept = 0;
|
|
200
|
+
for (const log of logs) {
|
|
201
|
+
if (log.status !== "error")
|
|
202
|
+
continue;
|
|
203
|
+
alerts.push(`${log.component}:${log.action} failed`);
|
|
204
|
+
errorsKept++;
|
|
205
|
+
if (errorsKept === 3)
|
|
206
|
+
break;
|
|
183
207
|
}
|
|
184
208
|
const highFrequencyComponents = getHighFrequencyComponents(logs);
|
|
185
209
|
for (const component of highFrequencyComponents) {
|
|
@@ -38,19 +38,21 @@ export class PromptSecurityValidator {
|
|
|
38
38
|
violations.push(`Prompt too long: ${prompt.length} > ${this.config.maxPromptLength}`);
|
|
39
39
|
riskLevel = "medium";
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
const folded = prompt.toLowerCase();
|
|
42
|
+
// Blocked pattern check. Reset lastIndex so a previous call cannot hide this one.
|
|
42
43
|
for (const pattern of this.config.blockedPatterns) {
|
|
44
|
+
pattern.lastIndex = 0;
|
|
43
45
|
if (pattern.test(prompt)) {
|
|
44
46
|
violations.push(`Blocked pattern detected: ${pattern.source}`);
|
|
45
47
|
riskLevel = "high";
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
// Advanced pattern analysis
|
|
49
|
-
if (this.containsSystemPromptOverride(
|
|
51
|
+
if (this.containsSystemPromptOverride(folded)) {
|
|
50
52
|
violations.push("Potential system prompt override attempt");
|
|
51
53
|
riskLevel = "critical";
|
|
52
54
|
}
|
|
53
|
-
if (this.containsInjectionAttempts(
|
|
55
|
+
if (this.containsInjectionAttempts(folded)) {
|
|
54
56
|
violations.push("Potential prompt injection detected");
|
|
55
57
|
riskLevel = "high";
|
|
56
58
|
}
|
|
@@ -66,7 +68,7 @@ export class PromptSecurityValidator {
|
|
|
66
68
|
/**
|
|
67
69
|
* Check for system prompt override attempts
|
|
68
70
|
*/
|
|
69
|
-
containsSystemPromptOverride(
|
|
71
|
+
containsSystemPromptOverride(lowerPrompt) {
|
|
70
72
|
const overrideIndicators = [
|
|
71
73
|
"you are now",
|
|
72
74
|
"act as if",
|
|
@@ -78,13 +80,12 @@ export class PromptSecurityValidator {
|
|
|
78
80
|
"new personality",
|
|
79
81
|
"different role",
|
|
80
82
|
];
|
|
81
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
82
83
|
return overrideIndicators.some((indicator) => lowerPrompt.includes(indicator));
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
* Check for prompt injection attempts
|
|
86
87
|
*/
|
|
87
|
-
containsInjectionAttempts(
|
|
88
|
+
containsInjectionAttempts(lowerPrompt) {
|
|
88
89
|
const injectionIndicators = [
|
|
89
90
|
"ignore previous",
|
|
90
91
|
"forget instructions",
|
|
@@ -94,7 +95,6 @@ export class PromptSecurityValidator {
|
|
|
94
95
|
"clear memory",
|
|
95
96
|
"delete history",
|
|
96
97
|
];
|
|
97
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
98
98
|
return injectionIndicators.some((indicator) => lowerPrompt.includes(indicator));
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
@@ -104,6 +104,7 @@ export class PromptSecurityValidator {
|
|
|
104
104
|
let sanitized = prompt;
|
|
105
105
|
// Remove blocked patterns
|
|
106
106
|
for (const pattern of this.config.blockedPatterns) {
|
|
107
|
+
pattern.lastIndex = 0;
|
|
107
108
|
sanitized = sanitized.replace(pattern, "[REDACTED]");
|
|
108
109
|
}
|
|
109
110
|
// Additional sanitization based on level
|