@mcptoolshop/claude-guardian 1.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 +45 -0
- package/HANDBOOK.md +209 -0
- package/LICENSE +21 -0
- package/README.es.md +185 -0
- package/README.fr.md +185 -0
- package/README.hi.md +184 -0
- package/README.it.md +184 -0
- package/README.ja.md +185 -0
- package/README.md +184 -0
- package/README.pt-BR.md +184 -0
- package/README.zh.md +185 -0
- package/dist/budget-store.d.ts +33 -0
- package/dist/budget-store.js +62 -0
- package/dist/budget-store.js.map +1 -0
- package/dist/budget.d.ts +52 -0
- package/dist/budget.js +136 -0
- package/dist/budget.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +387 -0
- package/dist/cli.js.map +1 -0
- package/dist/defaults.d.ts +51 -0
- package/dist/defaults.js +67 -0
- package/dist/defaults.js.map +1 -0
- package/dist/doctor.d.ts +69 -0
- package/dist/doctor.js +294 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/fs-utils.d.ts +23 -0
- package/dist/fs-utils.js +184 -0
- package/dist/fs-utils.js.map +1 -0
- package/dist/handle-count.d.ts +9 -0
- package/dist/handle-count.js +68 -0
- package/dist/handle-count.js.map +1 -0
- package/dist/incident.d.ts +33 -0
- package/dist/incident.js +115 -0
- package/dist/incident.js.map +1 -0
- package/dist/log-manager.d.ts +17 -0
- package/dist/log-manager.js +418 -0
- package/dist/log-manager.js.map +1 -0
- package/dist/mcp-server.d.ts +8 -0
- package/dist/mcp-server.js +503 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/process-monitor.d.ts +56 -0
- package/dist/process-monitor.js +214 -0
- package/dist/process-monitor.js.map +1 -0
- package/dist/recovery-plan.d.ts +22 -0
- package/dist/recovery-plan.js +146 -0
- package/dist/recovery-plan.js.map +1 -0
- package/dist/state.d.ts +64 -0
- package/dist/state.js +140 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/watch-daemon.d.ts +7 -0
- package/dist/watch-daemon.js +162 -0
- package/dist/watch-daemon.js.map +1 -0
- package/dist/watchdog.d.ts +30 -0
- package/dist/watchdog.js +225 -0
- package/dist/watchdog.js.map +1 -0
- package/package.json +50 -0
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
/** The 3 user-facing knobs with sane defaults. */
|
|
4
|
+
export const DEFAULT_CONFIG = {
|
|
5
|
+
maxProjectLogDirMB: 200,
|
|
6
|
+
hangNoActivitySeconds: 300,
|
|
7
|
+
autoRestart: false,
|
|
8
|
+
};
|
|
9
|
+
/** Hardcoded thresholds — not user-configurable in v1. */
|
|
10
|
+
export const THRESHOLDS = {
|
|
11
|
+
/** Disk free below this triggers aggressive mode. */
|
|
12
|
+
diskFreeWarningGB: 5,
|
|
13
|
+
/** Max single file size before trimming. */
|
|
14
|
+
maxFileMB: 25,
|
|
15
|
+
/** How many days of logs to retain during rotation. */
|
|
16
|
+
retainDays: 7,
|
|
17
|
+
/** Days before a session transcript is considered stale and eligible for cleanup. */
|
|
18
|
+
staleSessionDays: 3,
|
|
19
|
+
/** Tail lines to include in doctor bundle per log file. */
|
|
20
|
+
doctorTailLines: 500,
|
|
21
|
+
/** Watchdog poll interval in ms. */
|
|
22
|
+
watchdogPollMs: 2000,
|
|
23
|
+
/** Restart backoff schedule in ms. */
|
|
24
|
+
restartBackoffMs: [2000, 5000, 15000, 60000],
|
|
25
|
+
/** Max restarts before giving up. */
|
|
26
|
+
maxRestarts: 5,
|
|
27
|
+
/** Grace period after first discovering a PID — risk stays ok. */
|
|
28
|
+
graceWindowSeconds: 60,
|
|
29
|
+
/** CPU below this % counts as "low" for hang detection. */
|
|
30
|
+
cpuLowThreshold: 5,
|
|
31
|
+
/** After warn, escalate to critical after this many additional seconds. */
|
|
32
|
+
criticalAfterSeconds: 600,
|
|
33
|
+
/** Rate limit: min seconds between bundles for the same PID. */
|
|
34
|
+
bundleCooldownSeconds: 300,
|
|
35
|
+
};
|
|
36
|
+
/** Budget thresholds for concurrency control. */
|
|
37
|
+
export const BUDGET_THRESHOLDS = {
|
|
38
|
+
/** Maximum concurrency slots (base cap). */
|
|
39
|
+
baseCap: 4,
|
|
40
|
+
/** Cap when risk = warn. */
|
|
41
|
+
warnCap: 2,
|
|
42
|
+
/** Cap when risk = critical. */
|
|
43
|
+
criticalCap: 1,
|
|
44
|
+
/** Seconds of sustained ok before restoring base cap. */
|
|
45
|
+
hysteresisSeconds: 60,
|
|
46
|
+
};
|
|
47
|
+
/** Resolve the Claude projects directory. */
|
|
48
|
+
export function getClaudeProjectsPath() {
|
|
49
|
+
return join(homedir(), '.claude', 'projects');
|
|
50
|
+
}
|
|
51
|
+
/** Resolve the guardian data directory. */
|
|
52
|
+
export function getGuardianDataPath() {
|
|
53
|
+
return join(homedir(), '.claude-guardian');
|
|
54
|
+
}
|
|
55
|
+
/** Resolve the journal file path. */
|
|
56
|
+
export function getJournalPath() {
|
|
57
|
+
return join(getGuardianDataPath(), 'journal.jsonl');
|
|
58
|
+
}
|
|
59
|
+
/** Resolve the archive directory. */
|
|
60
|
+
export function getArchivePath() {
|
|
61
|
+
return join(getGuardianDataPath(), 'archive');
|
|
62
|
+
}
|
|
63
|
+
/** Resolve the budget file path. */
|
|
64
|
+
export function getBudgetPath() {
|
|
65
|
+
return join(getGuardianDataPath(), 'budget.json');
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,kDAAkD;AAClD,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,kBAAkB,EAAE,GAAG;IACvB,qBAAqB,EAAE,GAAG;IAC1B,WAAW,EAAE,KAAK;CACnB,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,qDAAqD;IACrD,iBAAiB,EAAE,CAAC;IAEpB,4CAA4C;IAC5C,SAAS,EAAE,EAAE;IAEb,uDAAuD;IACvD,UAAU,EAAE,CAAC;IAEb,qFAAqF;IACrF,gBAAgB,EAAE,CAAC;IAEnB,2DAA2D;IAC3D,eAAe,EAAE,GAAG;IAEpB,oCAAoC;IACpC,cAAc,EAAE,IAAI;IAEpB,sCAAsC;IACtC,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC;IAE5C,qCAAqC;IACrC,WAAW,EAAE,CAAC;IAEd,kEAAkE;IAClE,kBAAkB,EAAE,EAAE;IAEtB,2DAA2D;IAC3D,eAAe,EAAE,CAAC;IAElB,2EAA2E;IAC3E,oBAAoB,EAAE,GAAG;IAEzB,gEAAgE;IAChE,qBAAqB,EAAE,GAAG;CAClB,CAAC;AAEX,iDAAiD;AACjD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,4CAA4C;IAC5C,OAAO,EAAE,CAAC;IACV,4BAA4B;IAC5B,OAAO,EAAE,CAAC;IACV,gCAAgC;IAChC,WAAW,EAAE,CAAC;IACd,yDAAyD;IACzD,iBAAiB,EAAE,EAAE;CACb,CAAC;AAEX,6CAA6C;AAC7C,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC7C,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,eAAe,CAAC,CAAC;AACtD,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC"}
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { PreflightResult } from './types.js';
|
|
2
|
+
import { type HandleCountResult } from './handle-count.js';
|
|
3
|
+
export interface DoctorBundle {
|
|
4
|
+
/** Path to the generated zip file. */
|
|
5
|
+
zipPath: string;
|
|
6
|
+
/** Summary data included in the bundle. */
|
|
7
|
+
summary: DoctorSummary;
|
|
8
|
+
}
|
|
9
|
+
export interface DoctorSummary {
|
|
10
|
+
timestamp: string;
|
|
11
|
+
system: SystemInfo;
|
|
12
|
+
claudeProjects: PreflightResult;
|
|
13
|
+
biggestFiles: Array<{
|
|
14
|
+
path: string;
|
|
15
|
+
sizeMB: number;
|
|
16
|
+
}>;
|
|
17
|
+
journalEntries: number;
|
|
18
|
+
recentJournal: Array<{
|
|
19
|
+
timestamp: string;
|
|
20
|
+
action: string;
|
|
21
|
+
detail: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Handle/FD counts for Claude processes at bundle time. */
|
|
24
|
+
handleCounts: HandleCountResult[];
|
|
25
|
+
/** Process snapshot at bundle time. */
|
|
26
|
+
processSnapshot: ProcessSnapshot;
|
|
27
|
+
/** Reconstructed timeline of events. */
|
|
28
|
+
timeline: TimelineEvent[];
|
|
29
|
+
}
|
|
30
|
+
/** Snapshot of running Claude processes at bundle time. */
|
|
31
|
+
export interface ProcessSnapshot {
|
|
32
|
+
timestamp: string;
|
|
33
|
+
processes: Array<{
|
|
34
|
+
pid: number;
|
|
35
|
+
name: string;
|
|
36
|
+
cpuPercent: number;
|
|
37
|
+
memoryMB: number;
|
|
38
|
+
uptimeSeconds: number;
|
|
39
|
+
handleCount: number | null;
|
|
40
|
+
}>;
|
|
41
|
+
activitySignals: {
|
|
42
|
+
logLastModifiedSecondsAgo: number;
|
|
43
|
+
cpuActive: boolean;
|
|
44
|
+
sources: string[];
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** A single event in the diagnostic timeline. */
|
|
48
|
+
export interface TimelineEvent {
|
|
49
|
+
timestamp: string;
|
|
50
|
+
type: 'risk_change' | 'incident_open' | 'incident_close' | 'bundle_captured' | 'fix_applied' | 'budget_change' | 'journal';
|
|
51
|
+
detail: string;
|
|
52
|
+
}
|
|
53
|
+
export interface SystemInfo {
|
|
54
|
+
platform: string;
|
|
55
|
+
release: string;
|
|
56
|
+
arch: string;
|
|
57
|
+
totalMemoryGB: number;
|
|
58
|
+
freeMemoryGB: number;
|
|
59
|
+
cpuModel: string;
|
|
60
|
+
cpuCores: number;
|
|
61
|
+
diskFreeGB: number;
|
|
62
|
+
nodeVersion: string;
|
|
63
|
+
}
|
|
64
|
+
/** Collect system information. */
|
|
65
|
+
export declare function collectSystemInfo(diskFreeGB: number): SystemInfo;
|
|
66
|
+
/** Generate a full diagnostics bundle. */
|
|
67
|
+
export declare function generateBundle(outputPath?: string): Promise<DoctorBundle>;
|
|
68
|
+
/** Format a doctor summary as a human-readable report. */
|
|
69
|
+
export declare function formatDoctorReport(summary: DoctorSummary): string;
|
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { mkdir, readFile } from 'fs/promises';
|
|
2
|
+
import { join, basename } from 'path';
|
|
3
|
+
import { existsSync, createWriteStream } from 'fs';
|
|
4
|
+
import archiver from 'archiver';
|
|
5
|
+
import { homedir, platform, release, totalmem, freemem, cpus } from 'os';
|
|
6
|
+
import { getClaudeProjectsPath, getGuardianDataPath, THRESHOLDS } from './defaults.js';
|
|
7
|
+
import { listFilesRecursive, getDiskFreeGB, bytesToMB, tailFile, readJournal, pathExists, } from './fs-utils.js';
|
|
8
|
+
import { scanLogs } from './log-manager.js';
|
|
9
|
+
import { findClaudeProcesses, checkActivitySignals } from './process-monitor.js';
|
|
10
|
+
import { getHandleCounts } from './handle-count.js';
|
|
11
|
+
import { readState } from './state.js';
|
|
12
|
+
import { readIncidentLog } from './incident.js';
|
|
13
|
+
/** Collect system information. */
|
|
14
|
+
export function collectSystemInfo(diskFreeGB) {
|
|
15
|
+
const cpuInfo = cpus();
|
|
16
|
+
return {
|
|
17
|
+
platform: platform(),
|
|
18
|
+
release: release(),
|
|
19
|
+
arch: process.arch,
|
|
20
|
+
totalMemoryGB: Math.round((totalmem() / (1024 ** 3)) * 100) / 100,
|
|
21
|
+
freeMemoryGB: Math.round((freemem() / (1024 ** 3)) * 100) / 100,
|
|
22
|
+
cpuModel: cpuInfo[0]?.model || 'unknown',
|
|
23
|
+
cpuCores: cpuInfo.length,
|
|
24
|
+
diskFreeGB,
|
|
25
|
+
nodeVersion: process.version,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Generate a full diagnostics bundle. */
|
|
29
|
+
export async function generateBundle(outputPath) {
|
|
30
|
+
const dataDir = getGuardianDataPath();
|
|
31
|
+
if (!existsSync(dataDir)) {
|
|
32
|
+
await mkdir(dataDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
35
|
+
const zipPath = outputPath || join(dataDir, `bundle-${timestamp}.zip`);
|
|
36
|
+
// Collect preflight scan
|
|
37
|
+
const claudeProjects = await scanLogs();
|
|
38
|
+
// Collect system info
|
|
39
|
+
const diskFreeGB = await getDiskFreeGB(homedir());
|
|
40
|
+
const systemInfo = collectSystemInfo(diskFreeGB);
|
|
41
|
+
// Find biggest files
|
|
42
|
+
const claudePath = getClaudeProjectsPath();
|
|
43
|
+
const biggestFiles = [];
|
|
44
|
+
if (await pathExists(claudePath)) {
|
|
45
|
+
const allFiles = await listFilesRecursive(claudePath);
|
|
46
|
+
const fileSizes = [];
|
|
47
|
+
for (const f of allFiles) {
|
|
48
|
+
const { stat } = await import('fs/promises');
|
|
49
|
+
const s = await stat(f);
|
|
50
|
+
fileSizes.push({ path: f, sizeMB: bytesToMB(s.size) });
|
|
51
|
+
}
|
|
52
|
+
fileSizes.sort((a, b) => b.sizeMB - a.sizeMB);
|
|
53
|
+
biggestFiles.push(...fileSizes.slice(0, 20));
|
|
54
|
+
}
|
|
55
|
+
// Read journal
|
|
56
|
+
const journal = await readJournal();
|
|
57
|
+
const recentJournal = journal.slice(-50).map(e => ({
|
|
58
|
+
timestamp: e.timestamp,
|
|
59
|
+
action: e.action,
|
|
60
|
+
detail: e.detail,
|
|
61
|
+
}));
|
|
62
|
+
// Collect handle counts for running Claude processes
|
|
63
|
+
const processes = await findClaudeProcesses();
|
|
64
|
+
const handleCounts = processes.length > 0
|
|
65
|
+
? await getHandleCounts(processes.map(p => p.pid))
|
|
66
|
+
: [];
|
|
67
|
+
// Build process snapshot
|
|
68
|
+
const activity = await checkActivitySignals(processes);
|
|
69
|
+
const processSnapshot = buildProcessSnapshot(processes, handleCounts, activity);
|
|
70
|
+
// Build timeline from journal + incidents
|
|
71
|
+
const timeline = await buildTimeline(journal, recentJournal);
|
|
72
|
+
const summary = {
|
|
73
|
+
timestamp: new Date().toISOString(),
|
|
74
|
+
system: systemInfo,
|
|
75
|
+
claudeProjects,
|
|
76
|
+
biggestFiles,
|
|
77
|
+
journalEntries: journal.length,
|
|
78
|
+
recentJournal,
|
|
79
|
+
handleCounts,
|
|
80
|
+
processSnapshot,
|
|
81
|
+
timeline,
|
|
82
|
+
};
|
|
83
|
+
// Build the zip
|
|
84
|
+
await createZipBundle(zipPath, summary, claudePath);
|
|
85
|
+
return { zipPath, summary };
|
|
86
|
+
}
|
|
87
|
+
/** Create the actual zip file with summary + log tails. */
|
|
88
|
+
async function createZipBundle(zipPath, summary, claudePath) {
|
|
89
|
+
// Ensure parent dir exists
|
|
90
|
+
const parentDir = join(zipPath, '..');
|
|
91
|
+
if (!existsSync(parentDir)) {
|
|
92
|
+
await mkdir(parentDir, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
const output = createWriteStream(zipPath);
|
|
96
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
97
|
+
output.on('close', resolve);
|
|
98
|
+
archive.on('error', reject);
|
|
99
|
+
archive.pipe(output);
|
|
100
|
+
// Add summary.json
|
|
101
|
+
archive.append(JSON.stringify(summary, null, 2), { name: 'summary.json' });
|
|
102
|
+
// Add log tails (async — we queue them as promises)
|
|
103
|
+
const addTails = async () => {
|
|
104
|
+
if (await pathExists(claudePath)) {
|
|
105
|
+
const allFiles = await listFilesRecursive(claudePath);
|
|
106
|
+
// Only tail the biggest files (top 20 by path, to avoid huge bundles)
|
|
107
|
+
const textFiles = allFiles.filter(f => f.endsWith('.log') || f.endsWith('.jsonl') || f.endsWith('.json') || f.endsWith('.txt')).slice(0, 20);
|
|
108
|
+
for (const f of textFiles) {
|
|
109
|
+
const tail = await tailFile(f, THRESHOLDS.doctorTailLines);
|
|
110
|
+
if (tail.length > 0) {
|
|
111
|
+
// Use relative path from claude projects dir
|
|
112
|
+
const relPath = f.replace(claudePath, '').replace(/^[/\\]/, '');
|
|
113
|
+
archive.append(tail, { name: `log-tails/${relPath}` });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Add journal if it exists
|
|
118
|
+
const journalPath = join(getGuardianDataPath(), 'journal.jsonl');
|
|
119
|
+
if (await pathExists(journalPath)) {
|
|
120
|
+
const journalContent = await readFile(journalPath, 'utf-8');
|
|
121
|
+
archive.append(journalContent, { name: 'journal.jsonl' });
|
|
122
|
+
}
|
|
123
|
+
// Add process snapshot
|
|
124
|
+
archive.append(JSON.stringify(summary.processSnapshot, null, 2), { name: 'process.json' });
|
|
125
|
+
// Add timeline
|
|
126
|
+
archive.append(JSON.stringify(summary.timeline, null, 2), { name: 'timeline.json' });
|
|
127
|
+
// Add filtered events (journal entries relevant to recent incidents)
|
|
128
|
+
const events = buildEventLines(summary.recentJournal);
|
|
129
|
+
if (events.length > 0) {
|
|
130
|
+
archive.append(events, { name: 'events.jsonl' });
|
|
131
|
+
}
|
|
132
|
+
// Add current state if available
|
|
133
|
+
const statePath = join(getGuardianDataPath(), 'state.json');
|
|
134
|
+
if (await pathExists(statePath)) {
|
|
135
|
+
const stateContent = await readFile(statePath, 'utf-8');
|
|
136
|
+
archive.append(stateContent, { name: 'state.json' });
|
|
137
|
+
}
|
|
138
|
+
// Add incidents log if available
|
|
139
|
+
const incidentsPath = join(getGuardianDataPath(), 'incidents.jsonl');
|
|
140
|
+
if (await pathExists(incidentsPath)) {
|
|
141
|
+
const incidentsContent = await readFile(incidentsPath, 'utf-8');
|
|
142
|
+
archive.append(incidentsContent, { name: 'incidents.jsonl' });
|
|
143
|
+
}
|
|
144
|
+
archive.finalize();
|
|
145
|
+
};
|
|
146
|
+
addTails().catch(reject);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/** Build a process snapshot from current processes and handle counts. */
|
|
150
|
+
function buildProcessSnapshot(processes, handleCounts, activity) {
|
|
151
|
+
const handleMap = new Map(handleCounts.map(h => [h.pid, h.count]));
|
|
152
|
+
return {
|
|
153
|
+
timestamp: new Date().toISOString(),
|
|
154
|
+
processes: processes.map(p => ({
|
|
155
|
+
pid: p.pid,
|
|
156
|
+
name: p.name,
|
|
157
|
+
cpuPercent: p.cpuPercent,
|
|
158
|
+
memoryMB: p.memoryMB,
|
|
159
|
+
uptimeSeconds: p.uptimeSeconds,
|
|
160
|
+
handleCount: handleMap.get(p.pid) ?? null,
|
|
161
|
+
})),
|
|
162
|
+
activitySignals: {
|
|
163
|
+
logLastModifiedSecondsAgo: activity.logLastModifiedSecondsAgo,
|
|
164
|
+
cpuActive: activity.cpuActive,
|
|
165
|
+
sources: activity.sources,
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** Build a chronological timeline from journal and incident history. */
|
|
170
|
+
async function buildTimeline(journal, recentJournal) {
|
|
171
|
+
const events = [];
|
|
172
|
+
// Add journal events
|
|
173
|
+
for (const entry of journal.slice(-100)) {
|
|
174
|
+
let type = 'journal';
|
|
175
|
+
if (entry.action === 'auto-bundle' || entry.action === 'bundle') {
|
|
176
|
+
type = 'bundle_captured';
|
|
177
|
+
}
|
|
178
|
+
else if (entry.action.includes('fix') || entry.action.includes('rotate') || entry.action.includes('trim')) {
|
|
179
|
+
type = 'fix_applied';
|
|
180
|
+
}
|
|
181
|
+
events.push({
|
|
182
|
+
timestamp: entry.timestamp,
|
|
183
|
+
type,
|
|
184
|
+
detail: `${entry.action}: ${entry.detail}`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Add incident events
|
|
188
|
+
const incidents = await readIncidentLog(20);
|
|
189
|
+
for (const inc of incidents) {
|
|
190
|
+
events.push({
|
|
191
|
+
timestamp: inc.startedAt,
|
|
192
|
+
type: 'incident_open',
|
|
193
|
+
detail: `Incident ${inc.id} opened (${inc.peakLevel}): ${inc.reason}`,
|
|
194
|
+
});
|
|
195
|
+
if (inc.closedAt) {
|
|
196
|
+
events.push({
|
|
197
|
+
timestamp: inc.closedAt,
|
|
198
|
+
type: 'incident_close',
|
|
199
|
+
detail: `Incident ${inc.id} closed`,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (inc.bundleCaptured && inc.bundlePath) {
|
|
203
|
+
events.push({
|
|
204
|
+
timestamp: inc.startedAt, // approximate
|
|
205
|
+
type: 'bundle_captured',
|
|
206
|
+
detail: `Bundle for incident ${inc.id}: ${inc.bundlePath}`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Add current state info
|
|
211
|
+
const state = await readState();
|
|
212
|
+
if (state) {
|
|
213
|
+
events.push({
|
|
214
|
+
timestamp: state.updatedAt,
|
|
215
|
+
type: 'risk_change',
|
|
216
|
+
detail: `Current risk: ${state.hangRisk.level} | attention: ${state.attention.level}`,
|
|
217
|
+
});
|
|
218
|
+
if (state.budgetSummary && state.budgetSummary.currentCap < state.budgetSummary.baseCap) {
|
|
219
|
+
events.push({
|
|
220
|
+
timestamp: state.updatedAt,
|
|
221
|
+
type: 'budget_change',
|
|
222
|
+
detail: `Budget cap: ${state.budgetSummary.currentCap}/${state.budgetSummary.baseCap} (reduced by ${state.budgetSummary.capSetByRisk})`,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Sort chronologically
|
|
227
|
+
events.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
228
|
+
return events;
|
|
229
|
+
}
|
|
230
|
+
/** Build events.jsonl content from recent journal entries. */
|
|
231
|
+
function buildEventLines(recentJournal) {
|
|
232
|
+
return recentJournal.map(e => JSON.stringify(e)).join('\n');
|
|
233
|
+
}
|
|
234
|
+
/** Format a doctor summary as a human-readable report. */
|
|
235
|
+
export function formatDoctorReport(summary) {
|
|
236
|
+
const lines = [];
|
|
237
|
+
lines.push('=== Claude Guardian Doctor Report ===');
|
|
238
|
+
lines.push(`Generated: ${summary.timestamp}`);
|
|
239
|
+
lines.push('');
|
|
240
|
+
// System
|
|
241
|
+
lines.push('System:');
|
|
242
|
+
lines.push(` Platform: ${summary.system.platform} ${summary.system.release}`);
|
|
243
|
+
lines.push(` Arch: ${summary.system.arch}`);
|
|
244
|
+
lines.push(` Memory: ${summary.system.freeMemoryGB}GB free / ${summary.system.totalMemoryGB}GB total`);
|
|
245
|
+
lines.push(` CPU: ${summary.system.cpuModel} (${summary.system.cpuCores} cores)`);
|
|
246
|
+
lines.push(` Disk free: ${Math.round(summary.system.diskFreeGB * 100) / 100}GB`);
|
|
247
|
+
lines.push(` Node: ${summary.system.nodeVersion}`);
|
|
248
|
+
lines.push('');
|
|
249
|
+
// Claude projects
|
|
250
|
+
lines.push('Claude Projects:');
|
|
251
|
+
lines.push(` Total size: ${summary.claudeProjects.claudeProjectsSizeMB}MB`);
|
|
252
|
+
lines.push(` Issues: ${summary.claudeProjects.actions.length}`);
|
|
253
|
+
lines.push('');
|
|
254
|
+
// Biggest files
|
|
255
|
+
if (summary.biggestFiles.length > 0) {
|
|
256
|
+
lines.push('Biggest files:');
|
|
257
|
+
for (const f of summary.biggestFiles.slice(0, 10)) {
|
|
258
|
+
const name = basename(f.path);
|
|
259
|
+
lines.push(` ${name}: ${f.sizeMB}MB`);
|
|
260
|
+
}
|
|
261
|
+
lines.push('');
|
|
262
|
+
}
|
|
263
|
+
// Process snapshot
|
|
264
|
+
if (summary.processSnapshot.processes.length > 0) {
|
|
265
|
+
lines.push('Process Snapshot:');
|
|
266
|
+
for (const p of summary.processSnapshot.processes) {
|
|
267
|
+
let line = ` PID ${p.pid} (${p.name}): CPU ${p.cpuPercent}% | RAM ${p.memoryMB}MB`;
|
|
268
|
+
if (p.handleCount != null) {
|
|
269
|
+
line += ` | handles=${p.handleCount}`;
|
|
270
|
+
}
|
|
271
|
+
lines.push(line);
|
|
272
|
+
}
|
|
273
|
+
lines.push(` Activity: log=${summary.processSnapshot.activitySignals.logLastModifiedSecondsAgo}s ago | cpu=${summary.processSnapshot.activitySignals.cpuActive ? 'active' : 'idle'}`);
|
|
274
|
+
lines.push('');
|
|
275
|
+
}
|
|
276
|
+
// Timeline
|
|
277
|
+
if (summary.timeline.length > 0) {
|
|
278
|
+
lines.push(`Timeline: ${summary.timeline.length} events`);
|
|
279
|
+
for (const event of summary.timeline.slice(-10)) {
|
|
280
|
+
lines.push(` [${event.timestamp}] ${event.type}: ${event.detail}`);
|
|
281
|
+
}
|
|
282
|
+
lines.push('');
|
|
283
|
+
}
|
|
284
|
+
// Journal
|
|
285
|
+
lines.push(`Guardian journal: ${summary.journalEntries} entries`);
|
|
286
|
+
if (summary.recentJournal.length > 0) {
|
|
287
|
+
lines.push('Recent actions:');
|
|
288
|
+
for (const entry of summary.recentJournal.slice(-5)) {
|
|
289
|
+
lines.push(` [${entry.timestamp}] ${entry.action}: ${entry.detail}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return lines.join('\n');
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error type used across CLI + MCP.
|
|
3
|
+
* Every guardian error carries a machine-readable code, a human hint, and optionally the root cause.
|
|
4
|
+
*/
|
|
5
|
+
/** Error codes — one per failure mode. */
|
|
6
|
+
export type GuardianErrorCode = 'STATE_CORRUPT' | 'STATE_WRITE_FAILED' | 'BUDGET_CORRUPT' | 'BUDGET_WRITE_FAILED' | 'BUNDLE_FAILED' | 'SCAN_FAILED' | 'FIX_FAILED' | 'PROCESS_SCAN_FAILED' | 'DISK_CHECK_FAILED' | 'UNKNOWN';
|
|
7
|
+
export declare class GuardianError extends Error {
|
|
8
|
+
/** Machine-readable error code. */
|
|
9
|
+
readonly code: GuardianErrorCode;
|
|
10
|
+
/** Human-friendly hint about what to do. */
|
|
11
|
+
readonly hint: string;
|
|
12
|
+
/** Original error (if wrapping). */
|
|
13
|
+
readonly cause?: Error;
|
|
14
|
+
constructor(code: GuardianErrorCode, message: string, hint: string, cause?: Error);
|
|
15
|
+
/** Format for MCP tool responses (no stack traces). */
|
|
16
|
+
toMcpText(): string;
|
|
17
|
+
/** Format for CLI output. */
|
|
18
|
+
toCliText(): string;
|
|
19
|
+
}
|
|
20
|
+
/** Wrap any thrown value into a GuardianError. */
|
|
21
|
+
export declare function wrapError(err: unknown, code: GuardianErrorCode, hint: string): GuardianError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error type used across CLI + MCP.
|
|
3
|
+
* Every guardian error carries a machine-readable code, a human hint, and optionally the root cause.
|
|
4
|
+
*/
|
|
5
|
+
export class GuardianError extends Error {
|
|
6
|
+
/** Machine-readable error code. */
|
|
7
|
+
code;
|
|
8
|
+
/** Human-friendly hint about what to do. */
|
|
9
|
+
hint;
|
|
10
|
+
/** Original error (if wrapping). */
|
|
11
|
+
cause;
|
|
12
|
+
constructor(code, message, hint, cause) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'GuardianError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.hint = hint;
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
}
|
|
19
|
+
/** Format for MCP tool responses (no stack traces). */
|
|
20
|
+
toMcpText() {
|
|
21
|
+
const lines = [`Error [${this.code}]: ${this.message}`];
|
|
22
|
+
lines.push(`Hint: ${this.hint}`);
|
|
23
|
+
if (this.cause) {
|
|
24
|
+
lines.push(`Cause: ${this.cause.message}`);
|
|
25
|
+
}
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
/** Format for CLI output. */
|
|
29
|
+
toCliText() {
|
|
30
|
+
const lines = [`[guardian] Error: ${this.message}`];
|
|
31
|
+
lines.push(` Code: ${this.code}`);
|
|
32
|
+
lines.push(` Hint: ${this.hint}`);
|
|
33
|
+
if (this.cause) {
|
|
34
|
+
lines.push(` Cause: ${this.cause.message}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Wrap any thrown value into a GuardianError. */
|
|
40
|
+
export function wrapError(err, code, hint) {
|
|
41
|
+
if (err instanceof GuardianError)
|
|
42
|
+
return err;
|
|
43
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
44
|
+
return new GuardianError(code, cause.message, hint, cause);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,mCAAmC;IAC1B,IAAI,CAAoB;IACjC,4CAA4C;IACnC,IAAI,CAAS;IACtB,oCAAoC;IAC3B,KAAK,CAAS;IAEvB,YAAY,IAAuB,EAAE,OAAe,EAAE,IAAY,EAAE,KAAa;QAC/E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,uDAAuD;IACvD,SAAS;QACP,MAAM,KAAK,GAAG,CAAC,UAAU,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,6BAA6B;IAC7B,SAAS;QACP,MAAM,KAAK,GAAG,CAAC,qBAAqB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,GAAY,EAAE,IAAuB,EAAE,IAAY;IAC3E,IAAI,GAAG,YAAY,aAAa;QAAE,OAAO,GAAG,CAAC;IAC7C,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,OAAO,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { JournalEntry } from './types.js';
|
|
2
|
+
/** Get size of a file in bytes. Returns 0 if file doesn't exist. */
|
|
3
|
+
export declare function fileSize(filePath: string): Promise<number>;
|
|
4
|
+
/** Get total size of a directory (recursive) in bytes. */
|
|
5
|
+
export declare function dirSize(dirPath: string): Promise<number>;
|
|
6
|
+
/** List all files in a directory recursively. */
|
|
7
|
+
export declare function listFilesRecursive(dirPath: string): Promise<string[]>;
|
|
8
|
+
/** Get disk free space in GB for the drive containing a given path. */
|
|
9
|
+
export declare function getDiskFreeGB(targetPath: string): Promise<number>;
|
|
10
|
+
/** Gzip a file in place (original → original.gz, original deleted). */
|
|
11
|
+
export declare function gzipFile(filePath: string): Promise<string>;
|
|
12
|
+
/** Read the last N lines of a file. */
|
|
13
|
+
export declare function tailFile(filePath: string, lines: number): Promise<string>;
|
|
14
|
+
/** Trim a file to its last N lines. Returns new size in bytes. */
|
|
15
|
+
export declare function trimFileToLines(filePath: string, keepLines: number): Promise<number>;
|
|
16
|
+
/** Append a journal entry. */
|
|
17
|
+
export declare function writeJournalEntry(entry: JournalEntry): Promise<void>;
|
|
18
|
+
/** Read the journal (last N entries). */
|
|
19
|
+
export declare function readJournal(lastN?: number): Promise<JournalEntry[]>;
|
|
20
|
+
/** Bytes to MB, 2 decimal places. */
|
|
21
|
+
export declare function bytesToMB(bytes: number): number;
|
|
22
|
+
/** Check if a path exists. */
|
|
23
|
+
export declare function pathExists(p: string): Promise<boolean>;
|