fix: ignore non-persistent claude startups

This commit is contained in:
William Valentin
2026-04-30 17:07:19 -07:00
parent 476c0e347f
commit f8bec2d6d5
2 changed files with 103 additions and 6 deletions
+48 -3
View File
@@ -201,6 +201,36 @@ function clearState(sessionKey) {
} catch { } catch {
} }
} }
function readProcCmdline(pid) {
try {
return readFileSync(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ").trim();
} catch {
return "";
}
}
function readProcPPID(pid) {
try {
const status = readFileSync(`/proc/${pid}/status`, "utf8");
const match = status.match(/^PPid:\s+(\d+)$/m);
return match ? Number(match[1]) : void 0;
} catch {
return void 0;
}
}
function getProcessTree() {
const tree = [];
let pid = process.pid;
for (let i = 0; pid && i < 8; i++) {
tree.push({ pid, cmd: readProcCmdline(pid) });
pid = readProcPPID(pid);
}
return tree;
}
function isNonPersistentClaudeLaunch() {
return getProcessTree().some(
({ cmd }) => cmd.includes("/claude") && cmd.includes("--no-session-persistence")
);
}
var activeRuns = /* @__PURE__ */ new Map(); var activeRuns = /* @__PURE__ */ new Map();
var activeSpans = /* @__PURE__ */ new Map(); var activeSpans = /* @__PURE__ */ new Map();
var activeSubagents = /* @__PURE__ */ new Map(); var activeSubagents = /* @__PURE__ */ new Map();
@@ -275,8 +305,18 @@ async function handleSessionStart(input) {
return; return;
} }
const hookEventName = pickString(input.hook_event_name); const hookEventName = pickString(input.hook_event_name);
if (hookEventName && hookEventName !== "SessionStart") { if (hookEventName !== "SessionStart") {
console.error(`[agentmon] ignoring claude-code session.start with hook_event_name=${hookEventName}`); console.error(`[agentmon] ignoring claude-code session.start with hook_event_name=${hookEventName || "missing"}`);
return;
}
const cwd = pickString(input.cwd);
const transcriptPath = pickString(input.transcript_path);
if (!cwd || !transcriptPath) {
console.error("[agentmon] ignoring claude-code session.start without cwd or transcript_path");
return;
}
if (pickString(input.source) === "startup" && isNonPersistentClaudeLaunch()) {
console.error("[agentmon] ignoring claude-code startup from --no-session-persistence launch");
return; return;
} }
const runId = randomUUID2(); const runId = randomUUID2();
@@ -284,7 +324,12 @@ async function handleSessionStart(input) {
saveState(sessionKey, { runId, spans: {} }); saveState(sessionKey, { runId, spans: {} });
const contextWindow = getContextWindow(input); const contextWindow = getContextWindow(input);
enqueue(buildEnvelope(FRAMEWORK, HOST, "session.start", sessionKey, { enqueue(buildEnvelope(FRAMEWORK, HOST, "session.start", sessionKey, {
attributes: contextWindow ? { context_window: contextWindow } : void 0 attributes: {
cwd,
transcript_path: transcriptPath,
source: pickString(input.source),
...contextWindow && { context_window: contextWindow }
}
})); }));
enqueue(buildEnvelope(FRAMEWORK, HOST, "run.start", sessionKey, { enqueue(buildEnvelope(FRAMEWORK, HOST, "run.start", sessionKey, {
runId, runId,
+55 -3
View File
@@ -54,6 +54,41 @@ function saveState(sessionKey: string, state: SessionState) {
function clearState(sessionKey: string) { function clearState(sessionKey: string) {
try { unlinkSync(join(STATE_DIR, sessionKey + '.json')); } catch { /* ignore */ } try { unlinkSync(join(STATE_DIR, sessionKey + '.json')); } catch { /* ignore */ }
} }
function readProcCmdline(pid: number): string {
try {
return readFileSync(`/proc/${pid}/cmdline`, 'utf8').replace(/\0/g, ' ').trim();
} catch {
return '';
}
}
function readProcPPID(pid: number): number | undefined {
try {
const status = readFileSync(`/proc/${pid}/status`, 'utf8');
const match = status.match(/^PPid:\s+(\d+)$/m);
return match ? Number(match[1]) : undefined;
} catch {
return undefined;
}
}
function getProcessTree() {
const tree: Array<{ pid: number; cmd: string }> = [];
let pid: number | undefined = process.pid;
for (let i = 0; pid && i < 8; i++) {
tree.push({ pid, cmd: readProcCmdline(pid) });
pid = readProcPPID(pid);
}
return tree;
}
function isNonPersistentClaudeLaunch() {
return getProcessTree().some(({ cmd }) =>
cmd.includes('/claude') && cmd.includes('--no-session-persistence')
);
}
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
const activeRuns = new Map<string, string>(); const activeRuns = new Map<string, string>();
@@ -131,8 +166,20 @@ async function handleSessionStart(input: Dict) {
} }
const hookEventName = pickString(input.hook_event_name); const hookEventName = pickString(input.hook_event_name);
if (hookEventName && hookEventName !== 'SessionStart') { if (hookEventName !== 'SessionStart') {
console.error(`[agentmon] ignoring claude-code session.start with hook_event_name=${hookEventName}`); console.error(`[agentmon] ignoring claude-code session.start with hook_event_name=${hookEventName || 'missing'}`);
return;
}
const cwd = pickString(input.cwd);
const transcriptPath = pickString(input.transcript_path);
if (!cwd || !transcriptPath) {
console.error('[agentmon] ignoring claude-code session.start without cwd or transcript_path');
return;
}
if (pickString(input.source) === 'startup' && isNonPersistentClaudeLaunch()) {
console.error('[agentmon] ignoring claude-code startup from --no-session-persistence launch');
return; return;
} }
@@ -143,7 +190,12 @@ async function handleSessionStart(input: Dict) {
const contextWindow = getContextWindow(input); const contextWindow = getContextWindow(input);
enqueue(buildEnvelope(FRAMEWORK, HOST, 'session.start', sessionKey, { enqueue(buildEnvelope(FRAMEWORK, HOST, 'session.start', sessionKey, {
attributes: contextWindow ? { context_window: contextWindow } : undefined, attributes: {
cwd,
transcript_path: transcriptPath,
source: pickString(input.source),
...(contextWindow && { context_window: contextWindow }),
},
})); }));
enqueue(buildEnvelope(FRAMEWORK, HOST, 'run.start', sessionKey, { enqueue(buildEnvelope(FRAMEWORK, HOST, 'run.start', sessionKey, {