session-intelligence-cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/report-bg.d.ts +2 -0
- package/dist/report-bg.js +61 -0
- package/dist/report.js +27 -43
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { readGitState, readGitDiffStats } from "./git.js";
|
|
4
|
+
import { sendEvent } from "./api.js";
|
|
5
|
+
// Called as: node report-bg.js <json-payload>
|
|
6
|
+
// Runs detached from the parent process to avoid being killed on session teardown.
|
|
7
|
+
const raw = process.argv[2];
|
|
8
|
+
if (!raw)
|
|
9
|
+
process.exit(0);
|
|
10
|
+
const stdinData = JSON.parse(raw);
|
|
11
|
+
const sessionId = stdinData.session_id ?? "";
|
|
12
|
+
const cwd = stdinData.cwd ?? process.cwd();
|
|
13
|
+
const payload = {
|
|
14
|
+
session_id: sessionId,
|
|
15
|
+
cwd,
|
|
16
|
+
hook_event_name: "SessionEnd",
|
|
17
|
+
model: stdinData.model,
|
|
18
|
+
};
|
|
19
|
+
const transcriptPath = stdinData.transcript_path;
|
|
20
|
+
if (transcriptPath) {
|
|
21
|
+
try {
|
|
22
|
+
const content = readFileSync(transcriptPath, "utf-8");
|
|
23
|
+
const usage = { input_tokens: 0, output_tokens: 0, cache_read_tokens: 0, cache_creation_tokens: 0 };
|
|
24
|
+
for (const line of content.split("\n")) {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (!trimmed)
|
|
27
|
+
continue;
|
|
28
|
+
try {
|
|
29
|
+
const entry = JSON.parse(trimmed);
|
|
30
|
+
if (entry.type !== "assistant" || !entry.message?.usage)
|
|
31
|
+
continue;
|
|
32
|
+
const u = entry.message.usage;
|
|
33
|
+
usage.input_tokens += u.input_tokens ?? 0;
|
|
34
|
+
usage.output_tokens += u.output_tokens ?? 0;
|
|
35
|
+
usage.cache_read_tokens += u.cache_read_input_tokens ?? 0;
|
|
36
|
+
usage.cache_creation_tokens += u.cache_creation_input_tokens ?? 0;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// skip malformed lines
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
payload.usage = usage;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// transcript unreadable
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const git = readGitState(cwd);
|
|
49
|
+
if (git) {
|
|
50
|
+
const stats = readGitDiffStats(cwd);
|
|
51
|
+
payload.git = {
|
|
52
|
+
branch: git.branch,
|
|
53
|
+
lastCommitSha: git.lastCommitSha,
|
|
54
|
+
lastCommitMessage: git.lastCommitMessage,
|
|
55
|
+
hasUncommittedChanges: git.hasUncommittedChanges,
|
|
56
|
+
filesChanged: stats.filesChanged,
|
|
57
|
+
insertions: stats.insertions,
|
|
58
|
+
deletions: stats.deletions,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
await sendEvent(payload);
|
package/dist/report.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
2
4
|
import { readGitState, readGitDiffStats } from "./git.js";
|
|
3
5
|
import { sendEvent } from "./api.js";
|
|
4
6
|
const EVENT_MAP = {
|
|
@@ -9,47 +11,35 @@ const EVENT_MAP = {
|
|
|
9
11
|
"notification": "Notification",
|
|
10
12
|
"subagent-stop": "SubagentStop",
|
|
11
13
|
};
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const trimmed = line.trim();
|
|
18
|
-
if (!trimmed)
|
|
19
|
-
continue;
|
|
14
|
+
function readStdin() {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
18
|
+
process.stdin.on("end", () => {
|
|
20
19
|
try {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
continue;
|
|
24
|
-
const u = entry.message.usage;
|
|
25
|
-
zero.input_tokens += u.input_tokens ?? 0;
|
|
26
|
-
zero.output_tokens += u.output_tokens ?? 0;
|
|
27
|
-
zero.cache_read_tokens += u.cache_read_input_tokens ?? 0;
|
|
28
|
-
zero.cache_creation_tokens += u.cache_creation_input_tokens ?? 0;
|
|
20
|
+
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
21
|
+
resolve(raw ? JSON.parse(raw) : {});
|
|
29
22
|
}
|
|
30
23
|
catch {
|
|
31
|
-
|
|
24
|
+
resolve({});
|
|
32
25
|
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// file not found or unreadable
|
|
37
|
-
}
|
|
38
|
-
return zero;
|
|
26
|
+
});
|
|
27
|
+
process.stdin.on("error", () => resolve({}));
|
|
28
|
+
});
|
|
39
29
|
}
|
|
40
30
|
export async function report(eventType) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
31
|
+
const stdinData = await readStdin();
|
|
32
|
+
// For session-end, spawn a detached background process so the hook
|
|
33
|
+
// can exit immediately and avoid being killed during session teardown.
|
|
34
|
+
if (eventType === "session-end") {
|
|
35
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
const bgScript = join(scriptDir, "report-bg.js");
|
|
37
|
+
const child = spawn(process.execPath, [bgScript, JSON.stringify(stdinData)], {
|
|
38
|
+
detached: true,
|
|
39
|
+
stdio: "ignore",
|
|
40
|
+
});
|
|
41
|
+
child.unref();
|
|
42
|
+
return;
|
|
53
43
|
}
|
|
54
44
|
const sessionId = stdinData.session_id ?? "";
|
|
55
45
|
const cwd = stdinData.cwd ?? process.cwd();
|
|
@@ -60,12 +50,6 @@ export async function report(eventType) {
|
|
|
60
50
|
model: stdinData.model,
|
|
61
51
|
tool_name: stdinData.tool_name,
|
|
62
52
|
};
|
|
63
|
-
if (eventType === "session-end") {
|
|
64
|
-
const transcriptPath = stdinData.transcript_path;
|
|
65
|
-
if (transcriptPath) {
|
|
66
|
-
payload.usage = parseTranscriptTokens(transcriptPath);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
53
|
const git = readGitState(cwd);
|
|
70
54
|
if (git) {
|
|
71
55
|
const gitPayload = {
|
|
@@ -74,7 +58,7 @@ export async function report(eventType) {
|
|
|
74
58
|
lastCommitMessage: git.lastCommitMessage,
|
|
75
59
|
hasUncommittedChanges: git.hasUncommittedChanges,
|
|
76
60
|
};
|
|
77
|
-
if (eventType === "stop"
|
|
61
|
+
if (eventType === "stop") {
|
|
78
62
|
const stats = readGitDiffStats(cwd);
|
|
79
63
|
gitPayload.filesChanged = stats.filesChanged;
|
|
80
64
|
gitPayload.insertions = stats.insertions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "session-intelligence-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Real-time dashboard for Claude Code sessions — track activity, git changes, token usage, and session history across all your projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|