bb-cc-lite 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.
@@ -0,0 +1,231 @@
1
+ import { open, stat } from "node:fs/promises";
2
+ import { basename } from "node:path";
3
+ import { asRecord, extractUsage, mergeUsage, stringField } from "./status-input.js";
4
+ const DEFAULT_MAX_BYTES = 512 * 1024;
5
+ const TEST_COMMAND_RE = /\b(npm|pnpm|yarn|bun)\s+(run\s+)?(test|vitest|jest)|\b(vitest|jest|mocha|pytest|cargo\s+test|go\s+test|rspec|playwright\s+test)\b/i;
6
+ export async function parseTranscriptTail(transcriptPath, options = {}) {
7
+ if (!transcriptPath) {
8
+ return emptySummary(false);
9
+ }
10
+ try {
11
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
12
+ const fileStat = await stat(transcriptPath);
13
+ const bytesRead = Math.min(fileStat.size, maxBytes);
14
+ const start = Math.max(0, fileStat.size - bytesRead);
15
+ const handle = await open(transcriptPath, "r");
16
+ try {
17
+ const buffer = Buffer.alloc(bytesRead);
18
+ await handle.read(buffer, 0, bytesRead, start);
19
+ const text = buffer.toString("utf8");
20
+ const lines = trimPartialFirstLine(text, start).split(/\r?\n/).filter(Boolean);
21
+ return parseTranscriptLines(lines, bytesRead);
22
+ }
23
+ finally {
24
+ await handle.close();
25
+ }
26
+ }
27
+ catch {
28
+ return emptySummary(false);
29
+ }
30
+ }
31
+ export function parseTranscriptLines(lines, bytesRead = Buffer.byteLength(lines.join("\n"))) {
32
+ const toolById = new Map();
33
+ const failureCounts = new Map();
34
+ let recentEditBeforeTest = false;
35
+ let editTestLoopFailures = 0;
36
+ let toolCalls = 0;
37
+ let failedToolResults = 0;
38
+ let malformedLines = 0;
39
+ let compactionEvents = 0;
40
+ let usage = {};
41
+ let latestTimestamp;
42
+ for (const line of lines) {
43
+ let parsed;
44
+ try {
45
+ parsed = JSON.parse(line);
46
+ }
47
+ catch {
48
+ malformedLines += 1;
49
+ continue;
50
+ }
51
+ const entry = asRecord(parsed);
52
+ if (!entry) {
53
+ malformedLines += 1;
54
+ continue;
55
+ }
56
+ latestTimestamp = stringField(entry.timestamp) || latestTimestamp;
57
+ usage = mergeUsage(usage, extractUsage(entry), extractUsage(asRecord(entry.message)));
58
+ if (isCompactionEvent(entry)) {
59
+ compactionEvents += 1;
60
+ }
61
+ for (const toolUse of extractToolUses(entry)) {
62
+ toolCalls += 1;
63
+ if (toolUse.id) {
64
+ toolById.set(toolUse.id, {
65
+ name: safeToolName(toolUse.name),
66
+ purpose: classifyToolPurpose(toolUse.name, toolUse.input)
67
+ });
68
+ }
69
+ if (isEditTool(toolUse.name)) {
70
+ recentEditBeforeTest = true;
71
+ }
72
+ }
73
+ for (const toolResult of extractToolResults(entry)) {
74
+ if (!toolResult.isError) {
75
+ continue;
76
+ }
77
+ failedToolResults += 1;
78
+ const meta = (toolResult.toolUseId ? toolById.get(toolResult.toolUseId) : undefined) ||
79
+ (toolResult.toolName ? { name: safeToolName(toolResult.toolName), purpose: undefined } : undefined) ||
80
+ { name: "tool", purpose: undefined };
81
+ const purpose = toolResult.purpose || meta.purpose;
82
+ const key = `${meta.name}:${purpose || ""}`;
83
+ const existing = failureCounts.get(key);
84
+ failureCounts.set(key, {
85
+ toolName: meta.name,
86
+ purpose,
87
+ count: (existing?.count || 0) + 1
88
+ });
89
+ if (meta.name === "Bash" && purpose === "tests" && recentEditBeforeTest) {
90
+ editTestLoopFailures += 1;
91
+ recentEditBeforeTest = false;
92
+ }
93
+ }
94
+ }
95
+ return {
96
+ pathReadable: true,
97
+ bytesRead,
98
+ linesRead: lines.length,
99
+ malformedLines,
100
+ toolCalls,
101
+ failedToolResults,
102
+ repeatedFailures: [...failureCounts.values()].filter((item) => item.count >= 2),
103
+ editTestLoopFailures,
104
+ compactionEvents,
105
+ usage,
106
+ latestTimestamp
107
+ };
108
+ }
109
+ function emptySummary(pathReadable) {
110
+ return {
111
+ pathReadable,
112
+ bytesRead: 0,
113
+ linesRead: 0,
114
+ malformedLines: 0,
115
+ toolCalls: 0,
116
+ failedToolResults: 0,
117
+ repeatedFailures: [],
118
+ editTestLoopFailures: 0,
119
+ compactionEvents: 0,
120
+ usage: {}
121
+ };
122
+ }
123
+ function trimPartialFirstLine(text, start) {
124
+ if (start === 0) {
125
+ return text;
126
+ }
127
+ const newline = text.indexOf("\n");
128
+ return newline === -1 ? "" : text.slice(newline + 1);
129
+ }
130
+ function extractToolUses(entry) {
131
+ const result = [];
132
+ for (const part of contentParts(entry)) {
133
+ if (part.type === "tool_use") {
134
+ const name = stringField(part.name);
135
+ if (name) {
136
+ result.push({ id: stringField(part.id), name, input: part.input });
137
+ }
138
+ }
139
+ }
140
+ const toolUse = asRecord(entry.tool_use) || asRecord(entry.toolUse);
141
+ const directName = stringField(toolUse?.name) || stringField(entry.tool_name) || stringField(entry.toolName);
142
+ if (directName && (entry.type === "tool_use" || toolUse)) {
143
+ result.push({ id: stringField(toolUse?.id) || stringField(entry.tool_use_id), name: directName, input: toolUse?.input });
144
+ }
145
+ return result;
146
+ }
147
+ function extractToolResults(entry) {
148
+ const result = [];
149
+ for (const part of contentParts(entry)) {
150
+ if (part.type === "tool_result") {
151
+ result.push({
152
+ toolUseId: stringField(part.tool_use_id) || stringField(part.toolUseId),
153
+ toolName: stringField(part.name) || stringField(part.tool_name),
154
+ isError: truthyError(part),
155
+ purpose: classifyResultPurpose(part)
156
+ });
157
+ }
158
+ }
159
+ if (entry.type === "tool_result" || entry.type === "tool_result_delta") {
160
+ result.push({
161
+ toolUseId: stringField(entry.tool_use_id) || stringField(entry.toolUseId),
162
+ toolName: stringField(entry.name) || stringField(entry.tool_name) || stringField(entry.toolName),
163
+ isError: truthyError(entry),
164
+ purpose: classifyResultPurpose(entry)
165
+ });
166
+ }
167
+ return result;
168
+ }
169
+ function contentParts(entry) {
170
+ const message = asRecord(entry.message);
171
+ const candidates = [entry.content, message?.content];
172
+ const parts = [];
173
+ for (const candidate of candidates) {
174
+ if (Array.isArray(candidate)) {
175
+ parts.push(...candidate.flatMap((part) => (asRecord(part) ? [asRecord(part)] : [])));
176
+ }
177
+ else if (asRecord(candidate)) {
178
+ parts.push(asRecord(candidate));
179
+ }
180
+ }
181
+ return parts;
182
+ }
183
+ function truthyError(value) {
184
+ if (value.is_error === true || value.isError === true || value.error === true) {
185
+ return true;
186
+ }
187
+ const status = stringField(value.status) || stringField(value.result);
188
+ if (status && /error|failed|failure/i.test(status)) {
189
+ return true;
190
+ }
191
+ const exitCode = value.exit_code ?? value.exitCode;
192
+ return typeof exitCode === "number" && exitCode !== 0;
193
+ }
194
+ function classifyToolPurpose(toolName, input) {
195
+ if (safeToolName(toolName) !== "Bash") {
196
+ return undefined;
197
+ }
198
+ const command = stringField(asRecord(input)?.command);
199
+ if (command && TEST_COMMAND_RE.test(command)) {
200
+ return "tests";
201
+ }
202
+ return undefined;
203
+ }
204
+ function classifyResultPurpose(part) {
205
+ const title = stringField(part.title) || stringField(part.summary);
206
+ if (title && /test/i.test(title)) {
207
+ return "tests";
208
+ }
209
+ return undefined;
210
+ }
211
+ function isEditTool(toolName) {
212
+ return /^(Edit|MultiEdit|Write|NotebookEdit)$/u.test(safeToolName(toolName));
213
+ }
214
+ function safeToolName(toolName) {
215
+ if (!toolName) {
216
+ return "tool";
217
+ }
218
+ const base = basename(toolName);
219
+ return /^[A-Za-z][A-Za-z0-9_-]{0,32}$/u.test(base) ? base : "tool";
220
+ }
221
+ function isCompactionEvent(entry) {
222
+ const event = stringField(entry.hook_event_name) || stringField(entry.event) || stringField(entry.type);
223
+ if (event && /compact/i.test(event)) {
224
+ return true;
225
+ }
226
+ const message = asRecord(entry.message);
227
+ const role = stringField(message?.role) || stringField(entry.role);
228
+ const content = typeof entry.content === "string" ? entry.content : typeof message?.content === "string" ? message.content : "";
229
+ return role === "system" && /\b(compact|compaction)\b/i.test(content);
230
+ }
231
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ export type DecisionState = "Healthy" | "Careful" | "Stop";
2
+ export interface StatusLineModel {
3
+ id?: string;
4
+ displayName?: string;
5
+ }
6
+ export interface TokenUsage {
7
+ inputTokens?: number;
8
+ outputTokens?: number;
9
+ cacheCreationInputTokens?: number;
10
+ cacheReadInputTokens?: number;
11
+ totalTokens?: number;
12
+ }
13
+ export interface StatusLineInput {
14
+ rawValid: boolean;
15
+ sessionId?: string;
16
+ transcriptPath?: string;
17
+ cwd?: string;
18
+ model: StatusLineModel;
19
+ costUsd?: number;
20
+ costSource?: "claude" | "estimated";
21
+ durationMs?: number;
22
+ contextPercent?: number;
23
+ rateLimitPercent?: number;
24
+ usage: TokenUsage;
25
+ terminalWidth?: number;
26
+ parseError?: string;
27
+ }
28
+ export interface ToolFailureSummary {
29
+ toolName: string;
30
+ count: number;
31
+ purpose?: string;
32
+ }
33
+ export interface TranscriptSummary {
34
+ pathReadable: boolean;
35
+ bytesRead: number;
36
+ linesRead: number;
37
+ malformedLines: number;
38
+ toolCalls: number;
39
+ failedToolResults: number;
40
+ repeatedFailures: ToolFailureSummary[];
41
+ editTestLoopFailures: number;
42
+ compactionEvents: number;
43
+ usage: TokenUsage;
44
+ latestTimestamp?: string;
45
+ }
46
+ export type HookEventKind = "tool_success" | "tool_failure" | "tool_batch" | "compaction" | "stop" | "session_end";
47
+ export interface DerivedHookEvent {
48
+ kind: HookEventKind;
49
+ sessionKey?: string;
50
+ timestamp: string;
51
+ hookEventName: string;
52
+ toolName?: string;
53
+ purpose?: string;
54
+ toolCount?: number;
55
+ }
56
+ export interface StoredHookEvent extends DerivedHookEvent {
57
+ id: string;
58
+ }
59
+ export interface DecisionEvidence {
60
+ label: string;
61
+ detail?: string;
62
+ }
63
+ export interface Decision {
64
+ state: DecisionState;
65
+ reasonCode: string;
66
+ primaryEvidence: string;
67
+ evidence: DecisionEvidence[];
68
+ impact: string;
69
+ action: string;
70
+ costUsd?: number;
71
+ costSource?: "claude" | "estimated";
72
+ contextPercent?: number;
73
+ rateLimitPercent?: number;
74
+ sessionKey?: string;
75
+ createdAt: string;
76
+ }
77
+ export interface StoredDecision extends Decision {
78
+ id: string;
79
+ }
80
+ export interface EventStoreData {
81
+ version: 1;
82
+ updatedAt: string;
83
+ decisions: StoredDecision[];
84
+ hookEvents: StoredHookEvent[];
85
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "bb-cc-lite",
3
+ "version": "0.1.0",
4
+ "description": "Black Box Claude Code Lite: a small Claude Code status line that says when to continue, slow down, or stop.",
5
+ "type": "module",
6
+ "author": "Softcane",
7
+ "homepage": "https://github.com/softcane/bb-cc-lite#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/softcane/bb-cc-lite.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/softcane/bb-cc-lite/issues"
14
+ },
15
+ "bin": {
16
+ "bb-cc-lite": "dist/cli.js"
17
+ },
18
+ "files": [
19
+ "assets",
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
25
+ "typecheck": "tsc -p tsconfig.json --noEmit",
26
+ "lint": "eslint .",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "prepublishOnly": "npm run typecheck && npm run lint && npm test && npm run build"
30
+ },
31
+ "engines": {
32
+ "node": ">=20"
33
+ },
34
+ "keywords": [
35
+ "black-box",
36
+ "blackbox",
37
+ "claude-code",
38
+ "claude",
39
+ "statusline",
40
+ "litellm",
41
+ "cli"
42
+ ],
43
+ "license": "MIT",
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.39.1",
46
+ "@types/node": "^25.0.0",
47
+ "eslint": "^9.39.1",
48
+ "typescript": "^5.9.3",
49
+ "typescript-eslint": "^8.48.0",
50
+ "vitest": "^4.0.14"
51
+ }
52
+ }