@vainplex/openclaw-leuko 0.1.0
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/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/src/check-runner.d.ts +65 -0
- package/dist/src/check-runner.d.ts.map +1 -0
- package/dist/src/check-runner.js +40 -0
- package/dist/src/check-runner.js.map +1 -0
- package/dist/src/check-utils.d.ts +21 -0
- package/dist/src/check-utils.d.ts.map +1 -0
- package/dist/src/check-utils.js +39 -0
- package/dist/src/check-utils.js.map +1 -0
- package/dist/src/checks/anomaly-detection.d.ts +3 -0
- package/dist/src/checks/anomaly-detection.d.ts.map +1 -0
- package/dist/src/checks/anomaly-detection.js +127 -0
- package/dist/src/checks/anomaly-detection.js.map +1 -0
- package/dist/src/checks/bootstrap-integrity.d.ts +3 -0
- package/dist/src/checks/bootstrap-integrity.d.ts.map +1 -0
- package/dist/src/checks/bootstrap-integrity.js +107 -0
- package/dist/src/checks/bootstrap-integrity.js.map +1 -0
- package/dist/src/checks/goal-quality.d.ts +3 -0
- package/dist/src/checks/goal-quality.d.ts.map +1 -0
- package/dist/src/checks/goal-quality.js +143 -0
- package/dist/src/checks/goal-quality.js.map +1 -0
- package/dist/src/checks/pipeline-correlation.d.ts +7 -0
- package/dist/src/checks/pipeline-correlation.d.ts.map +1 -0
- package/dist/src/checks/pipeline-correlation.js +118 -0
- package/dist/src/checks/pipeline-correlation.js.map +1 -0
- package/dist/src/checks/recommendations.d.ts +3 -0
- package/dist/src/checks/recommendations.d.ts.map +1 -0
- package/dist/src/checks/recommendations.js +132 -0
- package/dist/src/checks/recommendations.js.map +1 -0
- package/dist/src/checks/thread-health.d.ts +3 -0
- package/dist/src/checks/thread-health.d.ts.map +1 -0
- package/dist/src/checks/thread-health.js +129 -0
- package/dist/src/checks/thread-health.js.map +1 -0
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +301 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +198 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/llm-client.d.ts +7 -0
- package/dist/src/llm-client.d.ts.map +1 -0
- package/dist/src/llm-client.js +111 -0
- package/dist/src/llm-client.js.map +1 -0
- package/dist/src/status-reader.d.ts +6 -0
- package/dist/src/status-reader.d.ts.map +1 -0
- package/dist/src/status-reader.js +156 -0
- package/dist/src/status-reader.js.map +1 -0
- package/dist/src/status-writer.d.ts +14 -0
- package/dist/src/status-writer.d.ts.map +1 -0
- package/dist/src/status-writer.js +52 -0
- package/dist/src/status-writer.js.map +1 -0
- package/dist/src/tool.d.ts +9 -0
- package/dist/src/tool.d.ts.map +1 -0
- package/dist/src/tool.js +129 -0
- package/dist/src/tool.js.map +1 -0
- package/dist/src/types.d.ts +261 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/openclaw.plugin.json +22 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-integrity.js","sourceRoot":"","sources":["../../../src/checks/bootstrap-integrity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CognitiveCheckResult, GoalQualityCheckConfig, LlmClient, PluginLogger } from "../types.js";
|
|
2
|
+
export declare function runGoalQualityCheck(config: GoalQualityCheckConfig, llm: LlmClient, logger: PluginLogger): Promise<CognitiveCheckResult>;
|
|
3
|
+
//# sourceMappingURL=goal-quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-quality.d.ts","sourceRoot":"","sources":["../../../src/checks/goal-quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAEpB,sBAAsB,EACtB,SAAS,EAET,YAAY,EACb,MAAM,aAAa,CAAC;AA4GrB,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA2D/B"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { readJsonInput } from "../status-reader.js";
|
|
2
|
+
import { parseSeverityString, worstSeverity } from "../check-utils.js";
|
|
3
|
+
import { runLlmCheck } from "../check-runner.js";
|
|
4
|
+
const CHECK_NAME = "cognitive:goal_quality";
|
|
5
|
+
const SYSTEM_PROMPT = `You are a system health evaluator. Analyze the pending goals and assess their quality.
|
|
6
|
+
Respond ONLY with valid JSON matching this schema:
|
|
7
|
+
{
|
|
8
|
+
"severity": "ok" | "warn" | "critical",
|
|
9
|
+
"detail": "single line summary",
|
|
10
|
+
"findings": [
|
|
11
|
+
{
|
|
12
|
+
"item_id": "goal id",
|
|
13
|
+
"issue": "vague_title" | "duplicate" | "expired" | "no_action" | "noise",
|
|
14
|
+
"detail": "explanation",
|
|
15
|
+
"recommendation": "what to do"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
Evaluation rules:
|
|
21
|
+
- Is each goal specific enough to act on? Vague goals like "Fix recurring general failures" are WARN
|
|
22
|
+
- Are there near-duplicates? Multiple similar "Fix recurring X failures" → WARN: consolidate
|
|
23
|
+
- Does proposed_action contain a real plan or just a placeholder?
|
|
24
|
+
- Are expired goals present? (expires < current date → WARN)
|
|
25
|
+
- If ALL goals are specific and actionable → severity "ok"
|
|
26
|
+
- If ≥1 vague/duplicate/expired goal → severity "warn"
|
|
27
|
+
- If ≥50% of goals are noise → severity "critical"`;
|
|
28
|
+
function extractGoals(data) {
|
|
29
|
+
if (Array.isArray(data))
|
|
30
|
+
return data;
|
|
31
|
+
if (typeof data === "object" && data !== null) {
|
|
32
|
+
const obj = data;
|
|
33
|
+
if (Array.isArray(obj.goals))
|
|
34
|
+
return obj.goals;
|
|
35
|
+
if (Array.isArray(obj.pending_goals))
|
|
36
|
+
return obj.pending_goals;
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
function preFilterGoals(goals) {
|
|
41
|
+
const findings = [];
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
for (const goal of goals) {
|
|
44
|
+
checkExpired(goal, now, findings);
|
|
45
|
+
checkStaleProposal(goal, now, findings);
|
|
46
|
+
}
|
|
47
|
+
return findings;
|
|
48
|
+
}
|
|
49
|
+
function checkExpired(goal, now, out) {
|
|
50
|
+
if (!goal.expires)
|
|
51
|
+
return;
|
|
52
|
+
const expiryMs = new Date(goal.expires).getTime();
|
|
53
|
+
if (!isNaN(expiryMs) && expiryMs < now) {
|
|
54
|
+
out.push({
|
|
55
|
+
item_id: goal.id,
|
|
56
|
+
issue: "expired",
|
|
57
|
+
detail: `Goal "${goal.title}" expired on ${goal.expires}`,
|
|
58
|
+
recommendation: "Remove or renew this goal",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function checkStaleProposal(goal, now, out) {
|
|
63
|
+
if (!goal.proposed_at || goal.status !== "proposed")
|
|
64
|
+
return;
|
|
65
|
+
const proposedMs = new Date(goal.proposed_at).getTime();
|
|
66
|
+
if (!isNaN(proposedMs) && now - proposedMs > 48 * 60 * 60 * 1000) {
|
|
67
|
+
out.push({
|
|
68
|
+
item_id: goal.id,
|
|
69
|
+
issue: "stale_proposal",
|
|
70
|
+
detail: `Goal "${goal.title}" proposed ${Math.round((now - proposedMs) / 3600000)}h ago, still not approved`,
|
|
71
|
+
recommendation: "Review and approve or reject this goal",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function mergeLlmFindings(preFindings, parsed) {
|
|
76
|
+
const llmFindings = Array.isArray(parsed.findings)
|
|
77
|
+
? parsed.findings.map((f) => ({
|
|
78
|
+
item_id: typeof f.item_id === "string" ? f.item_id : undefined,
|
|
79
|
+
issue: typeof f.issue === "string" ? f.issue : "unknown",
|
|
80
|
+
detail: typeof f.detail === "string" ? f.detail : "",
|
|
81
|
+
recommendation: typeof f.recommendation === "string" ? f.recommendation : undefined,
|
|
82
|
+
}))
|
|
83
|
+
: [];
|
|
84
|
+
const seenIds = new Set(preFindings.map((f) => f.item_id).filter(Boolean));
|
|
85
|
+
const unique = llmFindings.filter((f) => !f.item_id || !seenIds.has(f.item_id));
|
|
86
|
+
return [...preFindings, ...unique];
|
|
87
|
+
}
|
|
88
|
+
export async function runGoalQualityCheck(config, llm, logger) {
|
|
89
|
+
return runLlmCheck({
|
|
90
|
+
name: CHECK_NAME,
|
|
91
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
92
|
+
llm,
|
|
93
|
+
logger,
|
|
94
|
+
readInput(timestamp, startMs) {
|
|
95
|
+
const rawData = readJsonInput(config.inputPath, logger);
|
|
96
|
+
if (rawData === null) {
|
|
97
|
+
return { ok: false, skip: { check_name: CHECK_NAME, severity: "ok", detail: "Goals file not found — check skipped", timestamp, duration_ms: Date.now() - startMs } };
|
|
98
|
+
}
|
|
99
|
+
const goals = extractGoals(rawData);
|
|
100
|
+
if (goals.length === 0) {
|
|
101
|
+
return { ok: false, skip: { check_name: CHECK_NAME, severity: "ok", detail: "No pending goals found", timestamp, duration_ms: Date.now() - startMs } };
|
|
102
|
+
}
|
|
103
|
+
return { ok: true, input: goals };
|
|
104
|
+
},
|
|
105
|
+
preFilter(goals) {
|
|
106
|
+
const findings = preFilterGoals(goals);
|
|
107
|
+
return { severity: findings.length > 0 ? "warn" : "ok", findingCount: findings.length, data: { findings } };
|
|
108
|
+
},
|
|
109
|
+
buildPrompt(goals) {
|
|
110
|
+
const goalsText = JSON.stringify(goals, null, 2).substring(0, 4000);
|
|
111
|
+
return `Current date: ${new Date().toISOString().split("T")[0]}\n\nPending goals (${goals.length} total):\n${goalsText}`;
|
|
112
|
+
},
|
|
113
|
+
buildFailOpen({ pre, message, llmModel, llmTokens, timestamp, startMs }) {
|
|
114
|
+
const preFindings = pre.data["findings"];
|
|
115
|
+
return {
|
|
116
|
+
check_name: CHECK_NAME,
|
|
117
|
+
severity: pre.severity,
|
|
118
|
+
detail: `${message} — ${pre.findingCount} pre-filter findings`,
|
|
119
|
+
findings: preFindings,
|
|
120
|
+
timestamp,
|
|
121
|
+
model_used: llmModel,
|
|
122
|
+
tokens_used: llmTokens,
|
|
123
|
+
duration_ms: Date.now() - startMs,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
mergeResults(opts) {
|
|
127
|
+
const preFindings = opts.pre.data["findings"];
|
|
128
|
+
const allFindings = mergeLlmFindings(preFindings, opts.parsed);
|
|
129
|
+
const severity = worstSeverity(parseSeverityString(opts.parsed.severity), opts.pre.severity);
|
|
130
|
+
return {
|
|
131
|
+
check_name: CHECK_NAME,
|
|
132
|
+
severity,
|
|
133
|
+
detail: typeof opts.parsed.detail === "string" ? opts.parsed.detail : `${allFindings.length} findings`,
|
|
134
|
+
findings: allFindings,
|
|
135
|
+
timestamp: opts.timestamp,
|
|
136
|
+
model_used: opts.llmModel,
|
|
137
|
+
tokens_used: opts.llmTokens,
|
|
138
|
+
duration_ms: Date.now() - opts.startMs,
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=goal-quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-quality.js","sourceRoot":"","sources":["../../../src/checks/goal-quality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CognitiveCheckResult, PipelineCorrelationCheckConfig, LeukoStatus, PluginLogger } from "../types.js";
|
|
2
|
+
export interface PipelineCorrelationDeps {
|
|
3
|
+
threadsPath: string;
|
|
4
|
+
daemonChecks: LeukoStatus["daemon_checks"];
|
|
5
|
+
}
|
|
6
|
+
export declare function runPipelineCorrelationCheck(config: PipelineCorrelationCheckConfig, deps: PipelineCorrelationDeps, logger: PluginLogger): CognitiveCheckResult;
|
|
7
|
+
//# sourceMappingURL=pipeline-correlation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-correlation.d.ts","sourceRoot":"","sources":["../../../src/checks/pipeline-correlation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EAEpB,8BAA8B,EAC9B,WAAW,EACX,YAAY,EAEb,MAAM,aAAa,CAAC;AAwDrB,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC5C;AAoED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,8BAA8B,EACtC,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,YAAY,GACnB,oBAAoB,CAYtB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { statSync, existsSync } from "node:fs";
|
|
3
|
+
import { worstSeverity } from "../check-utils.js";
|
|
4
|
+
const CHECK_NAME = "cognitive:pipeline_correlation";
|
|
5
|
+
/**
|
|
6
|
+
* Try to get NATS stream message count via CLI.
|
|
7
|
+
* Returns null if nats CLI not available or fails.
|
|
8
|
+
*/
|
|
9
|
+
function getNatsEventCount(stream, logger) {
|
|
10
|
+
try {
|
|
11
|
+
const result = execFileSync("nats", ["stream", "info", stream, "--json"], {
|
|
12
|
+
timeout: 5000,
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
15
|
+
});
|
|
16
|
+
const parsed = JSON.parse(result);
|
|
17
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
18
|
+
return null;
|
|
19
|
+
const state = parsed["state"];
|
|
20
|
+
if (typeof state === "object" && state !== null) {
|
|
21
|
+
const msgs = state["messages"];
|
|
22
|
+
if (typeof msgs === "number")
|
|
23
|
+
return msgs;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
logger.debug("[leuko] NATS CLI not available or stream not found");
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function fileAgeHours(path) {
|
|
33
|
+
try {
|
|
34
|
+
if (!existsSync(path))
|
|
35
|
+
return null;
|
|
36
|
+
return (Date.now() - statSync(path).mtimeMs) / (60 * 60 * 1000);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isBusinessHours(bh) {
|
|
43
|
+
const hour = new Date().getUTCHours() + 1;
|
|
44
|
+
return hour >= bh.start && hour < bh.end;
|
|
45
|
+
}
|
|
46
|
+
function getCronStatus(daemonChecks) {
|
|
47
|
+
let allOk = true;
|
|
48
|
+
let staleOutputs = 0;
|
|
49
|
+
for (const check of daemonChecks) {
|
|
50
|
+
if (check.check_name.startsWith("cron_health:") && check.severity !== "ok")
|
|
51
|
+
allOk = false;
|
|
52
|
+
if (check.check_name.startsWith("output_freshness:") && check.severity !== "ok")
|
|
53
|
+
staleOutputs++;
|
|
54
|
+
}
|
|
55
|
+
return { allOk, staleOutputs };
|
|
56
|
+
}
|
|
57
|
+
function gatherSignals(config, deps, logger) {
|
|
58
|
+
return {
|
|
59
|
+
natsTotal: getNatsEventCount(config.natsStream, logger),
|
|
60
|
+
threadsAgeH: fileAgeHours(deps.threadsPath),
|
|
61
|
+
cronStatus: getCronStatus(deps.daemonChecks),
|
|
62
|
+
inBusinessHours: isBusinessHours(config.businessHours),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function buildCorrelations(signals, windowHours) {
|
|
66
|
+
const correlations = [];
|
|
67
|
+
addNatsThreadCorrelation(signals, windowHours, correlations);
|
|
68
|
+
addPipelineDisconnectCorrelation(signals, correlations);
|
|
69
|
+
addEventSourceSilentCorrelation(signals, correlations);
|
|
70
|
+
return correlations;
|
|
71
|
+
}
|
|
72
|
+
function addNatsThreadCorrelation(s, windowH, out) {
|
|
73
|
+
if (s.natsTotal === null || s.natsTotal <= 0 || s.threadsAgeH === null)
|
|
74
|
+
return;
|
|
75
|
+
if (s.threadsAgeH > 4) {
|
|
76
|
+
out.push({ input: "nats_total_messages", input_value: s.natsTotal, output: "threads_age_hours", output_value: Math.round(s.threadsAgeH * 10) / 10, diagnosis: "consumer_disconnected" });
|
|
77
|
+
}
|
|
78
|
+
else if (s.threadsAgeH > windowH) {
|
|
79
|
+
out.push({ input: "nats_total_messages", input_value: s.natsTotal, output: "threads_age_hours", output_value: Math.round(s.threadsAgeH * 10) / 10, diagnosis: "consumer_slow" });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function addPipelineDisconnectCorrelation(s, out) {
|
|
83
|
+
if (s.cronStatus.allOk && s.cronStatus.staleOutputs >= 2) {
|
|
84
|
+
out.push({ input: "crons_all_ok", input_value: 1, output: "stale_outputs", output_value: s.cronStatus.staleOutputs, diagnosis: "pipeline_disconnected" });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function addEventSourceSilentCorrelation(s, out) {
|
|
88
|
+
if (s.natsTotal !== null && s.natsTotal === 0 && s.inBusinessHours) {
|
|
89
|
+
out.push({ input: "nats_events", input_value: 0, output: "business_hours", output_value: 1, diagnosis: "event_source_silent" });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function computeCorrelationSeverity(correlations) {
|
|
93
|
+
let severity = "ok";
|
|
94
|
+
for (const c of correlations) {
|
|
95
|
+
if (c.diagnosis === "consumer_disconnected" && c.output_value > 4) {
|
|
96
|
+
severity = worstSeverity(severity, "critical");
|
|
97
|
+
}
|
|
98
|
+
else if (c.diagnosis === "consumer_disconnected") {
|
|
99
|
+
severity = worstSeverity(severity, "warn");
|
|
100
|
+
}
|
|
101
|
+
else if (c.diagnosis === "pipeline_disconnected" || c.diagnosis === "event_source_silent") {
|
|
102
|
+
severity = worstSeverity(severity, "warn");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return severity;
|
|
106
|
+
}
|
|
107
|
+
export function runPipelineCorrelationCheck(config, deps, logger) {
|
|
108
|
+
const startMs = Date.now();
|
|
109
|
+
const timestamp = new Date().toISOString();
|
|
110
|
+
const signals = gatherSignals(config, deps, logger);
|
|
111
|
+
const correlations = buildCorrelations(signals, config.correlationWindowHours);
|
|
112
|
+
const severity = computeCorrelationSeverity(correlations);
|
|
113
|
+
const detail = correlations.length === 0
|
|
114
|
+
? "All pipeline correlations normal"
|
|
115
|
+
: `${correlations.length} correlation issue(s) detected`;
|
|
116
|
+
return { check_name: CHECK_NAME, severity, detail, correlations, timestamp, duration_ms: Date.now() - startMs };
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=pipeline-correlation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-correlation.js","sourceRoot":"","sources":["../../../src/checks/pipeline-correlation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CognitiveCheckResult, RecommendationsCheckConfig, LlmClient, LeukoStatus, LeukoHistory, PluginLogger } from "../types.js";
|
|
2
|
+
export declare function runRecommendationsCheck(config: RecommendationsCheckConfig, llm: LlmClient, currentResults: CognitiveCheckResult[], status: LeukoStatus | null, _history: LeukoHistory | null, logger: PluginLogger): Promise<CognitiveCheckResult>;
|
|
3
|
+
//# sourceMappingURL=recommendations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommendations.d.ts","sourceRoot":"","sources":["../../../src/checks/recommendations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAEpB,0BAA0B,EAC1B,SAAS,EACT,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,aAAa,CAAC;AA2GrB,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,0BAA0B,EAClC,GAAG,EAAE,SAAS,EACd,cAAc,EAAE,oBAAoB,EAAE,EACtC,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,QAAQ,EAAE,YAAY,GAAG,IAAI,EAC7B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAsD/B"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { parseSeverityString } from "../check-utils.js";
|
|
2
|
+
import { runLlmCheck } from "../check-runner.js";
|
|
3
|
+
const CHECK_NAME = "cognitive:recommendations";
|
|
4
|
+
const SYSTEM_PROMPT = `You are a system health advisor. Based on the current check results and system history, generate housekeeping recommendations.
|
|
5
|
+
Respond ONLY with valid JSON matching this schema:
|
|
6
|
+
{
|
|
7
|
+
"severity": "ok" | "warn" | "critical",
|
|
8
|
+
"detail": "N recommendations generated",
|
|
9
|
+
"recommendations": [
|
|
10
|
+
{
|
|
11
|
+
"type": "archive_thread" | "cleanup_goals" | "adjust_config" | "investigate" | "maintenance",
|
|
12
|
+
"target": "what to act on",
|
|
13
|
+
"reason": "why this is recommended",
|
|
14
|
+
"priority": "low" | "medium" | "high"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Rules:
|
|
20
|
+
- Patterns in heal history (same check failing repeatedly → systemic issue)
|
|
21
|
+
- Stale threads/goals → archive candidates
|
|
22
|
+
- Cron jobs with repeated warnings → config change suggestion
|
|
23
|
+
- L1 checks stuck on warn for > 48h → needs human investigation
|
|
24
|
+
- severity "ok" when there are only low-priority suggestions
|
|
25
|
+
- severity "warn" when there are medium/high priority recommendations
|
|
26
|
+
- Maximum recommendations: as specified`;
|
|
27
|
+
function buildFindingsSummary(currentResults, status) {
|
|
28
|
+
const sections = ["=== Current Cognitive Check Results ==="];
|
|
29
|
+
for (const result of currentResults) {
|
|
30
|
+
sections.push(`${result.check_name}: ${result.severity} — ${result.detail}`);
|
|
31
|
+
appendFindings(result, sections);
|
|
32
|
+
appendCorrelations(result, sections);
|
|
33
|
+
appendAnomalies(result, sections);
|
|
34
|
+
}
|
|
35
|
+
appendDaemonIssues(status, sections);
|
|
36
|
+
return sections.join("\n").substring(0, 4000);
|
|
37
|
+
}
|
|
38
|
+
function appendFindings(result, out) {
|
|
39
|
+
if (!result.findings || result.findings.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
for (const f of result.findings.slice(0, 5)) {
|
|
42
|
+
out.push(` - ${f.issue}: ${f.detail}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function appendCorrelations(result, out) {
|
|
46
|
+
if (!result.correlations || result.correlations.length === 0)
|
|
47
|
+
return;
|
|
48
|
+
for (const c of result.correlations.slice(0, 5)) {
|
|
49
|
+
out.push(` - ${c.diagnosis}: ${c.input}=${c.input_value} → ${c.output}=${c.output_value}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function appendAnomalies(result, out) {
|
|
53
|
+
if (!result.anomalies || result.anomalies.length === 0)
|
|
54
|
+
return;
|
|
55
|
+
for (const a of result.anomalies.slice(0, 5)) {
|
|
56
|
+
out.push(` - ${a.metric}: ${a.deviation}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function appendDaemonIssues(status, out) {
|
|
60
|
+
if (!status)
|
|
61
|
+
return;
|
|
62
|
+
const issues = status.daemon_checks.filter((c) => c.severity !== "ok");
|
|
63
|
+
if (issues.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
out.push("\n=== Current Daemon Issues ===");
|
|
66
|
+
for (const issue of issues) {
|
|
67
|
+
out.push(`${issue.check_name}: ${issue.severity} — ${issue.detail}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function parseRecommendations(parsed, max) {
|
|
71
|
+
if (!Array.isArray(parsed.recommendations))
|
|
72
|
+
return [];
|
|
73
|
+
return parsed.recommendations.slice(0, max).map((r) => ({
|
|
74
|
+
type: typeof r.type === "string" ? r.type : "maintenance",
|
|
75
|
+
target: typeof r.target === "string" ? r.target : "unknown",
|
|
76
|
+
reason: typeof r.reason === "string" ? r.reason : "",
|
|
77
|
+
priority: (r.priority === "low" || r.priority === "medium" || r.priority === "high")
|
|
78
|
+
? r.priority
|
|
79
|
+
: "low",
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
export async function runRecommendationsCheck(config, llm, currentResults, status, _history, logger) {
|
|
83
|
+
return runLlmCheck({
|
|
84
|
+
name: CHECK_NAME,
|
|
85
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
86
|
+
llm,
|
|
87
|
+
logger,
|
|
88
|
+
readInput() {
|
|
89
|
+
const summary = buildFindingsSummary(currentResults, status);
|
|
90
|
+
return { ok: true, input: { summary, maxRecs: config.maxRecommendations } };
|
|
91
|
+
},
|
|
92
|
+
preFilter() {
|
|
93
|
+
return { severity: "ok", findingCount: 0, data: {} };
|
|
94
|
+
},
|
|
95
|
+
buildPrompt(input) {
|
|
96
|
+
return [
|
|
97
|
+
`Current date: ${new Date().toISOString().split("T")[0]}`,
|
|
98
|
+
`Maximum recommendations: ${input.maxRecs}`,
|
|
99
|
+
"",
|
|
100
|
+
input.summary,
|
|
101
|
+
].join("\n");
|
|
102
|
+
},
|
|
103
|
+
buildFailOpen({ message, llmModel, llmTokens, timestamp, startMs }) {
|
|
104
|
+
return {
|
|
105
|
+
check_name: CHECK_NAME,
|
|
106
|
+
severity: "ok",
|
|
107
|
+
detail: `${message} — no recommendations`,
|
|
108
|
+
recommendations: [],
|
|
109
|
+
timestamp,
|
|
110
|
+
model_used: llmModel,
|
|
111
|
+
tokens_used: llmTokens,
|
|
112
|
+
duration_ms: Date.now() - startMs,
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
mergeResults(opts) {
|
|
116
|
+
const recs = parseRecommendations(opts.parsed, config.maxRecommendations);
|
|
117
|
+
return {
|
|
118
|
+
check_name: CHECK_NAME,
|
|
119
|
+
severity: parseSeverityString(opts.parsed.severity),
|
|
120
|
+
detail: typeof opts.parsed.detail === "string"
|
|
121
|
+
? opts.parsed.detail
|
|
122
|
+
: `${recs.length} recommendations generated`,
|
|
123
|
+
recommendations: recs,
|
|
124
|
+
timestamp: opts.timestamp,
|
|
125
|
+
model_used: opts.llmModel,
|
|
126
|
+
tokens_used: opts.llmTokens,
|
|
127
|
+
duration_ms: Date.now() - opts.startMs,
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=recommendations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommendations.js","sourceRoot":"","sources":["../../../src/checks/recommendations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CognitiveCheckResult, ThreadHealthCheckConfig, LlmClient, PluginLogger } from "../types.js";
|
|
2
|
+
export declare function runThreadHealthCheck(config: ThreadHealthCheckConfig, llm: LlmClient, logger: PluginLogger): Promise<CognitiveCheckResult>;
|
|
3
|
+
//# sourceMappingURL=thread-health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-health.d.ts","sourceRoot":"","sources":["../../../src/checks/thread-health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAEpB,uBAAuB,EACvB,SAAS,EAGT,YAAY,EACb,MAAM,aAAa,CAAC;AA2FrB,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,uBAAuB,EAC/B,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA2D/B"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { readJsonInput } from "../status-reader.js";
|
|
2
|
+
import { parseSeverityString, worstSeverity } from "../check-utils.js";
|
|
3
|
+
import { runLlmCheck } from "../check-runner.js";
|
|
4
|
+
const CHECK_NAME = "cognitive:thread_health";
|
|
5
|
+
const SYSTEM_PROMPT = `You are a system health evaluator. Analyze the conversation threads and assess their health.
|
|
6
|
+
Respond ONLY with valid JSON matching this schema:
|
|
7
|
+
{
|
|
8
|
+
"severity": "ok" | "warn" | "critical",
|
|
9
|
+
"detail": "single line summary",
|
|
10
|
+
"findings": [
|
|
11
|
+
{
|
|
12
|
+
"thread_id": "thread id",
|
|
13
|
+
"issue": "stale" | "duplicate" | "incomplete" | "accumulating",
|
|
14
|
+
"detail": "explanation",
|
|
15
|
+
"days_since_update": 0,
|
|
16
|
+
"recommendation": "what to do"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Evaluation rules:
|
|
22
|
+
- Open threads with no update for > staleDays → WARN: stale
|
|
23
|
+
- Threads with identical or near-identical titles → WARN: duplicate
|
|
24
|
+
- Threads with empty or minimal description → WARN: incomplete
|
|
25
|
+
- Ratio of open to total (>80% open with >10 total) → WARN: accumulating
|
|
26
|
+
- ALL threads current and well-formed → severity "ok"
|
|
27
|
+
- ≥1 stale/duplicate/incomplete → severity "warn"
|
|
28
|
+
- ≥50% threads are stale or noise → severity "critical"`;
|
|
29
|
+
function extractThreads(data) {
|
|
30
|
+
if (typeof data !== "object" || data === null)
|
|
31
|
+
return [];
|
|
32
|
+
const obj = data;
|
|
33
|
+
if (Array.isArray(obj.threads))
|
|
34
|
+
return obj.threads;
|
|
35
|
+
if (Array.isArray(data))
|
|
36
|
+
return data;
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
function preFilterThreads(threads, staleDays) {
|
|
40
|
+
const findings = [];
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const staleMs = staleDays * 24 * 60 * 60 * 1000;
|
|
43
|
+
for (const thread of threads) {
|
|
44
|
+
if (thread.status !== "open" || !thread.last_activity)
|
|
45
|
+
continue;
|
|
46
|
+
const lastMs = new Date(thread.last_activity).getTime();
|
|
47
|
+
if (isNaN(lastMs) || now - lastMs <= staleMs)
|
|
48
|
+
continue;
|
|
49
|
+
const daysSince = Math.round((now - lastMs) / (24 * 60 * 60 * 1000));
|
|
50
|
+
findings.push({
|
|
51
|
+
thread_id: thread.id,
|
|
52
|
+
issue: "stale",
|
|
53
|
+
detail: `Thread "${thread.title}" has no update for ${daysSince} days`,
|
|
54
|
+
days_since_update: daysSince,
|
|
55
|
+
recommendation: "Archive or update thread",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return findings;
|
|
59
|
+
}
|
|
60
|
+
function mergeLlmFindings(preFindings, parsed) {
|
|
61
|
+
const llmFindings = Array.isArray(parsed.findings)
|
|
62
|
+
? parsed.findings.map((f) => ({
|
|
63
|
+
thread_id: typeof f.thread_id === "string" ? f.thread_id : undefined,
|
|
64
|
+
issue: typeof f.issue === "string" ? f.issue : "unknown",
|
|
65
|
+
detail: typeof f.detail === "string" ? f.detail : "",
|
|
66
|
+
days_since_update: typeof f.days_since_update === "number" ? f.days_since_update : undefined,
|
|
67
|
+
recommendation: typeof f.recommendation === "string" ? f.recommendation : undefined,
|
|
68
|
+
}))
|
|
69
|
+
: [];
|
|
70
|
+
const seenIds = new Set(preFindings.map((f) => f.thread_id).filter(Boolean));
|
|
71
|
+
const unique = llmFindings.filter((f) => !f.thread_id || !seenIds.has(f.thread_id));
|
|
72
|
+
return [...preFindings, ...unique];
|
|
73
|
+
}
|
|
74
|
+
export async function runThreadHealthCheck(config, llm, logger) {
|
|
75
|
+
return runLlmCheck({
|
|
76
|
+
name: CHECK_NAME,
|
|
77
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
78
|
+
llm,
|
|
79
|
+
logger,
|
|
80
|
+
readInput(timestamp, startMs) {
|
|
81
|
+
const rawData = readJsonInput(config.inputPath, logger);
|
|
82
|
+
if (rawData === null) {
|
|
83
|
+
return { ok: false, skip: { check_name: CHECK_NAME, severity: "ok", detail: "Threads file not found — check skipped", timestamp, duration_ms: Date.now() - startMs } };
|
|
84
|
+
}
|
|
85
|
+
const threads = extractThreads(rawData);
|
|
86
|
+
if (threads.length === 0) {
|
|
87
|
+
return { ok: false, skip: { check_name: CHECK_NAME, severity: "ok", detail: "No threads found", timestamp, duration_ms: Date.now() - startMs } };
|
|
88
|
+
}
|
|
89
|
+
return { ok: true, input: { threads, staleDays: config.staleDays } };
|
|
90
|
+
},
|
|
91
|
+
preFilter(input) {
|
|
92
|
+
const findings = preFilterThreads(input.threads, input.staleDays);
|
|
93
|
+
return { severity: findings.length > 0 ? "warn" : "ok", findingCount: findings.length, data: { findings } };
|
|
94
|
+
},
|
|
95
|
+
buildPrompt(input) {
|
|
96
|
+
const text = JSON.stringify(input.threads, null, 2).substring(0, 4000);
|
|
97
|
+
return `Current date: ${new Date().toISOString().split("T")[0]}\nStale threshold: ${input.staleDays} days\n\nThreads (${input.threads.length} total):\n${text}`;
|
|
98
|
+
},
|
|
99
|
+
buildFailOpen({ pre, message, llmModel, llmTokens, timestamp, startMs }) {
|
|
100
|
+
const preFindings = pre.data["findings"];
|
|
101
|
+
return {
|
|
102
|
+
check_name: CHECK_NAME,
|
|
103
|
+
severity: pre.severity,
|
|
104
|
+
detail: `${message} — ${pre.findingCount} pre-filter findings`,
|
|
105
|
+
findings: preFindings,
|
|
106
|
+
timestamp,
|
|
107
|
+
model_used: llmModel,
|
|
108
|
+
tokens_used: llmTokens,
|
|
109
|
+
duration_ms: Date.now() - startMs,
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
mergeResults(opts) {
|
|
113
|
+
const preFindings = opts.pre.data["findings"];
|
|
114
|
+
const allFindings = mergeLlmFindings(preFindings, opts.parsed);
|
|
115
|
+
const severity = worstSeverity(parseSeverityString(opts.parsed.severity), opts.pre.severity);
|
|
116
|
+
return {
|
|
117
|
+
check_name: CHECK_NAME,
|
|
118
|
+
severity,
|
|
119
|
+
detail: typeof opts.parsed.detail === "string" ? opts.parsed.detail : `${allFindings.length} findings`,
|
|
120
|
+
findings: allFindings,
|
|
121
|
+
timestamp: opts.timestamp,
|
|
122
|
+
model_used: opts.llmModel,
|
|
123
|
+
tokens_used: opts.llmTokens,
|
|
124
|
+
duration_ms: Date.now() - opts.startMs,
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=thread-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-health.js","sourceRoot":"","sources":["../../../src/checks/thread-health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LeukoConfig, PluginLogger } from "./types.js";
|
|
2
|
+
export declare const DEFAULTS: LeukoConfig;
|
|
3
|
+
export declare function resolveConfig(pluginConfig?: Record<string, unknown>): LeukoConfig;
|
|
4
|
+
export interface ConfigLoadResult {
|
|
5
|
+
readonly config: LeukoConfig;
|
|
6
|
+
readonly source: "inline" | "file" | "defaults";
|
|
7
|
+
readonly filePath?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadConfig(pluginConfig: Record<string, unknown> | undefined, logger: PluginLogger): ConfigLoadResult;
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EAKX,YAAY,EAEb,MAAM,YAAY,CAAC;AASpB,eAAO,MAAM,QAAQ,EAAE,WAyEtB,CAAC;AAyJF,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAajF;AAoED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,UAAU,CACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACjD,MAAM,EAAE,YAAY,GACnB,gBAAgB,CAkClB"}
|