@ironbee-ai/cli 0.11.4 → 0.13.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 +12 -0
- package/README.md +17 -3
- package/dist/assets/banner.txt +1 -1
- package/dist/clients/claude/hooks/session-start.d.ts.map +1 -1
- package/dist/clients/claude/hooks/session-start.js +7 -0
- package/dist/clients/claude/hooks/session-start.js.map +1 -1
- package/dist/clients/claude/hooks/session-status.d.ts +129 -0
- package/dist/clients/claude/hooks/session-status.d.ts.map +1 -0
- package/dist/clients/claude/hooks/session-status.js +450 -0
- package/dist/clients/claude/hooks/session-status.js.map +1 -0
- package/dist/clients/claude/index.d.ts +26 -0
- package/dist/clients/claude/index.d.ts.map +1 -1
- package/dist/clients/claude/index.js +151 -0
- package/dist/clients/claude/index.js.map +1 -1
- package/dist/clients/cursor/index.d.ts.map +1 -1
- package/dist/clients/cursor/index.js +6 -0
- package/dist/clients/cursor/index.js.map +1 -1
- package/dist/clients/registry.d.ts +8 -9
- package/dist/clients/registry.d.ts.map +1 -1
- package/dist/clients/registry.js +13 -11
- package/dist/clients/registry.js.map +1 -1
- package/dist/commands/config.d.ts +5 -4
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +10 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/hook.js +44 -0
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +4 -5
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/register.d.ts +0 -1
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +7 -27
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/statusline-toggle.d.ts +29 -0
- package/dist/commands/statusline-toggle.d.ts.map +1 -0
- package/dist/commands/statusline-toggle.js +114 -0
- package/dist/commands/statusline-toggle.js.map +1 -0
- package/dist/commands/statusline.d.ts +24 -0
- package/dist/commands/statusline.d.ts.map +1 -0
- package/dist/commands/statusline.js +79 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/uninstall.d.ts +2 -3
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +3 -4
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/unregister.d.ts +0 -1
- package/dist/commands/unregister.d.ts.map +1 -1
- package/dist/commands/unregister.js +3 -24
- package/dist/commands/unregister.js.map +1 -1
- package/dist/hooks/core/session-state.d.ts +25 -0
- package/dist/hooks/core/session-state.d.ts.map +1 -1
- package/dist/hooks/core/session-state.js +49 -1
- package/dist/hooks/core/session-state.js.map +1 -1
- package/dist/index.js +35 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +64 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +48 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/event.d.ts +60 -0
- package/dist/lib/event.d.ts.map +1 -1
- package/dist/lib/event.js +1 -0
- package/dist/lib/event.js.map +1 -1
- package/dist/lib/fs-prune.d.ts +20 -0
- package/dist/lib/fs-prune.d.ts.map +1 -0
- package/dist/lib/fs-prune.js +72 -0
- package/dist/lib/fs-prune.js.map +1 -0
- package/dist/lib/gitignore.d.ts.map +1 -1
- package/dist/lib/gitignore.js +11 -0
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/install-snapshots.d.ts +70 -0
- package/dist/lib/install-snapshots.d.ts.map +1 -0
- package/dist/lib/install-snapshots.js +168 -0
- package/dist/lib/install-snapshots.js.map +1 -0
- package/dist/lib/projects-registry.d.ts +6 -13
- package/dist/lib/projects-registry.d.ts.map +1 -1
- package/dist/lib/projects-registry.js +11 -46
- package/dist/lib/projects-registry.js.map +1 -1
- package/dist/tui/command.d.ts +18 -0
- package/dist/tui/command.d.ts.map +1 -0
- package/dist/tui/command.js +87 -0
- package/dist/tui/command.js.map +1 -0
- package/dist/tui/config/area.d.ts +6 -0
- package/dist/tui/config/area.d.ts.map +1 -0
- package/dist/tui/config/area.js +16 -0
- package/dist/tui/config/area.js.map +1 -0
- package/dist/tui/config/docs.d.ts +28 -0
- package/dist/tui/config/docs.d.ts.map +1 -0
- package/dist/tui/config/docs.js +68 -0
- package/dist/tui/config/docs.js.map +1 -0
- package/dist/tui/config/edit.d.ts +36 -0
- package/dist/tui/config/edit.d.ts.map +1 -0
- package/dist/tui/config/edit.js +69 -0
- package/dist/tui/config/edit.js.map +1 -0
- package/dist/tui/config/introspect.d.ts +58 -0
- package/dist/tui/config/introspect.d.ts.map +1 -0
- package/dist/tui/config/introspect.js +93 -0
- package/dist/tui/config/introspect.js.map +1 -0
- package/dist/tui/config/schema.d.ts +81 -0
- package/dist/tui/config/schema.d.ts.map +1 -0
- package/dist/tui/config/schema.js +534 -0
- package/dist/tui/config/schema.js.map +1 -0
- package/dist/tui/config/tree.d.ts +39 -0
- package/dist/tui/config/tree.d.ts.map +1 -0
- package/dist/tui/config/tree.js +59 -0
- package/dist/tui/config/tree.js.map +1 -0
- package/dist/tui/config/value.d.ts +75 -0
- package/dist/tui/config/value.d.ts.map +1 -0
- package/dist/tui/config/value.js +228 -0
- package/dist/tui/config/value.js.map +1 -0
- package/dist/tui/config/view.d.ts +13 -0
- package/dist/tui/config/view.d.ts.map +1 -0
- package/dist/tui/config/view.js +423 -0
- package/dist/tui/config/view.js.map +1 -0
- package/dist/tui/import/area.d.ts +11 -0
- package/dist/tui/import/area.d.ts.map +1 -0
- package/dist/tui/import/area.js +202 -0
- package/dist/tui/import/area.js.map +1 -0
- package/dist/tui/index.d.ts +9 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +14 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/platforms/area.d.ts +12 -0
- package/dist/tui/platforms/area.d.ts.map +1 -0
- package/dist/tui/platforms/area.js +228 -0
- package/dist/tui/platforms/area.js.map +1 -0
- package/dist/tui/projects/area.d.ts +26 -0
- package/dist/tui/projects/area.d.ts.map +1 -0
- package/dist/tui/projects/area.js +588 -0
- package/dist/tui/projects/area.js.map +1 -0
- package/dist/tui/queue/area.d.ts +11 -0
- package/dist/tui/queue/area.d.ts.map +1 -0
- package/dist/tui/queue/area.js +338 -0
- package/dist/tui/queue/area.js.map +1 -0
- package/dist/tui/queue/read.d.ts +49 -0
- package/dist/tui/queue/read.d.ts.map +1 -0
- package/dist/tui/queue/read.js +261 -0
- package/dist/tui/queue/read.js.map +1 -0
- package/dist/tui/sessions/area.d.ts +10 -0
- package/dist/tui/sessions/area.d.ts.map +1 -0
- package/dist/tui/sessions/area.js +266 -0
- package/dist/tui/sessions/area.js.map +1 -0
- package/dist/tui/sessions/read.d.ts +79 -0
- package/dist/tui/sessions/read.d.ts.map +1 -0
- package/dist/tui/sessions/read.js +202 -0
- package/dist/tui/sessions/read.js.map +1 -0
- package/dist/tui/shell/area.d.ts +47 -0
- package/dist/tui/shell/area.d.ts.map +1 -0
- package/dist/tui/shell/area.js +13 -0
- package/dist/tui/shell/area.js.map +1 -0
- package/dist/tui/shell/frame.d.ts +23 -0
- package/dist/tui/shell/frame.d.ts.map +1 -0
- package/dist/tui/shell/frame.js +91 -0
- package/dist/tui/shell/frame.js.map +1 -0
- package/dist/tui/shell/registry.d.ts +11 -0
- package/dist/tui/shell/registry.d.ts.map +1 -0
- package/dist/tui/shell/registry.js +29 -0
- package/dist/tui/shell/registry.js.map +1 -0
- package/dist/tui/shell/rerender.d.ts +16 -0
- package/dist/tui/shell/rerender.d.ts.map +1 -0
- package/dist/tui/shell/rerender.js +34 -0
- package/dist/tui/shell/rerender.js.map +1 -0
- package/dist/tui/shell/session.d.ts +75 -0
- package/dist/tui/shell/session.d.ts.map +1 -0
- package/dist/tui/shell/session.js +333 -0
- package/dist/tui/shell/session.js.map +1 -0
- package/dist/tui/shell/shell.d.ts +16 -0
- package/dist/tui/shell/shell.d.ts.map +1 -0
- package/dist/tui/shell/shell.js +213 -0
- package/dist/tui/shell/shell.js.map +1 -0
- package/dist/tui/shell/util.d.ts +18 -0
- package/dist/tui/shell/util.d.ts.map +1 -0
- package/dist/tui/shell/util.js +31 -0
- package/dist/tui/shell/util.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code — statusline wrapper (`ironbee hook session-status`)
|
|
4
|
+
*
|
|
5
|
+
* Installed as the project's `statusLine.command`. On every statusline tick
|
|
6
|
+
* it does two independent things:
|
|
7
|
+
* 1. Submits a `session_status` event (context-window size, cost,
|
|
8
|
+
* subscription rate-limits) to the queue — signals unavailable to hooks
|
|
9
|
+
* or the transcript.
|
|
10
|
+
* 2. Chains to the user's ORIGINAL statusline command so their statusline
|
|
11
|
+
* keeps rendering exactly as before (we wrap, never replace).
|
|
12
|
+
*
|
|
13
|
+
* The event submit is fire-and-forget and must NEVER block or break the
|
|
14
|
+
* statusline render. The chain target is resolved once at SessionStart and
|
|
15
|
+
* cached in state.json; this wrapper falls back to live cascade resolution
|
|
16
|
+
* if the cache is missing/unreadable, so a cache miss can never make the
|
|
17
|
+
* user's statusline vanish.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.isIronbeeStatusLine = isIronbeeStatusLine;
|
|
21
|
+
exports.resolveProjectDir = resolveProjectDir;
|
|
22
|
+
exports.resolveChainTarget = resolveChainTarget;
|
|
23
|
+
exports.normalizeModelId = normalizeModelId;
|
|
24
|
+
exports.buildSessionStatusEvent = buildSessionStatusEvent;
|
|
25
|
+
exports.deriveSessionStatusEventId = deriveSessionStatusEventId;
|
|
26
|
+
exports.computeSessionStatusSignature = computeSessionStatusSignature;
|
|
27
|
+
exports.runSessionStatus = runSessionStatus;
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
29
|
+
const crypto_1 = require("crypto");
|
|
30
|
+
const fs_1 = require("fs");
|
|
31
|
+
const os_1 = require("os");
|
|
32
|
+
const path_1 = require("path");
|
|
33
|
+
const install_snapshots_1 = require("../../../lib/install-snapshots");
|
|
34
|
+
const config_1 = require("../../../lib/config");
|
|
35
|
+
const logger_1 = require("../../../lib/logger");
|
|
36
|
+
const stdin_1 = require("../../../lib/stdin");
|
|
37
|
+
const queue_1 = require("../../../queue");
|
|
38
|
+
const actions_1 = require("../../../hooks/core/actions");
|
|
39
|
+
const session_state_1 = require("../../../hooks/core/session-state");
|
|
40
|
+
const CLIENT = "claude";
|
|
41
|
+
/**
|
|
42
|
+
* True only when the command is EXACTLY our bare wrapper invocation. A tight
|
|
43
|
+
* match so a user who wraps us themselves (`tee >(ironbee hook session-status)
|
|
44
|
+
* | real-cmd`) is NOT mis-identified as "ours" — that compound is their own
|
|
45
|
+
* statusline and must be chained, not skipped.
|
|
46
|
+
*/
|
|
47
|
+
function isIronbeeStatusLine(command) {
|
|
48
|
+
if (typeof command !== "string") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return /^\s*ironbee\s+hook\s+session-status(\s+--client\s+\S+)?\s*$/.test(command);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the project dir anchor. Prefers `CLAUDE_PROJECT_DIR` to stay
|
|
55
|
+
* consistent with every other hook and with SessionStart (session runtime
|
|
56
|
+
* files — state.json, queue — live under exactly this path), falling back to
|
|
57
|
+
* the statusline's `workspace.project_dir` and finally cwd. NOT canonicalized
|
|
58
|
+
* — the snapshot store canonicalizes internally on lookup, and the session
|
|
59
|
+
* dir must match the raw path SessionStart wrote under.
|
|
60
|
+
*/
|
|
61
|
+
function resolveProjectDir(input) {
|
|
62
|
+
return process.env.CLAUDE_PROJECT_DIR
|
|
63
|
+
?? input.workspace?.project_dir
|
|
64
|
+
?? process.cwd();
|
|
65
|
+
}
|
|
66
|
+
/** Read `statusLine.command` from a settings.json file; undefined on any failure. */
|
|
67
|
+
function readStatusLineCommand(settingsPath) {
|
|
68
|
+
if (!(0, fs_1.existsSync)(settingsPath)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse((0, fs_1.readFileSync)(settingsPath, "utf-8"));
|
|
73
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const sl = parsed.statusLine;
|
|
77
|
+
if (sl === null || typeof sl !== "object") {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const cmd = sl.command;
|
|
81
|
+
return typeof cmd === "string" && cmd.length > 0 ? cmd : undefined;
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
logger_1.logger.debug(`session-status: failed to read statusLine from ${settingsPath}: ${e instanceof Error ? e.message : e}`);
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the chain target = the statusline command Claude Code WOULD run
|
|
90
|
+
* without us = the highest-priority non-ours `statusLine.command` across the
|
|
91
|
+
* settings layers, walking high → low:
|
|
92
|
+
* 1. localSettings layer — our wrapper overwrote it, so the original lives
|
|
93
|
+
* in the install snapshot.
|
|
94
|
+
* 2. projectSettings (`.claude/settings.json`) — untouched, read live.
|
|
95
|
+
* 3. userSettings (`~/.claude/settings.json`) — untouched, read live.
|
|
96
|
+
* First non-ours wins. `undefined` = nothing to chain.
|
|
97
|
+
*/
|
|
98
|
+
function resolveChainTarget(projectDir) {
|
|
99
|
+
const snapshot = (0, install_snapshots_1.readStatusLineSnapshot)(projectDir, CLIENT)?.command;
|
|
100
|
+
if (snapshot && !isIronbeeStatusLine(snapshot)) {
|
|
101
|
+
return snapshot;
|
|
102
|
+
}
|
|
103
|
+
const projectCmd = readStatusLineCommand((0, path_1.join)(projectDir, ".claude", "settings.json"));
|
|
104
|
+
if (projectCmd && !isIronbeeStatusLine(projectCmd)) {
|
|
105
|
+
return projectCmd;
|
|
106
|
+
}
|
|
107
|
+
const userCmd = readStatusLineCommand((0, path_1.join)((0, os_1.homedir)(), ".claude", "settings.json"));
|
|
108
|
+
if (userCmd && !isIronbeeStatusLine(userCmd)) {
|
|
109
|
+
return userCmd;
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
function num(value) {
|
|
114
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Strip the bracketed runtime suffix from the model id
|
|
118
|
+
* (`claude-opus-4-7[1m]` → `claude-opus-4-7`). The `[1m]` extended-context
|
|
119
|
+
* marker is redundant on the event — `context_window.context_window_size`
|
|
120
|
+
* already carries the effective window — so we keep the model field a clean
|
|
121
|
+
* canonical id.
|
|
122
|
+
*/
|
|
123
|
+
function normalizeModelId(id) {
|
|
124
|
+
return (id ?? "").replace(/\[[^\]]*\]/g, "").trim();
|
|
125
|
+
}
|
|
126
|
+
/** Map the statusline's `current_usage` explicitly (R12); null passes through. */
|
|
127
|
+
function mapCurrentUsage(usage) {
|
|
128
|
+
if (usage === null || usage === undefined) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
input_tokens: num(usage.input_tokens),
|
|
133
|
+
output_tokens: num(usage.output_tokens),
|
|
134
|
+
cache_creation_input_tokens: num(usage.cache_creation_input_tokens),
|
|
135
|
+
cache_read_input_tokens: num(usage.cache_read_input_tokens),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function mapRateLimitWindow(w) {
|
|
139
|
+
if (!w || typeof w.used_percentage !== "number" || typeof w.resets_at !== "number") {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
// The statusline reports `resets_at` in epoch seconds; convert to ms to
|
|
143
|
+
// match every other IronBee timestamp.
|
|
144
|
+
return { used_percentage: w.used_percentage, resets_at: w.resets_at * 1000 };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build the wire event. Maps fields EXPLICITLY from the statusline JSON (R12)
|
|
148
|
+
* so our wire contract is independent of host JSON drift. `model` is the flat
|
|
149
|
+
* id string. `actionsFile` is only the derivation anchor for `baseFields`
|
|
150
|
+
* (id/session_id/project_name + user/usage) — we never write to it.
|
|
151
|
+
*/
|
|
152
|
+
function buildSessionStatusEvent(input, projectDir, sessionId) {
|
|
153
|
+
const sessionDir = (0, path_1.join)(projectDir, ".ironbee", "sessions", sessionId);
|
|
154
|
+
const actionsFile = (0, path_1.join)(sessionDir, "actions.jsonl");
|
|
155
|
+
const cw = input.context_window ?? {};
|
|
156
|
+
const cost = input.cost ?? {};
|
|
157
|
+
const rl = mapRateLimitWindow(input.rate_limits?.five_hour);
|
|
158
|
+
const rl7 = mapRateLimitWindow(input.rate_limits?.seven_day);
|
|
159
|
+
// The active activity in flight at this tick (torn-read-safe via readState's
|
|
160
|
+
// try/catch). Empty string when no activity is open — e.g. a tick between
|
|
161
|
+
// turns or before the first user prompt.
|
|
162
|
+
const state = (0, session_state_1.readState)(sessionDir);
|
|
163
|
+
const event = {
|
|
164
|
+
...(0, actions_1.baseFields)(actionsFile),
|
|
165
|
+
id: deriveSessionStatusEventId(sessionId, num(cost.total_duration_ms)),
|
|
166
|
+
type: "session_status",
|
|
167
|
+
timestamp: Date.now(),
|
|
168
|
+
activity_id: state.activeActivityId ?? "",
|
|
169
|
+
model: normalizeModelId(input.model?.id),
|
|
170
|
+
cost: {
|
|
171
|
+
total_cost_usd: num(cost.total_cost_usd),
|
|
172
|
+
// Host fields carry the `_ms` suffix; our wire shape drops it (ms implied).
|
|
173
|
+
total_duration: num(cost.total_duration_ms),
|
|
174
|
+
total_api_duration: num(cost.total_api_duration_ms),
|
|
175
|
+
total_lines_added: num(cost.total_lines_added),
|
|
176
|
+
total_lines_removed: num(cost.total_lines_removed),
|
|
177
|
+
},
|
|
178
|
+
context_window: {
|
|
179
|
+
total_input_tokens: num(cw.total_input_tokens),
|
|
180
|
+
total_output_tokens: num(cw.total_output_tokens),
|
|
181
|
+
context_window_size: num(cw.context_window_size),
|
|
182
|
+
used_percentage: num(cw.used_percentage),
|
|
183
|
+
remaining_percentage: num(cw.remaining_percentage),
|
|
184
|
+
current_usage: mapCurrentUsage(cw.current_usage),
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
if (rl || rl7) {
|
|
188
|
+
event.rate_limits = {};
|
|
189
|
+
if (rl) {
|
|
190
|
+
event.rate_limits.five_hour = rl;
|
|
191
|
+
}
|
|
192
|
+
if (rl7) {
|
|
193
|
+
event.rate_limits.seven_day = rl7;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return event;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Deterministic per-tick id. `total_duration_ms` is monotonic within a
|
|
200
|
+
* session (`Date.now() - startTime`), so each tick gets a distinct id and the
|
|
201
|
+
* backend keeps every tick; a cancelled-then-refired identical tick collides
|
|
202
|
+
* on the same id (dedup). UUID-shaped via the same hashing convention as the
|
|
203
|
+
* analytics deterministic ids.
|
|
204
|
+
*/
|
|
205
|
+
function deriveSessionStatusEventId(sessionId, totalDurationMs) {
|
|
206
|
+
const hex = (0, crypto_1.createHash)("sha256")
|
|
207
|
+
.update(`session_status:${sessionId}:${totalDurationMs}`)
|
|
208
|
+
.digest("hex");
|
|
209
|
+
return formatHexAsUuid(hex);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Signature over the RESOURCE-METRIC fields of the event — the fields that
|
|
213
|
+
* only change on an API response. Deliberately EXCLUDES:
|
|
214
|
+
* - `cost.total_duration` / `total_api_duration` — wall-clock durations that
|
|
215
|
+
* tick up on every statusline fire (including them would make the
|
|
216
|
+
* signature differ every tick, defeating the dedup).
|
|
217
|
+
* - `id` / `timestamp` — per-emit, not metrics.
|
|
218
|
+
* - `activity_id` — correlation metadata, not a resource metric (a new turn
|
|
219
|
+
* with frozen metrics shouldn't re-emit; the next real metric change
|
|
220
|
+
* captures the new activity_id).
|
|
221
|
+
* Used by skip-if-unchanged: two ticks with the same signature carry the same
|
|
222
|
+
* resource snapshot, so the later one is a redundant emit and is skipped.
|
|
223
|
+
*/
|
|
224
|
+
function computeSessionStatusSignature(e) {
|
|
225
|
+
const source = {
|
|
226
|
+
model: e.model,
|
|
227
|
+
context_window: e.context_window,
|
|
228
|
+
cost: {
|
|
229
|
+
total_cost_usd: e.cost.total_cost_usd,
|
|
230
|
+
total_lines_added: e.cost.total_lines_added,
|
|
231
|
+
total_lines_removed: e.cost.total_lines_removed,
|
|
232
|
+
},
|
|
233
|
+
rate_limits: e.rate_limits,
|
|
234
|
+
};
|
|
235
|
+
return (0, crypto_1.createHash)("sha256").update(JSON.stringify(source)).digest("hex");
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Path of the per-session statusline state file (single writer: this wrapper).
|
|
239
|
+
* Lives in its own `statusline/` subdir — mirrors `queue/` / `analytics/` so the
|
|
240
|
+
* session dir stays organized — and never in `state.json` (avoids lost-update
|
|
241
|
+
* contention with the per-tool hooks).
|
|
242
|
+
*/
|
|
243
|
+
function statuslineStatePath(projectDir, sessionId) {
|
|
244
|
+
return (0, path_1.join)(projectDir, ".ironbee", "sessions", sessionId, "statusline", "state.json");
|
|
245
|
+
}
|
|
246
|
+
function readStatuslineState(path) {
|
|
247
|
+
if (!(0, fs_1.existsSync)(path)) {
|
|
248
|
+
return {};
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const parsed = JSON.parse((0, fs_1.readFileSync)(path, "utf-8"));
|
|
252
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
253
|
+
return {};
|
|
254
|
+
}
|
|
255
|
+
const obj = parsed;
|
|
256
|
+
return {
|
|
257
|
+
sig: typeof obj.sig === "string" ? obj.sig : undefined,
|
|
258
|
+
lastEmitMs: typeof obj.lastEmitMs === "number" ? obj.lastEmitMs : undefined,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
logger_1.logger.debug(`session-status: failed to read statusline state ${path}: ${e instanceof Error ? e.message : e}`);
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** Atomic write (tmp+rename). Single writer, so no lost-update concern. */
|
|
267
|
+
function writeStatuslineState(path, state) {
|
|
268
|
+
const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
269
|
+
try {
|
|
270
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(path), { recursive: true });
|
|
271
|
+
(0, fs_1.writeFileSync)(tmp, JSON.stringify(state));
|
|
272
|
+
(0, fs_1.renameSync)(tmp, path);
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
try {
|
|
276
|
+
if ((0, fs_1.existsSync)(tmp)) {
|
|
277
|
+
(0, fs_1.unlinkSync)(tmp);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// best-effort cleanup
|
|
282
|
+
}
|
|
283
|
+
logger_1.logger.debug(`session-status: failed to write statusline state ${path}: ${e instanceof Error ? e.message : e}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/** Format a hex digest as a UUID-shaped string (8-4-4-4-12). */
|
|
287
|
+
function formatHexAsUuid(hex) {
|
|
288
|
+
const h = hex.padEnd(32, "0").slice(0, 32);
|
|
289
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Submit the session_status event. Gated on `isSessionStatusEnabled` and on
|
|
293
|
+
* the session being IronBee-tracked. Skips empty pre-first-response ticks (no
|
|
294
|
+
* usage yet) AND content-identical ticks (skip-if-unchanged): the statusline
|
|
295
|
+
* fires far more often than API responses (vim toggles, permission-mode
|
|
296
|
+
* changes, re-renders during tool execution) but the metrics only change on an
|
|
297
|
+
* API response, so without this the wire fills with byte-identical events.
|
|
298
|
+
* Fire-and-forget: errors are swallowed so the statusline render is never
|
|
299
|
+
* affected.
|
|
300
|
+
*/
|
|
301
|
+
async function submitSessionStatusEvent(input, projectDir) {
|
|
302
|
+
const sessionId = input.session_id;
|
|
303
|
+
if (!sessionId) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const cfg = (0, config_1.loadConfig)(projectDir);
|
|
307
|
+
if (!(0, config_1.isSessionStatusEnabled)(cfg)) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// Session-tracking guard: only emit for IronBee-tracked sessions.
|
|
311
|
+
const sessionDir = (0, path_1.join)(projectDir, ".ironbee", "sessions", sessionId);
|
|
312
|
+
if (!(0, fs_1.existsSync)(sessionDir)) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
// Skip empty ticks before the first API response (no usage, zero cost).
|
|
316
|
+
const cw = input.context_window ?? {};
|
|
317
|
+
if ((cw.current_usage === null || cw.current_usage === undefined) && num(cw.total_input_tokens) === 0) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const event = buildSessionStatusEvent(input, projectDir, sessionId);
|
|
321
|
+
const sig = computeSessionStatusSignature(event);
|
|
322
|
+
const statePath = statuslineStatePath(projectDir, sessionId);
|
|
323
|
+
const prev = readStatuslineState(statePath);
|
|
324
|
+
// 1) Skip-if-unchanged: same resource signature → redundant tick, skip
|
|
325
|
+
// without writing (the dominant case — vim/permission/re-render ticks).
|
|
326
|
+
if (prev.sig === sig) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// 2) Min-interval throttle: even on a real metric change, don't emit more
|
|
330
|
+
// often than `emitMinIntervalSeconds` (default 10; 0 disables). Rapid
|
|
331
|
+
// changes coalesce — the next tick after the interval elapses emits the
|
|
332
|
+
// latest state. Skip WITHOUT advancing state so the pending change is
|
|
333
|
+
// still emitted once the window opens.
|
|
334
|
+
const intervalMs = (0, config_1.getStatusLineEmitMinIntervalSeconds)(cfg) * 1000;
|
|
335
|
+
const now = Date.now();
|
|
336
|
+
if (intervalMs > 0 && prev.lastEmitMs !== undefined && now - prev.lastEmitMs < intervalMs) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
(0, queue_1.submit)(projectDir, sessionId, "send_event", event);
|
|
340
|
+
writeStatuslineState(statePath, { sig, lastEmitMs: now });
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Spawn the chained statusline command, piping our stdin to it and inheriting
|
|
344
|
+
* its stdout (so its output becomes the rendered statusline). On Windows,
|
|
345
|
+
* Claude Code runs statuslines via Git Bash, so a bash command would break
|
|
346
|
+
* under cmd.exe — prefer Git Bash there when available.
|
|
347
|
+
*/
|
|
348
|
+
function runChained(userCmd, stdinPayload) {
|
|
349
|
+
return new Promise((resolve) => {
|
|
350
|
+
let child;
|
|
351
|
+
const bash = process.platform === "win32" ? findGitBash() : undefined;
|
|
352
|
+
try {
|
|
353
|
+
child = bash
|
|
354
|
+
? (0, child_process_1.spawn)(bash, ["-c", userCmd], { stdio: ["pipe", "inherit", "inherit"] })
|
|
355
|
+
: (0, child_process_1.spawn)(userCmd, [], { stdio: ["pipe", "inherit", "inherit"], shell: true });
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
logger_1.logger.debug(`session-status: failed to spawn chained statusline: ${e instanceof Error ? e.message : e}`);
|
|
359
|
+
resolve();
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
child.on("error", (e) => {
|
|
363
|
+
logger_1.logger.debug(`session-status: chained statusline error: ${e.message}`);
|
|
364
|
+
resolve();
|
|
365
|
+
});
|
|
366
|
+
child.on("exit", (code) => {
|
|
367
|
+
// Preserve the chained command's exit code so its render semantics
|
|
368
|
+
// (CC drops stdout on non-zero) match the unwrapped behavior.
|
|
369
|
+
process.exitCode = code ?? 0;
|
|
370
|
+
resolve();
|
|
371
|
+
});
|
|
372
|
+
if (child.stdin) {
|
|
373
|
+
child.stdin.on("error", () => { });
|
|
374
|
+
child.stdin.write(stdinPayload);
|
|
375
|
+
child.stdin.end();
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
/** Common Git Bash install locations on Windows; undefined → fall back to cmd.exe. */
|
|
380
|
+
function findGitBash() {
|
|
381
|
+
const candidates = [
|
|
382
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
383
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
384
|
+
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
385
|
+
];
|
|
386
|
+
for (const c of candidates) {
|
|
387
|
+
if ((0, fs_1.existsSync)(c)) {
|
|
388
|
+
return c;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
/** Minimal default statusline when there is nothing to chain. */
|
|
394
|
+
function buildDefaultLine(input) {
|
|
395
|
+
const model = input.model?.id ?? "?";
|
|
396
|
+
const pct = num(input.context_window?.used_percentage);
|
|
397
|
+
return `[${model}] ${pct}% ctx`;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Statusline entry point. Reads stdin, submits the event (gated, fire-and-
|
|
401
|
+
* forget), then chains the user's original statusline.
|
|
402
|
+
*/
|
|
403
|
+
async function runSessionStatus() {
|
|
404
|
+
let raw;
|
|
405
|
+
try {
|
|
406
|
+
raw = (0, stdin_1.readStdin)();
|
|
407
|
+
}
|
|
408
|
+
catch (e) {
|
|
409
|
+
logger_1.logger.debug(`session-status: failed to read stdin: ${e}`);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
let input;
|
|
413
|
+
try {
|
|
414
|
+
input = JSON.parse(raw);
|
|
415
|
+
}
|
|
416
|
+
catch (e) {
|
|
417
|
+
logger_1.logger.debug(`session-status: failed to parse stdin: ${e}`);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const projectDir = resolveProjectDir(input);
|
|
421
|
+
// 1) Submit our metrics — never blocks/breaks the render.
|
|
422
|
+
await submitSessionStatusEvent(input, projectDir).catch((e) => {
|
|
423
|
+
logger_1.logger.debug(`session-status: submit failed: ${e instanceof Error ? e.message : e}`);
|
|
424
|
+
});
|
|
425
|
+
// 2) Chain the user's original statusline. Primary: SessionStart cache.
|
|
426
|
+
// Fallback: live resolution (cache missing/torn/absent) so a cache miss
|
|
427
|
+
// never makes the user's statusline disappear.
|
|
428
|
+
let chained;
|
|
429
|
+
if (input.session_id) {
|
|
430
|
+
const sessionDir = (0, path_1.join)(projectDir, ".ironbee", "sessions", input.session_id);
|
|
431
|
+
try {
|
|
432
|
+
chained = (0, session_state_1.getChainedStatusLine)(sessionDir);
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
chained = undefined;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (chained === undefined) {
|
|
439
|
+
chained = resolveChainTarget(projectDir);
|
|
440
|
+
}
|
|
441
|
+
if (chained && !isIronbeeStatusLine(chained)) {
|
|
442
|
+
await runChained(chained, raw);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
// 3) Nothing to chain → silent unless renderDefault is on.
|
|
446
|
+
if ((0, config_1.getStatusLineRenderDefault)((0, config_1.loadConfig)(projectDir))) {
|
|
447
|
+
process.stdout.write(buildDefaultLine(input) + "\n");
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=session-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-status.js","sourceRoot":"","sources":["../../../../src/clients/claude/hooks/session-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,32 @@ export declare class ClaudeClient implements IClient {
|
|
|
7
7
|
install(projectDir: string, config?: IronBeeConfig): void;
|
|
8
8
|
uninstall(projectDir: string): void;
|
|
9
9
|
private cleanupArtifacts;
|
|
10
|
+
/**
|
|
11
|
+
* Install the statusline wrapper into `.claude/settings.local.json` (the
|
|
12
|
+
* highest writable layer — deep-merge guarantees our command wins so the
|
|
13
|
+
* wrapper runs, and the gitignored layer leaves any committed/global
|
|
14
|
+
* statusline on disk to chain to). Gated on the session_status feature:
|
|
15
|
+
* when disabled we never touch the user's statusline.
|
|
16
|
+
*
|
|
17
|
+
* If the user already has a (non-ours) statusline in THIS layer, we'd
|
|
18
|
+
* destroy it by overwriting the single command slot — so snapshot the
|
|
19
|
+
* original block first (only on the first install — never clobber an
|
|
20
|
+
* existing snapshot, which represents the true pre-install state).
|
|
21
|
+
*/
|
|
22
|
+
private installStatusLine;
|
|
23
|
+
/**
|
|
24
|
+
* Reverse `installStatusLine`. If a snapshot exists (we'd overwritten the
|
|
25
|
+
* user's local-layer statusline), restore it. Otherwise strip our wrapper
|
|
26
|
+
* so a lower-layer (committed / global) statusline re-emerges via
|
|
27
|
+
* deep-merge. Idempotent.
|
|
28
|
+
*/
|
|
29
|
+
private uninstallStatusLine;
|
|
30
|
+
/** Read the `statusLine` block from a settings file; undefined if absent/malformed. */
|
|
31
|
+
private readStatusLineBlock;
|
|
32
|
+
/** Merge a `statusLine` block into a settings file (preserves other keys). */
|
|
33
|
+
private writeStatusLineBlock;
|
|
34
|
+
/** Remove the `statusLine` key from a settings file; delete the file if it's then empty. */
|
|
35
|
+
private removeStatusLineBlock;
|
|
10
36
|
/**
|
|
11
37
|
* After stripping ironbee hooks + permissions, if `settings.json` is
|
|
12
38
|
* left as a hollow `{ "hooks": {}, "permissions": { "allow": [], "deny": [] } }`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/clients/claude/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/clients/claude/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAelC,OAAO,EAAoG,aAAa,EAA4G,MAAM,kBAAkB,CAAC;AA6H7P,qBAAa,YAAa,YAAW,OAAO;IACxC,SAAgB,IAAI,EAAE,MAAM,CAAY;IAEjC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInC,iBAAiB,IAAI,MAAM;IAI3B,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI;IAsEzD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAK1C,OAAO,CAAC,gBAAgB;IAkCxB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAgB3B,uFAAuF;IACvF,OAAO,CAAC,mBAAmB;IAiC3B,8EAA8E;IAC9E,OAAO,CAAC,oBAAoB;IAkB5B,4FAA4F;IAC5F,OAAO,CAAC,qBAAqB;IAqB7B;;;;;;;;OAQG;IACH,OAAO,CAAC,wBAAwB;IAcnB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IA0KxB,OAAO,CAAC,kBAAkB;IA4B1B,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,gBAAgB;IA6BxB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,cAAc;IAkDtB,OAAO,CAAC,gBAAgB;CAuE3B;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAG1D"}
|