@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.
Files changed (176) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +17 -3
  3. package/dist/assets/banner.txt +1 -1
  4. package/dist/clients/claude/hooks/session-start.d.ts.map +1 -1
  5. package/dist/clients/claude/hooks/session-start.js +7 -0
  6. package/dist/clients/claude/hooks/session-start.js.map +1 -1
  7. package/dist/clients/claude/hooks/session-status.d.ts +129 -0
  8. package/dist/clients/claude/hooks/session-status.d.ts.map +1 -0
  9. package/dist/clients/claude/hooks/session-status.js +450 -0
  10. package/dist/clients/claude/hooks/session-status.js.map +1 -0
  11. package/dist/clients/claude/index.d.ts +26 -0
  12. package/dist/clients/claude/index.d.ts.map +1 -1
  13. package/dist/clients/claude/index.js +151 -0
  14. package/dist/clients/claude/index.js.map +1 -1
  15. package/dist/clients/cursor/index.d.ts.map +1 -1
  16. package/dist/clients/cursor/index.js +6 -0
  17. package/dist/clients/cursor/index.js.map +1 -1
  18. package/dist/clients/registry.d.ts +8 -9
  19. package/dist/clients/registry.d.ts.map +1 -1
  20. package/dist/clients/registry.js +13 -11
  21. package/dist/clients/registry.js.map +1 -1
  22. package/dist/commands/config.d.ts +5 -4
  23. package/dist/commands/config.d.ts.map +1 -1
  24. package/dist/commands/config.js +10 -4
  25. package/dist/commands/config.js.map +1 -1
  26. package/dist/commands/hook.js +44 -0
  27. package/dist/commands/hook.js.map +1 -1
  28. package/dist/commands/install.d.ts.map +1 -1
  29. package/dist/commands/install.js +4 -5
  30. package/dist/commands/install.js.map +1 -1
  31. package/dist/commands/register.d.ts +0 -1
  32. package/dist/commands/register.d.ts.map +1 -1
  33. package/dist/commands/register.js +7 -27
  34. package/dist/commands/register.js.map +1 -1
  35. package/dist/commands/statusline-toggle.d.ts +29 -0
  36. package/dist/commands/statusline-toggle.d.ts.map +1 -0
  37. package/dist/commands/statusline-toggle.js +114 -0
  38. package/dist/commands/statusline-toggle.js.map +1 -0
  39. package/dist/commands/statusline.d.ts +24 -0
  40. package/dist/commands/statusline.d.ts.map +1 -0
  41. package/dist/commands/statusline.js +79 -0
  42. package/dist/commands/statusline.js.map +1 -0
  43. package/dist/commands/uninstall.d.ts +2 -3
  44. package/dist/commands/uninstall.d.ts.map +1 -1
  45. package/dist/commands/uninstall.js +3 -4
  46. package/dist/commands/uninstall.js.map +1 -1
  47. package/dist/commands/unregister.d.ts +0 -1
  48. package/dist/commands/unregister.d.ts.map +1 -1
  49. package/dist/commands/unregister.js +3 -24
  50. package/dist/commands/unregister.js.map +1 -1
  51. package/dist/hooks/core/session-state.d.ts +25 -0
  52. package/dist/hooks/core/session-state.d.ts.map +1 -1
  53. package/dist/hooks/core/session-state.js +49 -1
  54. package/dist/hooks/core/session-state.js.map +1 -1
  55. package/dist/index.js +35 -15
  56. package/dist/index.js.map +1 -1
  57. package/dist/lib/config.d.ts +64 -0
  58. package/dist/lib/config.d.ts.map +1 -1
  59. package/dist/lib/config.js +48 -0
  60. package/dist/lib/config.js.map +1 -1
  61. package/dist/lib/event.d.ts +60 -0
  62. package/dist/lib/event.d.ts.map +1 -1
  63. package/dist/lib/event.js +1 -0
  64. package/dist/lib/event.js.map +1 -1
  65. package/dist/lib/fs-prune.d.ts +20 -0
  66. package/dist/lib/fs-prune.d.ts.map +1 -0
  67. package/dist/lib/fs-prune.js +72 -0
  68. package/dist/lib/fs-prune.js.map +1 -0
  69. package/dist/lib/gitignore.d.ts.map +1 -1
  70. package/dist/lib/gitignore.js +11 -0
  71. package/dist/lib/gitignore.js.map +1 -1
  72. package/dist/lib/install-snapshots.d.ts +70 -0
  73. package/dist/lib/install-snapshots.d.ts.map +1 -0
  74. package/dist/lib/install-snapshots.js +168 -0
  75. package/dist/lib/install-snapshots.js.map +1 -0
  76. package/dist/lib/projects-registry.d.ts +6 -13
  77. package/dist/lib/projects-registry.d.ts.map +1 -1
  78. package/dist/lib/projects-registry.js +11 -46
  79. package/dist/lib/projects-registry.js.map +1 -1
  80. package/dist/tui/command.d.ts +18 -0
  81. package/dist/tui/command.d.ts.map +1 -0
  82. package/dist/tui/command.js +87 -0
  83. package/dist/tui/command.js.map +1 -0
  84. package/dist/tui/config/area.d.ts +6 -0
  85. package/dist/tui/config/area.d.ts.map +1 -0
  86. package/dist/tui/config/area.js +16 -0
  87. package/dist/tui/config/area.js.map +1 -0
  88. package/dist/tui/config/docs.d.ts +28 -0
  89. package/dist/tui/config/docs.d.ts.map +1 -0
  90. package/dist/tui/config/docs.js +68 -0
  91. package/dist/tui/config/docs.js.map +1 -0
  92. package/dist/tui/config/edit.d.ts +36 -0
  93. package/dist/tui/config/edit.d.ts.map +1 -0
  94. package/dist/tui/config/edit.js +69 -0
  95. package/dist/tui/config/edit.js.map +1 -0
  96. package/dist/tui/config/introspect.d.ts +58 -0
  97. package/dist/tui/config/introspect.d.ts.map +1 -0
  98. package/dist/tui/config/introspect.js +93 -0
  99. package/dist/tui/config/introspect.js.map +1 -0
  100. package/dist/tui/config/schema.d.ts +81 -0
  101. package/dist/tui/config/schema.d.ts.map +1 -0
  102. package/dist/tui/config/schema.js +534 -0
  103. package/dist/tui/config/schema.js.map +1 -0
  104. package/dist/tui/config/tree.d.ts +39 -0
  105. package/dist/tui/config/tree.d.ts.map +1 -0
  106. package/dist/tui/config/tree.js +59 -0
  107. package/dist/tui/config/tree.js.map +1 -0
  108. package/dist/tui/config/value.d.ts +75 -0
  109. package/dist/tui/config/value.d.ts.map +1 -0
  110. package/dist/tui/config/value.js +228 -0
  111. package/dist/tui/config/value.js.map +1 -0
  112. package/dist/tui/config/view.d.ts +13 -0
  113. package/dist/tui/config/view.d.ts.map +1 -0
  114. package/dist/tui/config/view.js +423 -0
  115. package/dist/tui/config/view.js.map +1 -0
  116. package/dist/tui/import/area.d.ts +11 -0
  117. package/dist/tui/import/area.d.ts.map +1 -0
  118. package/dist/tui/import/area.js +202 -0
  119. package/dist/tui/import/area.js.map +1 -0
  120. package/dist/tui/index.d.ts +9 -0
  121. package/dist/tui/index.d.ts.map +1 -0
  122. package/dist/tui/index.js +14 -0
  123. package/dist/tui/index.js.map +1 -0
  124. package/dist/tui/platforms/area.d.ts +12 -0
  125. package/dist/tui/platforms/area.d.ts.map +1 -0
  126. package/dist/tui/platforms/area.js +228 -0
  127. package/dist/tui/platforms/area.js.map +1 -0
  128. package/dist/tui/projects/area.d.ts +26 -0
  129. package/dist/tui/projects/area.d.ts.map +1 -0
  130. package/dist/tui/projects/area.js +588 -0
  131. package/dist/tui/projects/area.js.map +1 -0
  132. package/dist/tui/queue/area.d.ts +11 -0
  133. package/dist/tui/queue/area.d.ts.map +1 -0
  134. package/dist/tui/queue/area.js +338 -0
  135. package/dist/tui/queue/area.js.map +1 -0
  136. package/dist/tui/queue/read.d.ts +49 -0
  137. package/dist/tui/queue/read.d.ts.map +1 -0
  138. package/dist/tui/queue/read.js +261 -0
  139. package/dist/tui/queue/read.js.map +1 -0
  140. package/dist/tui/sessions/area.d.ts +10 -0
  141. package/dist/tui/sessions/area.d.ts.map +1 -0
  142. package/dist/tui/sessions/area.js +266 -0
  143. package/dist/tui/sessions/area.js.map +1 -0
  144. package/dist/tui/sessions/read.d.ts +79 -0
  145. package/dist/tui/sessions/read.d.ts.map +1 -0
  146. package/dist/tui/sessions/read.js +202 -0
  147. package/dist/tui/sessions/read.js.map +1 -0
  148. package/dist/tui/shell/area.d.ts +47 -0
  149. package/dist/tui/shell/area.d.ts.map +1 -0
  150. package/dist/tui/shell/area.js +13 -0
  151. package/dist/tui/shell/area.js.map +1 -0
  152. package/dist/tui/shell/frame.d.ts +23 -0
  153. package/dist/tui/shell/frame.d.ts.map +1 -0
  154. package/dist/tui/shell/frame.js +91 -0
  155. package/dist/tui/shell/frame.js.map +1 -0
  156. package/dist/tui/shell/registry.d.ts +11 -0
  157. package/dist/tui/shell/registry.d.ts.map +1 -0
  158. package/dist/tui/shell/registry.js +29 -0
  159. package/dist/tui/shell/registry.js.map +1 -0
  160. package/dist/tui/shell/rerender.d.ts +16 -0
  161. package/dist/tui/shell/rerender.d.ts.map +1 -0
  162. package/dist/tui/shell/rerender.js +34 -0
  163. package/dist/tui/shell/rerender.js.map +1 -0
  164. package/dist/tui/shell/session.d.ts +75 -0
  165. package/dist/tui/shell/session.d.ts.map +1 -0
  166. package/dist/tui/shell/session.js +333 -0
  167. package/dist/tui/shell/session.js.map +1 -0
  168. package/dist/tui/shell/shell.d.ts +16 -0
  169. package/dist/tui/shell/shell.d.ts.map +1 -0
  170. package/dist/tui/shell/shell.js +213 -0
  171. package/dist/tui/shell/shell.js.map +1 -0
  172. package/dist/tui/shell/util.d.ts +18 -0
  173. package/dist/tui/shell/util.d.ts.map +1 -0
  174. package/dist/tui/shell/util.js +31 -0
  175. package/dist/tui/shell/util.js.map +1 -0
  176. 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;AAclC,OAAO,EAAoG,aAAa,EAAsD,MAAM,kBAAkB,CAAC;AAyHvM,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;IAgEzD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAK1C,OAAO,CAAC,gBAAgB;IA0BxB;;;;;;;;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"}
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"}