claude-scope 0.6.2 → 0.6.9
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/claude-scope.cjs +1951 -991
- package/package.json +2 -2
package/dist/claude-scope.cjs
CHANGED
|
@@ -35,73 +35,14 @@ __export(index_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
|
-
// src/
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
* Register a widget
|
|
43
|
-
*/
|
|
44
|
-
async register(widget, context) {
|
|
45
|
-
if (this.widgets.has(widget.id)) {
|
|
46
|
-
throw new Error(`Widget with id '${widget.id}' already registered`);
|
|
47
|
-
}
|
|
48
|
-
if (context) {
|
|
49
|
-
await widget.initialize(context);
|
|
50
|
-
}
|
|
51
|
-
this.widgets.set(widget.id, widget);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Unregister a widget
|
|
55
|
-
*/
|
|
56
|
-
async unregister(id) {
|
|
57
|
-
const widget = this.widgets.get(id);
|
|
58
|
-
if (!widget) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
if (widget.cleanup) {
|
|
63
|
-
await widget.cleanup();
|
|
64
|
-
}
|
|
65
|
-
} finally {
|
|
66
|
-
this.widgets.delete(id);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get a widget by id
|
|
71
|
-
*/
|
|
72
|
-
get(id) {
|
|
73
|
-
return this.widgets.get(id);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Check if widget is registered
|
|
77
|
-
*/
|
|
78
|
-
has(id) {
|
|
79
|
-
return this.widgets.has(id);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Get all registered widgets
|
|
83
|
-
*/
|
|
84
|
-
getAll() {
|
|
85
|
-
return Array.from(this.widgets.values());
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Get only enabled widgets
|
|
89
|
-
*/
|
|
90
|
-
getEnabledWidgets() {
|
|
91
|
-
return this.getAll().filter((w) => w.isEnabled());
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Clear all widgets
|
|
95
|
-
*/
|
|
96
|
-
async clear() {
|
|
97
|
-
for (const widget of this.widgets.values()) {
|
|
98
|
-
if (widget.cleanup) {
|
|
99
|
-
await widget.cleanup();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
this.widgets.clear();
|
|
103
|
-
}
|
|
38
|
+
// src/config/widget-flags.ts
|
|
39
|
+
var WIDGET_FLAGS = {
|
|
40
|
+
activeTools: true,
|
|
41
|
+
cacheMetrics: true
|
|
104
42
|
};
|
|
43
|
+
function isWidgetEnabled(name) {
|
|
44
|
+
return WIDGET_FLAGS[name] ?? true;
|
|
45
|
+
}
|
|
105
46
|
|
|
106
47
|
// src/constants.ts
|
|
107
48
|
var TIME = {
|
|
@@ -207,120 +148,395 @@ var Renderer = class {
|
|
|
207
148
|
}
|
|
208
149
|
};
|
|
209
150
|
|
|
210
|
-
// src/core/widget-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
var import_node_child_process = require("node:child_process");
|
|
223
|
-
var import_node_util = require("node:util");
|
|
224
|
-
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
225
|
-
var NativeGit = class {
|
|
226
|
-
cwd;
|
|
227
|
-
constructor(cwd) {
|
|
228
|
-
this.cwd = cwd;
|
|
229
|
-
}
|
|
230
|
-
async status() {
|
|
231
|
-
try {
|
|
232
|
-
const { stdout } = await execFileAsync("git", ["status", "--branch", "--short"], {
|
|
233
|
-
cwd: this.cwd
|
|
234
|
-
});
|
|
235
|
-
const match = stdout.match(/^##\s+(\S+)/m);
|
|
236
|
-
const current = match ? match[1] : null;
|
|
237
|
-
return { current };
|
|
238
|
-
} catch {
|
|
239
|
-
return { current: null };
|
|
151
|
+
// src/core/widget-registry.ts
|
|
152
|
+
var WidgetRegistry = class {
|
|
153
|
+
widgets = /* @__PURE__ */ new Map();
|
|
154
|
+
/**
|
|
155
|
+
* Register a widget
|
|
156
|
+
*/
|
|
157
|
+
async register(widget, context) {
|
|
158
|
+
if (this.widgets.has(widget.id)) {
|
|
159
|
+
throw new Error(`Widget with id '${widget.id}' already registered`);
|
|
160
|
+
}
|
|
161
|
+
if (context) {
|
|
162
|
+
await widget.initialize(context);
|
|
240
163
|
}
|
|
164
|
+
this.widgets.set(widget.id, widget);
|
|
241
165
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Unregister a widget
|
|
168
|
+
*/
|
|
169
|
+
async unregister(id) {
|
|
170
|
+
const widget = this.widgets.get(id);
|
|
171
|
+
if (!widget) {
|
|
172
|
+
return;
|
|
246
173
|
}
|
|
247
174
|
try {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const deletionMatch = stdout.match(/(\d+)\s+deletion/);
|
|
254
|
-
const fileCount = fileMatch ? parseInt(fileMatch[1], 10) : 0;
|
|
255
|
-
const insertions = insertionMatch ? parseInt(insertionMatch[1], 10) : 0;
|
|
256
|
-
const deletions = deletionMatch ? parseInt(deletionMatch[1], 10) : 0;
|
|
257
|
-
const files = insertions > 0 || deletions > 0 ? [{ file: "(total)", insertions, deletions }] : [];
|
|
258
|
-
return { fileCount, files };
|
|
259
|
-
} catch {
|
|
260
|
-
return { fileCount: 0, files: [] };
|
|
175
|
+
if (widget.cleanup) {
|
|
176
|
+
await widget.cleanup();
|
|
177
|
+
}
|
|
178
|
+
} finally {
|
|
179
|
+
this.widgets.delete(id);
|
|
261
180
|
}
|
|
262
181
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Get a widget by id
|
|
184
|
+
*/
|
|
185
|
+
get(id) {
|
|
186
|
+
return this.widgets.get(id);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if widget is registered
|
|
190
|
+
*/
|
|
191
|
+
has(id) {
|
|
192
|
+
return this.widgets.has(id);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get all registered widgets
|
|
196
|
+
*/
|
|
197
|
+
getAll() {
|
|
198
|
+
return Array.from(this.widgets.values());
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get only enabled widgets
|
|
202
|
+
*/
|
|
203
|
+
getEnabledWidgets() {
|
|
204
|
+
return this.getAll().filter((w) => w.isEnabled());
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Clear all widgets
|
|
208
|
+
*/
|
|
209
|
+
async clear() {
|
|
210
|
+
for (const widget of this.widgets.values()) {
|
|
211
|
+
if (widget.cleanup) {
|
|
212
|
+
await widget.cleanup();
|
|
213
|
+
}
|
|
271
214
|
}
|
|
215
|
+
this.widgets.clear();
|
|
272
216
|
}
|
|
273
217
|
};
|
|
274
|
-
function createGit(cwd) {
|
|
275
|
-
return new NativeGit(cwd);
|
|
276
|
-
}
|
|
277
218
|
|
|
278
|
-
// src/
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
var gray = "\x1B[90m";
|
|
282
|
-
var lightGray = "\x1B[37m";
|
|
283
|
-
var bold = "\x1B[1m";
|
|
284
|
-
function colorize(text, color) {
|
|
285
|
-
return `${color}${text}${reset}`;
|
|
219
|
+
// src/validation/result.ts
|
|
220
|
+
function success(data) {
|
|
221
|
+
return { success: true, data };
|
|
286
222
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
function rgb(r, g, b) {
|
|
290
|
-
return `\x1B[38;2;${r};${g};${b}m`;
|
|
223
|
+
function failure(path2, message, value) {
|
|
224
|
+
return { success: false, error: { path: path2, message, value } };
|
|
291
225
|
}
|
|
292
|
-
function
|
|
226
|
+
function formatError(error) {
|
|
227
|
+
const path2 = error.path.length > 0 ? error.path.join(".") : "root";
|
|
228
|
+
return `${path2}: ${error.message}`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/validation/combinators.ts
|
|
232
|
+
function object(shape) {
|
|
293
233
|
return {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
234
|
+
validate(value) {
|
|
235
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
236
|
+
return failure([], "Expected object", value);
|
|
237
|
+
}
|
|
238
|
+
const result = {};
|
|
239
|
+
for (const [key, validator] of Object.entries(shape)) {
|
|
240
|
+
const fieldValue = value[key];
|
|
241
|
+
const validationResult = validator.validate(fieldValue);
|
|
242
|
+
if (!validationResult.success) {
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
error: { ...validationResult.error, path: [key, ...validationResult.error.path] }
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
result[key] = validationResult.data;
|
|
249
|
+
}
|
|
250
|
+
return success(result);
|
|
251
|
+
}
|
|
298
252
|
};
|
|
299
253
|
}
|
|
300
|
-
function
|
|
254
|
+
function optional(validator) {
|
|
301
255
|
return {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
256
|
+
validate(value) {
|
|
257
|
+
if (value === void 0) return success(void 0);
|
|
258
|
+
return validator.validate(value);
|
|
259
|
+
}
|
|
306
260
|
};
|
|
307
261
|
}
|
|
308
|
-
function
|
|
309
|
-
const base = createBaseColors({
|
|
310
|
-
modelColor: params.model,
|
|
311
|
-
durationColor: params.duration,
|
|
312
|
-
accentColor: params.accent
|
|
313
|
-
});
|
|
314
|
-
const semantic = createSemanticColors({
|
|
315
|
-
contextLow: params.contextLow,
|
|
316
|
-
contextMedium: params.contextMedium,
|
|
317
|
-
contextHigh: params.contextHigh,
|
|
318
|
-
branchColor: params.branch
|
|
319
|
-
});
|
|
262
|
+
function nullable(validator) {
|
|
320
263
|
return {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
264
|
+
validate(value) {
|
|
265
|
+
if (value === null) return success(null);
|
|
266
|
+
return validator.validate(value);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/validation/validators.ts
|
|
272
|
+
function string() {
|
|
273
|
+
return {
|
|
274
|
+
validate(value) {
|
|
275
|
+
if (typeof value === "string") return success(value);
|
|
276
|
+
return failure([], "Expected string", value);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function number() {
|
|
281
|
+
return {
|
|
282
|
+
validate(value) {
|
|
283
|
+
if (typeof value === "number" && !Number.isNaN(value)) return success(value);
|
|
284
|
+
return failure([], "Expected number", value);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function literal(expected) {
|
|
289
|
+
return {
|
|
290
|
+
validate(value) {
|
|
291
|
+
if (value === expected) return success(expected);
|
|
292
|
+
return failure([], `Expected '${expected}'`, value);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/schemas/stdin-schema.ts
|
|
298
|
+
var ContextUsageSchema = object({
|
|
299
|
+
input_tokens: number(),
|
|
300
|
+
output_tokens: number(),
|
|
301
|
+
cache_creation_input_tokens: number(),
|
|
302
|
+
cache_read_input_tokens: number()
|
|
303
|
+
});
|
|
304
|
+
var CostInfoSchema = object({
|
|
305
|
+
total_cost_usd: optional(number()),
|
|
306
|
+
total_duration_ms: optional(number()),
|
|
307
|
+
total_api_duration_ms: optional(number()),
|
|
308
|
+
total_lines_added: optional(number()),
|
|
309
|
+
total_lines_removed: optional(number())
|
|
310
|
+
});
|
|
311
|
+
var ContextWindowSchema = object({
|
|
312
|
+
total_input_tokens: number(),
|
|
313
|
+
total_output_tokens: number(),
|
|
314
|
+
context_window_size: number(),
|
|
315
|
+
current_usage: nullable(ContextUsageSchema)
|
|
316
|
+
});
|
|
317
|
+
var ModelInfoSchema = object({
|
|
318
|
+
id: string(),
|
|
319
|
+
display_name: string()
|
|
320
|
+
});
|
|
321
|
+
var WorkspaceSchema = object({
|
|
322
|
+
current_dir: string(),
|
|
323
|
+
project_dir: string()
|
|
324
|
+
});
|
|
325
|
+
var OutputStyleSchema = object({
|
|
326
|
+
name: string()
|
|
327
|
+
});
|
|
328
|
+
var StdinDataSchema = object({
|
|
329
|
+
hook_event_name: optional(literal("Status")),
|
|
330
|
+
session_id: string(),
|
|
331
|
+
transcript_path: string(),
|
|
332
|
+
cwd: string(),
|
|
333
|
+
model: ModelInfoSchema,
|
|
334
|
+
workspace: WorkspaceSchema,
|
|
335
|
+
version: string(),
|
|
336
|
+
output_style: OutputStyleSchema,
|
|
337
|
+
cost: optional(CostInfoSchema),
|
|
338
|
+
context_window: ContextWindowSchema
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// src/data/stdin-provider.ts
|
|
342
|
+
var StdinParseError = class extends Error {
|
|
343
|
+
constructor(message) {
|
|
344
|
+
super(message);
|
|
345
|
+
this.name = "StdinParseError";
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var StdinValidationError = class extends Error {
|
|
349
|
+
constructor(message) {
|
|
350
|
+
super(message);
|
|
351
|
+
this.name = "StdinValidationError";
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
var StdinProvider = class {
|
|
355
|
+
/**
|
|
356
|
+
* Parse and validate JSON string from stdin
|
|
357
|
+
* @param input JSON string to parse
|
|
358
|
+
* @returns Validated StdinData object
|
|
359
|
+
* @throws StdinParseError if JSON is malformed
|
|
360
|
+
* @throws StdinValidationError if data doesn't match schema
|
|
361
|
+
*/
|
|
362
|
+
async parse(input) {
|
|
363
|
+
if (!input || input.trim().length === 0) {
|
|
364
|
+
throw new StdinParseError("stdin data is empty");
|
|
365
|
+
}
|
|
366
|
+
let data;
|
|
367
|
+
try {
|
|
368
|
+
data = JSON.parse(input);
|
|
369
|
+
} catch (error) {
|
|
370
|
+
throw new StdinParseError(`Invalid JSON: ${error.message}`);
|
|
371
|
+
}
|
|
372
|
+
const result = StdinDataSchema.validate(data);
|
|
373
|
+
if (!result.success) {
|
|
374
|
+
throw new StdinValidationError(`Validation failed: ${formatError(result.error)}`);
|
|
375
|
+
}
|
|
376
|
+
return result.data;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Safe parse that returns result instead of throwing
|
|
380
|
+
* Useful for testing and optional validation
|
|
381
|
+
* @param input JSON string to parse
|
|
382
|
+
* @returns Result object with success flag
|
|
383
|
+
*/
|
|
384
|
+
async safeParse(input) {
|
|
385
|
+
try {
|
|
386
|
+
const data = await this.parse(input);
|
|
387
|
+
return { success: true, data };
|
|
388
|
+
} catch (error) {
|
|
389
|
+
return { success: false, error: error.message };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/providers/transcript-provider.ts
|
|
395
|
+
var import_fs = require("fs");
|
|
396
|
+
var import_readline = require("readline");
|
|
397
|
+
var TranscriptProvider = class {
|
|
398
|
+
MAX_TOOLS = 20;
|
|
399
|
+
/**
|
|
400
|
+
* Parse tools from a JSONL transcript file
|
|
401
|
+
* @param transcriptPath Path to the transcript file
|
|
402
|
+
* @returns Array of tool entries, limited to last 20
|
|
403
|
+
*/
|
|
404
|
+
async parseTools(transcriptPath) {
|
|
405
|
+
if (!(0, import_fs.existsSync)(transcriptPath)) {
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
409
|
+
try {
|
|
410
|
+
const fileStream = (0, import_fs.createReadStream)(transcriptPath, { encoding: "utf-8" });
|
|
411
|
+
const rl = (0, import_readline.createInterface)({
|
|
412
|
+
input: fileStream,
|
|
413
|
+
crlfDelay: Infinity
|
|
414
|
+
});
|
|
415
|
+
for await (const line of rl) {
|
|
416
|
+
if (!line.trim()) continue;
|
|
417
|
+
try {
|
|
418
|
+
const entry = JSON.parse(line);
|
|
419
|
+
this.processLine(entry, toolMap);
|
|
420
|
+
} catch {
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const tools = Array.from(toolMap.values());
|
|
424
|
+
return tools.slice(-this.MAX_TOOLS);
|
|
425
|
+
} catch {
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Process a single transcript line and update tool map
|
|
431
|
+
*/
|
|
432
|
+
processLine(line, toolMap) {
|
|
433
|
+
const blocks = line.message?.content ?? [];
|
|
434
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
435
|
+
for (const block of blocks) {
|
|
436
|
+
if (block.type === "tool_use" && block.id && block.name) {
|
|
437
|
+
const tool = {
|
|
438
|
+
id: block.id,
|
|
439
|
+
name: block.name,
|
|
440
|
+
target: this.extractTarget(block.name, block.input),
|
|
441
|
+
status: "running",
|
|
442
|
+
startTime: timestamp
|
|
443
|
+
};
|
|
444
|
+
toolMap.set(block.id, tool);
|
|
445
|
+
}
|
|
446
|
+
if (block.type === "tool_result" && block.tool_use_id) {
|
|
447
|
+
const existing = toolMap.get(block.tool_use_id);
|
|
448
|
+
if (existing) {
|
|
449
|
+
existing.status = block.is_error ? "error" : "completed";
|
|
450
|
+
existing.endTime = timestamp;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Extract target from tool input based on tool type
|
|
457
|
+
*/
|
|
458
|
+
extractTarget(toolName, input) {
|
|
459
|
+
if (!input) return void 0;
|
|
460
|
+
switch (toolName) {
|
|
461
|
+
case "Read":
|
|
462
|
+
case "Write":
|
|
463
|
+
case "Edit":
|
|
464
|
+
return this.asString(input.file_path ?? input.path);
|
|
465
|
+
case "Glob":
|
|
466
|
+
return this.asString(input.pattern);
|
|
467
|
+
case "Grep":
|
|
468
|
+
return this.asString(input.pattern);
|
|
469
|
+
case "Bash": {
|
|
470
|
+
const cmd = this.asString(input.command);
|
|
471
|
+
return cmd ? this.truncateCommand(cmd) : void 0;
|
|
472
|
+
}
|
|
473
|
+
default:
|
|
474
|
+
return void 0;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Safely convert value to string
|
|
479
|
+
*/
|
|
480
|
+
asString(value) {
|
|
481
|
+
if (typeof value === "string") return value;
|
|
482
|
+
if (typeof value === "number") return String(value);
|
|
483
|
+
return void 0;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Truncate long commands to 30 chars
|
|
487
|
+
*/
|
|
488
|
+
truncateCommand(cmd) {
|
|
489
|
+
if (cmd.length <= 30) return cmd;
|
|
490
|
+
return cmd.slice(0, 30) + "...";
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// src/ui/utils/colors.ts
|
|
495
|
+
var reset = "\x1B[0m";
|
|
496
|
+
var red = "\x1B[31m";
|
|
497
|
+
var gray = "\x1B[90m";
|
|
498
|
+
var lightGray = "\x1B[37m";
|
|
499
|
+
var bold = "\x1B[1m";
|
|
500
|
+
function colorize(text, color) {
|
|
501
|
+
return `${color}${text}${reset}`;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/ui/theme/helpers.ts
|
|
505
|
+
function rgb(r, g, b) {
|
|
506
|
+
return `\x1B[38;2;${r};${g};${b}m`;
|
|
507
|
+
}
|
|
508
|
+
function createBaseColors(params) {
|
|
509
|
+
return {
|
|
510
|
+
text: params.modelColor,
|
|
511
|
+
muted: params.durationColor,
|
|
512
|
+
accent: params.accentColor,
|
|
513
|
+
border: params.durationColor
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function createSemanticColors(params) {
|
|
517
|
+
return {
|
|
518
|
+
success: params.contextLow,
|
|
519
|
+
warning: params.contextMedium,
|
|
520
|
+
error: params.contextHigh,
|
|
521
|
+
info: params.branchColor
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function createThemeColors(params) {
|
|
525
|
+
const base = createBaseColors({
|
|
526
|
+
modelColor: params.model,
|
|
527
|
+
durationColor: params.duration,
|
|
528
|
+
accentColor: params.accent
|
|
529
|
+
});
|
|
530
|
+
const semantic = createSemanticColors({
|
|
531
|
+
contextLow: params.contextLow,
|
|
532
|
+
contextMedium: params.contextMedium,
|
|
533
|
+
contextHigh: params.contextHigh,
|
|
534
|
+
branchColor: params.branch
|
|
535
|
+
});
|
|
536
|
+
return {
|
|
537
|
+
base,
|
|
538
|
+
semantic,
|
|
539
|
+
git: {
|
|
324
540
|
branch: params.branch,
|
|
325
541
|
changes: params.changes
|
|
326
542
|
},
|
|
@@ -350,6 +566,21 @@ function createThemeColors(params) {
|
|
|
350
566
|
participating: params.model,
|
|
351
567
|
nonParticipating: params.duration,
|
|
352
568
|
result: params.accent
|
|
569
|
+
},
|
|
570
|
+
cache: {
|
|
571
|
+
high: params.cacheHigh,
|
|
572
|
+
medium: params.cacheMedium,
|
|
573
|
+
low: params.cacheLow,
|
|
574
|
+
read: params.cacheRead,
|
|
575
|
+
write: params.cacheWrite
|
|
576
|
+
},
|
|
577
|
+
tools: {
|
|
578
|
+
running: params.toolsRunning,
|
|
579
|
+
completed: params.toolsCompleted,
|
|
580
|
+
error: params.toolsError,
|
|
581
|
+
name: params.toolsName,
|
|
582
|
+
target: params.toolsTarget,
|
|
583
|
+
count: params.toolsCount
|
|
353
584
|
}
|
|
354
585
|
};
|
|
355
586
|
}
|
|
@@ -369,7 +600,18 @@ var GRAY_THEME = {
|
|
|
369
600
|
cost: gray,
|
|
370
601
|
model: gray,
|
|
371
602
|
duration: gray,
|
|
372
|
-
accent: gray
|
|
603
|
+
accent: gray,
|
|
604
|
+
cacheHigh: gray,
|
|
605
|
+
cacheMedium: gray,
|
|
606
|
+
cacheLow: gray,
|
|
607
|
+
cacheRead: gray,
|
|
608
|
+
cacheWrite: gray,
|
|
609
|
+
toolsRunning: gray,
|
|
610
|
+
toolsCompleted: gray,
|
|
611
|
+
toolsError: gray,
|
|
612
|
+
toolsName: gray,
|
|
613
|
+
toolsTarget: gray,
|
|
614
|
+
toolsCount: gray
|
|
373
615
|
})
|
|
374
616
|
};
|
|
375
617
|
|
|
@@ -398,8 +640,30 @@ var CATPPUCCIN_MOCHA_THEME = {
|
|
|
398
640
|
// Mauve
|
|
399
641
|
duration: rgb(147, 153, 178),
|
|
400
642
|
// Text gray
|
|
401
|
-
accent: rgb(243, 139, 168)
|
|
643
|
+
accent: rgb(243, 139, 168),
|
|
402
644
|
// Pink
|
|
645
|
+
cacheHigh: rgb(166, 227, 161),
|
|
646
|
+
// Green
|
|
647
|
+
cacheMedium: rgb(238, 212, 159),
|
|
648
|
+
// Yellow
|
|
649
|
+
cacheLow: rgb(243, 139, 168),
|
|
650
|
+
// Red
|
|
651
|
+
cacheRead: rgb(137, 180, 250),
|
|
652
|
+
// Blue
|
|
653
|
+
cacheWrite: rgb(203, 166, 247),
|
|
654
|
+
// Mauve
|
|
655
|
+
toolsRunning: rgb(238, 212, 159),
|
|
656
|
+
// Yellow
|
|
657
|
+
toolsCompleted: rgb(166, 227, 161),
|
|
658
|
+
// Green
|
|
659
|
+
toolsError: rgb(243, 139, 168),
|
|
660
|
+
// Red
|
|
661
|
+
toolsName: rgb(137, 180, 250),
|
|
662
|
+
// Blue
|
|
663
|
+
toolsTarget: rgb(147, 153, 178),
|
|
664
|
+
// Gray
|
|
665
|
+
toolsCount: rgb(203, 166, 247)
|
|
666
|
+
// Mauve
|
|
403
667
|
})
|
|
404
668
|
};
|
|
405
669
|
|
|
@@ -428,8 +692,30 @@ var CYBERPUNK_NEON_THEME = {
|
|
|
428
692
|
// Purple neon
|
|
429
693
|
duration: rgb(0, 191, 255),
|
|
430
694
|
// Cyan neon
|
|
431
|
-
accent: rgb(255, 0, 122)
|
|
695
|
+
accent: rgb(255, 0, 122),
|
|
696
|
+
// Magenta neon
|
|
697
|
+
cacheHigh: rgb(0, 255, 122),
|
|
698
|
+
// Green neon
|
|
699
|
+
cacheMedium: rgb(255, 214, 0),
|
|
700
|
+
// Yellow neon
|
|
701
|
+
cacheLow: rgb(255, 0, 122),
|
|
702
|
+
// Magenta neon
|
|
703
|
+
cacheRead: rgb(0, 191, 255),
|
|
704
|
+
// Cyan neon
|
|
705
|
+
cacheWrite: rgb(140, 27, 255),
|
|
706
|
+
// Purple neon
|
|
707
|
+
toolsRunning: rgb(255, 214, 0),
|
|
708
|
+
// Yellow neon
|
|
709
|
+
toolsCompleted: rgb(0, 255, 122),
|
|
710
|
+
// Green neon
|
|
711
|
+
toolsError: rgb(255, 0, 122),
|
|
432
712
|
// Magenta neon
|
|
713
|
+
toolsName: rgb(0, 191, 255),
|
|
714
|
+
// Cyan neon
|
|
715
|
+
toolsTarget: rgb(140, 27, 255),
|
|
716
|
+
// Purple neon
|
|
717
|
+
toolsCount: rgb(255, 111, 97)
|
|
718
|
+
// Orange neon
|
|
433
719
|
})
|
|
434
720
|
};
|
|
435
721
|
|
|
@@ -458,7 +744,29 @@ var DRACULA_THEME = {
|
|
|
458
744
|
// Comment gray
|
|
459
745
|
duration: rgb(68, 71, 90),
|
|
460
746
|
// Selection gray
|
|
461
|
-
accent: rgb(189, 147, 249)
|
|
747
|
+
accent: rgb(189, 147, 249),
|
|
748
|
+
// Purple
|
|
749
|
+
cacheHigh: rgb(80, 250, 123),
|
|
750
|
+
// Green
|
|
751
|
+
cacheMedium: rgb(241, 250, 140),
|
|
752
|
+
// Yellow
|
|
753
|
+
cacheLow: rgb(255, 85, 85),
|
|
754
|
+
// Red
|
|
755
|
+
cacheRead: rgb(139, 233, 253),
|
|
756
|
+
// Cyan
|
|
757
|
+
cacheWrite: rgb(189, 147, 249),
|
|
758
|
+
// Purple
|
|
759
|
+
toolsRunning: rgb(241, 250, 140),
|
|
760
|
+
// Yellow
|
|
761
|
+
toolsCompleted: rgb(80, 250, 123),
|
|
762
|
+
// Green
|
|
763
|
+
toolsError: rgb(255, 85, 85),
|
|
764
|
+
// Red
|
|
765
|
+
toolsName: rgb(139, 233, 253),
|
|
766
|
+
// Cyan
|
|
767
|
+
toolsTarget: rgb(98, 114, 164),
|
|
768
|
+
// Gray
|
|
769
|
+
toolsCount: rgb(189, 147, 249)
|
|
462
770
|
// Purple
|
|
463
771
|
})
|
|
464
772
|
};
|
|
@@ -483,7 +791,24 @@ var DUSTY_SAGE_THEME = {
|
|
|
483
791
|
cost: rgb(156, 163, 175),
|
|
484
792
|
model: rgb(148, 163, 184),
|
|
485
793
|
duration: rgb(120, 130, 140),
|
|
486
|
-
accent: rgb(120, 140, 130)
|
|
794
|
+
accent: rgb(120, 140, 130),
|
|
795
|
+
cacheHigh: rgb(135, 145, 140),
|
|
796
|
+
cacheMedium: rgb(150, 160, 145),
|
|
797
|
+
cacheLow: rgb(165, 175, 160),
|
|
798
|
+
cacheRead: rgb(120, 140, 130),
|
|
799
|
+
cacheWrite: rgb(148, 163, 184),
|
|
800
|
+
toolsRunning: rgb(150, 160, 145),
|
|
801
|
+
// Medium sage
|
|
802
|
+
toolsCompleted: rgb(135, 145, 140),
|
|
803
|
+
// Subtle sage
|
|
804
|
+
toolsError: rgb(165, 175, 160),
|
|
805
|
+
// Light sage
|
|
806
|
+
toolsName: rgb(120, 140, 130),
|
|
807
|
+
// Dusty green
|
|
808
|
+
toolsTarget: rgb(148, 163, 184),
|
|
809
|
+
// Gray
|
|
810
|
+
toolsCount: rgb(156, 163, 175)
|
|
811
|
+
// Light gray
|
|
487
812
|
})
|
|
488
813
|
};
|
|
489
814
|
|
|
@@ -512,18 +837,40 @@ var GITHUB_DARK_DIMMED_THEME = {
|
|
|
512
837
|
// Gray
|
|
513
838
|
duration: rgb(110, 118, 129),
|
|
514
839
|
// Dark gray
|
|
515
|
-
accent: rgb(88, 166, 255)
|
|
840
|
+
accent: rgb(88, 166, 255),
|
|
516
841
|
// GitHub blue
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
//
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
//
|
|
842
|
+
cacheHigh: rgb(35, 134, 54),
|
|
843
|
+
// GitHub green
|
|
844
|
+
cacheMedium: rgb(210, 153, 34),
|
|
845
|
+
// GitHub orange
|
|
846
|
+
cacheLow: rgb(248, 81, 73),
|
|
847
|
+
// GitHub red
|
|
848
|
+
cacheRead: rgb(88, 166, 255),
|
|
849
|
+
// GitHub blue
|
|
850
|
+
cacheWrite: rgb(163, 113, 247),
|
|
851
|
+
// Purple
|
|
852
|
+
toolsRunning: rgb(210, 153, 34),
|
|
853
|
+
// GitHub orange
|
|
854
|
+
toolsCompleted: rgb(35, 134, 54),
|
|
855
|
+
// GitHub green
|
|
856
|
+
toolsError: rgb(248, 81, 73),
|
|
857
|
+
// GitHub red
|
|
858
|
+
toolsName: rgb(88, 166, 255),
|
|
859
|
+
// GitHub blue
|
|
860
|
+
toolsTarget: rgb(201, 209, 217),
|
|
861
|
+
// Gray
|
|
862
|
+
toolsCount: rgb(163, 113, 247)
|
|
863
|
+
// Purple
|
|
864
|
+
})
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// src/ui/theme/themes/monokai-theme.ts
|
|
868
|
+
var MONOKAI_THEME = {
|
|
869
|
+
name: "monokai",
|
|
870
|
+
description: "Vibrant, high-contrast",
|
|
871
|
+
colors: createThemeColors({
|
|
872
|
+
branch: rgb(102, 217, 239),
|
|
873
|
+
// Cyan
|
|
527
874
|
changes: rgb(249, 26, 114),
|
|
528
875
|
// Pink
|
|
529
876
|
contextLow: rgb(166, 226, 46),
|
|
@@ -542,8 +889,30 @@ var MONOKAI_THEME = {
|
|
|
542
889
|
// Purple
|
|
543
890
|
duration: rgb(102, 217, 239),
|
|
544
891
|
// Cyan
|
|
545
|
-
accent: rgb(249, 26, 114)
|
|
892
|
+
accent: rgb(249, 26, 114),
|
|
893
|
+
// Pink
|
|
894
|
+
cacheHigh: rgb(166, 226, 46),
|
|
895
|
+
// Green
|
|
896
|
+
cacheMedium: rgb(253, 151, 31),
|
|
897
|
+
// Orange
|
|
898
|
+
cacheLow: rgb(249, 26, 114),
|
|
899
|
+
// Pink
|
|
900
|
+
cacheRead: rgb(102, 217, 239),
|
|
901
|
+
// Cyan
|
|
902
|
+
cacheWrite: rgb(174, 129, 255),
|
|
903
|
+
// Purple
|
|
904
|
+
toolsRunning: rgb(253, 151, 31),
|
|
905
|
+
// Orange
|
|
906
|
+
toolsCompleted: rgb(166, 226, 46),
|
|
907
|
+
// Green
|
|
908
|
+
toolsError: rgb(249, 26, 114),
|
|
546
909
|
// Pink
|
|
910
|
+
toolsName: rgb(102, 217, 239),
|
|
911
|
+
// Cyan
|
|
912
|
+
toolsTarget: rgb(174, 129, 255),
|
|
913
|
+
// Purple
|
|
914
|
+
toolsCount: rgb(254, 128, 25)
|
|
915
|
+
// Bright orange
|
|
547
916
|
})
|
|
548
917
|
};
|
|
549
918
|
|
|
@@ -567,7 +936,24 @@ var MUTED_GRAY_THEME = {
|
|
|
567
936
|
cost: rgb(156, 163, 175),
|
|
568
937
|
model: rgb(148, 163, 184),
|
|
569
938
|
duration: rgb(107, 114, 128),
|
|
570
|
-
accent: rgb(156, 163, 175)
|
|
939
|
+
accent: rgb(156, 163, 175),
|
|
940
|
+
cacheHigh: rgb(148, 163, 184),
|
|
941
|
+
cacheMedium: rgb(160, 174, 192),
|
|
942
|
+
cacheLow: rgb(175, 188, 201),
|
|
943
|
+
cacheRead: rgb(156, 163, 175),
|
|
944
|
+
cacheWrite: rgb(148, 163, 184),
|
|
945
|
+
toolsRunning: rgb(160, 174, 192),
|
|
946
|
+
// Medium gray
|
|
947
|
+
toolsCompleted: rgb(148, 163, 184),
|
|
948
|
+
// Subtle gray
|
|
949
|
+
toolsError: rgb(175, 188, 201),
|
|
950
|
+
// Light gray
|
|
951
|
+
toolsName: rgb(156, 163, 175),
|
|
952
|
+
// Slate gray
|
|
953
|
+
toolsTarget: rgb(148, 163, 184),
|
|
954
|
+
// Lighter slate
|
|
955
|
+
toolsCount: rgb(156, 163, 175)
|
|
956
|
+
// Slate gray
|
|
571
957
|
})
|
|
572
958
|
};
|
|
573
959
|
|
|
@@ -596,8 +982,30 @@ var NORD_THEME = {
|
|
|
596
982
|
// Nordic blue
|
|
597
983
|
duration: rgb(94, 129, 172),
|
|
598
984
|
// Nordic dark blue
|
|
599
|
-
accent: rgb(136, 192, 208)
|
|
985
|
+
accent: rgb(136, 192, 208),
|
|
986
|
+
// Nordic cyan
|
|
987
|
+
cacheHigh: rgb(163, 190, 140),
|
|
988
|
+
// Nordic green
|
|
989
|
+
cacheMedium: rgb(235, 203, 139),
|
|
990
|
+
// Nordic yellow
|
|
991
|
+
cacheLow: rgb(191, 97, 106),
|
|
992
|
+
// Nordic red
|
|
993
|
+
cacheRead: rgb(136, 192, 208),
|
|
994
|
+
// Nordic cyan
|
|
995
|
+
cacheWrite: rgb(129, 161, 193),
|
|
996
|
+
// Nordic blue
|
|
997
|
+
toolsRunning: rgb(235, 203, 139),
|
|
998
|
+
// Nordic yellow
|
|
999
|
+
toolsCompleted: rgb(163, 190, 140),
|
|
1000
|
+
// Nordic green
|
|
1001
|
+
toolsError: rgb(191, 97, 106),
|
|
1002
|
+
// Nordic red
|
|
1003
|
+
toolsName: rgb(136, 192, 208),
|
|
600
1004
|
// Nordic cyan
|
|
1005
|
+
toolsTarget: rgb(129, 161, 193),
|
|
1006
|
+
// Nordic blue
|
|
1007
|
+
toolsCount: rgb(216, 222, 233)
|
|
1008
|
+
// Nordic white
|
|
601
1009
|
})
|
|
602
1010
|
};
|
|
603
1011
|
|
|
@@ -626,8 +1034,30 @@ var ONE_DARK_PRO_THEME = {
|
|
|
626
1034
|
// Gray
|
|
627
1035
|
duration: rgb(125, 148, 173),
|
|
628
1036
|
// Dark gray
|
|
629
|
-
accent: rgb(97, 175, 239)
|
|
1037
|
+
accent: rgb(97, 175, 239),
|
|
630
1038
|
// Blue
|
|
1039
|
+
cacheHigh: rgb(152, 195, 121),
|
|
1040
|
+
// Green
|
|
1041
|
+
cacheMedium: rgb(229, 192, 123),
|
|
1042
|
+
// Yellow
|
|
1043
|
+
cacheLow: rgb(224, 108, 117),
|
|
1044
|
+
// Red
|
|
1045
|
+
cacheRead: rgb(97, 175, 239),
|
|
1046
|
+
// Blue
|
|
1047
|
+
cacheWrite: rgb(171, 178, 191),
|
|
1048
|
+
// Gray
|
|
1049
|
+
toolsRunning: rgb(229, 192, 123),
|
|
1050
|
+
// Yellow
|
|
1051
|
+
toolsCompleted: rgb(152, 195, 121),
|
|
1052
|
+
// Green
|
|
1053
|
+
toolsError: rgb(224, 108, 117),
|
|
1054
|
+
// Red
|
|
1055
|
+
toolsName: rgb(97, 175, 239),
|
|
1056
|
+
// Blue
|
|
1057
|
+
toolsTarget: rgb(171, 178, 191),
|
|
1058
|
+
// Gray
|
|
1059
|
+
toolsCount: rgb(209, 154, 102)
|
|
1060
|
+
// Orange
|
|
631
1061
|
})
|
|
632
1062
|
};
|
|
633
1063
|
|
|
@@ -656,8 +1086,30 @@ var PROFESSIONAL_BLUE_THEME = {
|
|
|
656
1086
|
// Purple
|
|
657
1087
|
duration: rgb(203, 213, 225),
|
|
658
1088
|
// Light gray
|
|
659
|
-
accent: rgb(37, 99, 235)
|
|
1089
|
+
accent: rgb(37, 99, 235),
|
|
1090
|
+
// Royal blue
|
|
1091
|
+
cacheHigh: rgb(74, 222, 128),
|
|
1092
|
+
// Green
|
|
1093
|
+
cacheMedium: rgb(251, 191, 36),
|
|
1094
|
+
// Amber
|
|
1095
|
+
cacheLow: rgb(248, 113, 113),
|
|
1096
|
+
// Red
|
|
1097
|
+
cacheRead: rgb(96, 165, 250),
|
|
1098
|
+
// Light blue
|
|
1099
|
+
cacheWrite: rgb(167, 139, 250),
|
|
1100
|
+
// Purple
|
|
1101
|
+
toolsRunning: rgb(251, 191, 36),
|
|
1102
|
+
// Amber
|
|
1103
|
+
toolsCompleted: rgb(74, 222, 128),
|
|
1104
|
+
// Green
|
|
1105
|
+
toolsError: rgb(248, 113, 113),
|
|
1106
|
+
// Red
|
|
1107
|
+
toolsName: rgb(37, 99, 235),
|
|
660
1108
|
// Royal blue
|
|
1109
|
+
toolsTarget: rgb(148, 163, 184),
|
|
1110
|
+
// Slate gray
|
|
1111
|
+
toolsCount: rgb(167, 139, 250)
|
|
1112
|
+
// Purple
|
|
661
1113
|
})
|
|
662
1114
|
};
|
|
663
1115
|
|
|
@@ -686,8 +1138,30 @@ var ROSE_PINE_THEME = {
|
|
|
686
1138
|
// Pine violet
|
|
687
1139
|
duration: rgb(148, 137, 176),
|
|
688
1140
|
// Pine mute
|
|
689
|
-
accent: rgb(235, 111, 146)
|
|
1141
|
+
accent: rgb(235, 111, 146),
|
|
1142
|
+
// Pine red
|
|
1143
|
+
cacheHigh: rgb(156, 207, 216),
|
|
1144
|
+
// Pine cyan
|
|
1145
|
+
cacheMedium: rgb(233, 201, 176),
|
|
1146
|
+
// Pine beige
|
|
1147
|
+
cacheLow: rgb(235, 111, 146),
|
|
1148
|
+
// Pine red
|
|
1149
|
+
cacheRead: rgb(156, 207, 216),
|
|
1150
|
+
// Pine cyan
|
|
1151
|
+
cacheWrite: rgb(224, 208, 245),
|
|
1152
|
+
// Pine violet
|
|
1153
|
+
toolsRunning: rgb(233, 201, 176),
|
|
1154
|
+
// Pine beige
|
|
1155
|
+
toolsCompleted: rgb(156, 207, 216),
|
|
1156
|
+
// Pine cyan
|
|
1157
|
+
toolsError: rgb(235, 111, 146),
|
|
690
1158
|
// Pine red
|
|
1159
|
+
toolsName: rgb(156, 207, 216),
|
|
1160
|
+
// Pine cyan
|
|
1161
|
+
toolsTarget: rgb(224, 208, 245),
|
|
1162
|
+
// Pine violet
|
|
1163
|
+
toolsCount: rgb(226, 185, 218)
|
|
1164
|
+
// Pine pink
|
|
691
1165
|
})
|
|
692
1166
|
};
|
|
693
1167
|
|
|
@@ -716,8 +1190,30 @@ var SEMANTIC_CLASSIC_THEME = {
|
|
|
716
1190
|
// Indigo
|
|
717
1191
|
duration: rgb(107, 114, 128),
|
|
718
1192
|
// Gray
|
|
719
|
-
accent: rgb(59, 130, 246)
|
|
1193
|
+
accent: rgb(59, 130, 246),
|
|
1194
|
+
// Blue
|
|
1195
|
+
cacheHigh: rgb(34, 197, 94),
|
|
1196
|
+
// Green
|
|
1197
|
+
cacheMedium: rgb(234, 179, 8),
|
|
1198
|
+
// Yellow
|
|
1199
|
+
cacheLow: rgb(239, 68, 68),
|
|
1200
|
+
// Red
|
|
1201
|
+
cacheRead: rgb(59, 130, 246),
|
|
1202
|
+
// Blue
|
|
1203
|
+
cacheWrite: rgb(99, 102, 241),
|
|
1204
|
+
// Indigo
|
|
1205
|
+
toolsRunning: rgb(234, 179, 8),
|
|
1206
|
+
// Yellow
|
|
1207
|
+
toolsCompleted: rgb(34, 197, 94),
|
|
1208
|
+
// Green
|
|
1209
|
+
toolsError: rgb(239, 68, 68),
|
|
1210
|
+
// Red
|
|
1211
|
+
toolsName: rgb(59, 130, 246),
|
|
720
1212
|
// Blue
|
|
1213
|
+
toolsTarget: rgb(107, 114, 128),
|
|
1214
|
+
// Gray
|
|
1215
|
+
toolsCount: rgb(99, 102, 241)
|
|
1216
|
+
// Indigo
|
|
721
1217
|
})
|
|
722
1218
|
};
|
|
723
1219
|
|
|
@@ -741,7 +1237,24 @@ var SLATE_BLUE_THEME = {
|
|
|
741
1237
|
cost: rgb(156, 163, 175),
|
|
742
1238
|
model: rgb(148, 163, 184),
|
|
743
1239
|
duration: rgb(100, 116, 139),
|
|
744
|
-
accent: rgb(100, 116, 139)
|
|
1240
|
+
accent: rgb(100, 116, 139),
|
|
1241
|
+
cacheHigh: rgb(148, 163, 184),
|
|
1242
|
+
cacheMedium: rgb(160, 174, 192),
|
|
1243
|
+
cacheLow: rgb(175, 188, 201),
|
|
1244
|
+
cacheRead: rgb(100, 116, 139),
|
|
1245
|
+
cacheWrite: rgb(148, 163, 184),
|
|
1246
|
+
toolsRunning: rgb(160, 174, 192),
|
|
1247
|
+
// Medium slate
|
|
1248
|
+
toolsCompleted: rgb(148, 163, 184),
|
|
1249
|
+
// Subtle slate-blue
|
|
1250
|
+
toolsError: rgb(175, 188, 201),
|
|
1251
|
+
// Light slate
|
|
1252
|
+
toolsName: rgb(100, 116, 139),
|
|
1253
|
+
// Cool slate
|
|
1254
|
+
toolsTarget: rgb(148, 163, 184),
|
|
1255
|
+
// Neutral slate
|
|
1256
|
+
toolsCount: rgb(156, 163, 175)
|
|
1257
|
+
// Light slate
|
|
745
1258
|
})
|
|
746
1259
|
};
|
|
747
1260
|
|
|
@@ -770,8 +1283,30 @@ var SOLARIZED_DARK_THEME = {
|
|
|
770
1283
|
// Base0
|
|
771
1284
|
duration: rgb(88, 110, 117),
|
|
772
1285
|
// Base01
|
|
773
|
-
accent: rgb(38, 139, 210)
|
|
1286
|
+
accent: rgb(38, 139, 210),
|
|
1287
|
+
// Blue
|
|
1288
|
+
cacheHigh: rgb(133, 153, 0),
|
|
1289
|
+
// Olive
|
|
1290
|
+
cacheMedium: rgb(181, 137, 0),
|
|
1291
|
+
// Yellow
|
|
1292
|
+
cacheLow: rgb(220, 50, 47),
|
|
1293
|
+
// Red
|
|
1294
|
+
cacheRead: rgb(38, 139, 210),
|
|
1295
|
+
// Blue
|
|
1296
|
+
cacheWrite: rgb(147, 161, 161),
|
|
1297
|
+
// Base1
|
|
1298
|
+
toolsRunning: rgb(181, 137, 0),
|
|
1299
|
+
// Yellow
|
|
1300
|
+
toolsCompleted: rgb(133, 153, 0),
|
|
1301
|
+
// Olive
|
|
1302
|
+
toolsError: rgb(220, 50, 47),
|
|
1303
|
+
// Red
|
|
1304
|
+
toolsName: rgb(38, 139, 210),
|
|
774
1305
|
// Blue
|
|
1306
|
+
toolsTarget: rgb(131, 148, 150),
|
|
1307
|
+
// Base0
|
|
1308
|
+
toolsCount: rgb(203, 75, 22)
|
|
1309
|
+
// Orange
|
|
775
1310
|
})
|
|
776
1311
|
};
|
|
777
1312
|
|
|
@@ -800,8 +1335,30 @@ var TOKYO_NIGHT_THEME = {
|
|
|
800
1335
|
// White-ish
|
|
801
1336
|
duration: rgb(113, 119, 161),
|
|
802
1337
|
// Dark blue-gray
|
|
803
|
-
accent: rgb(122, 132, 173)
|
|
1338
|
+
accent: rgb(122, 132, 173),
|
|
1339
|
+
// Blue
|
|
1340
|
+
cacheHigh: rgb(146, 180, 203),
|
|
1341
|
+
// Cyan
|
|
1342
|
+
cacheMedium: rgb(232, 166, 162),
|
|
1343
|
+
// Pink-red
|
|
1344
|
+
cacheLow: rgb(249, 86, 119),
|
|
1345
|
+
// Red
|
|
1346
|
+
cacheRead: rgb(122, 132, 173),
|
|
1347
|
+
// Blue
|
|
1348
|
+
cacheWrite: rgb(169, 177, 214),
|
|
1349
|
+
// White-ish
|
|
1350
|
+
toolsRunning: rgb(232, 166, 162),
|
|
1351
|
+
// Pink-red
|
|
1352
|
+
toolsCompleted: rgb(146, 180, 203),
|
|
1353
|
+
// Cyan
|
|
1354
|
+
toolsError: rgb(249, 86, 119),
|
|
1355
|
+
// Red
|
|
1356
|
+
toolsName: rgb(122, 132, 173),
|
|
804
1357
|
// Blue
|
|
1358
|
+
toolsTarget: rgb(169, 177, 214),
|
|
1359
|
+
// White-ish
|
|
1360
|
+
toolsCount: rgb(158, 206, 209)
|
|
1361
|
+
// Teal
|
|
805
1362
|
})
|
|
806
1363
|
};
|
|
807
1364
|
|
|
@@ -830,429 +1387,875 @@ var VSCODE_DARK_PLUS_THEME = {
|
|
|
830
1387
|
// Gray
|
|
831
1388
|
duration: rgb(125, 148, 173),
|
|
832
1389
|
// Dark gray
|
|
833
|
-
accent: rgb(0, 122, 204)
|
|
1390
|
+
accent: rgb(0, 122, 204),
|
|
1391
|
+
// VSCode blue
|
|
1392
|
+
cacheHigh: rgb(78, 201, 176),
|
|
1393
|
+
// Teal
|
|
1394
|
+
cacheMedium: rgb(220, 220, 170),
|
|
1395
|
+
// Yellow
|
|
1396
|
+
cacheLow: rgb(244, 71, 71),
|
|
1397
|
+
// Red
|
|
1398
|
+
cacheRead: rgb(0, 122, 204),
|
|
834
1399
|
// VSCode blue
|
|
1400
|
+
cacheWrite: rgb(171, 178, 191),
|
|
1401
|
+
// Gray
|
|
1402
|
+
toolsRunning: rgb(251, 191, 36),
|
|
1403
|
+
// Yellow
|
|
1404
|
+
toolsCompleted: rgb(74, 222, 128),
|
|
1405
|
+
// Green
|
|
1406
|
+
toolsError: rgb(248, 113, 113),
|
|
1407
|
+
// Red
|
|
1408
|
+
toolsName: rgb(96, 165, 250),
|
|
1409
|
+
// Blue
|
|
1410
|
+
toolsTarget: rgb(156, 163, 175),
|
|
1411
|
+
// Gray
|
|
1412
|
+
toolsCount: rgb(167, 139, 250)
|
|
1413
|
+
// Purple
|
|
835
1414
|
})
|
|
836
1415
|
};
|
|
837
1416
|
|
|
838
1417
|
// src/ui/theme/index.ts
|
|
839
1418
|
var DEFAULT_THEME = VSCODE_DARK_PLUS_THEME.colors;
|
|
840
1419
|
|
|
841
|
-
// src/
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1420
|
+
// src/widgets/core/stdin-data-widget.ts
|
|
1421
|
+
var StdinDataWidget = class {
|
|
1422
|
+
/**
|
|
1423
|
+
* Stored stdin data from last update
|
|
1424
|
+
*/
|
|
1425
|
+
data = null;
|
|
1426
|
+
/**
|
|
1427
|
+
* Widget enabled state
|
|
1428
|
+
*/
|
|
1429
|
+
enabled = true;
|
|
1430
|
+
/**
|
|
1431
|
+
* Initialize widget with context
|
|
1432
|
+
* @param context - Widget initialization context
|
|
1433
|
+
*/
|
|
1434
|
+
async initialize(context) {
|
|
1435
|
+
this.enabled = context.config?.enabled !== false;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Update widget with new stdin data
|
|
1439
|
+
* @param data - Stdin data from Claude Code
|
|
1440
|
+
*/
|
|
1441
|
+
async update(data) {
|
|
1442
|
+
this.data = data;
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* Get stored stdin data
|
|
1446
|
+
* @returns Stored stdin data
|
|
1447
|
+
* @throws Error if data has not been initialized (update not called)
|
|
1448
|
+
*/
|
|
1449
|
+
getData() {
|
|
1450
|
+
if (!this.data) {
|
|
1451
|
+
throw new Error(`Widget ${this.id} data not initialized. Call update() first.`);
|
|
1452
|
+
}
|
|
1453
|
+
return this.data;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Check if widget is enabled
|
|
1457
|
+
* @returns true if widget should render
|
|
1458
|
+
*/
|
|
1459
|
+
isEnabled() {
|
|
1460
|
+
return this.enabled;
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Template method - final, subclasses implement renderWithData()
|
|
1464
|
+
*
|
|
1465
|
+
* Handles null data checks and calls renderWithData() hook.
|
|
1466
|
+
*
|
|
1467
|
+
* @param context - Render context
|
|
1468
|
+
* @returns Rendered string, or null if widget should not display
|
|
1469
|
+
*/
|
|
1470
|
+
async render(context) {
|
|
1471
|
+
if (!this.data || !this.enabled) {
|
|
1472
|
+
return null;
|
|
1473
|
+
}
|
|
1474
|
+
return this.renderWithData(this.data, context);
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
|
|
1478
|
+
// src/widgets/active-tools/styles.ts
|
|
1479
|
+
function truncatePath(path2) {
|
|
1480
|
+
if (path2.length <= 30) {
|
|
1481
|
+
return path2;
|
|
1482
|
+
}
|
|
1483
|
+
const parts = path2.split("/");
|
|
1484
|
+
return `.../${parts[parts.length - 1]}`;
|
|
848
1485
|
}
|
|
849
|
-
function
|
|
850
|
-
const
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1486
|
+
function formatTool(name, target, colors) {
|
|
1487
|
+
const nameStr = colorize(name, colors.tools.name);
|
|
1488
|
+
if (target) {
|
|
1489
|
+
const targetStr = colorize(`: ${truncatePath(target)}`, colors.tools.target);
|
|
1490
|
+
return `${nameStr}${targetStr}`;
|
|
1491
|
+
}
|
|
1492
|
+
return nameStr;
|
|
854
1493
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
if (!colors) return data.branch;
|
|
860
|
-
return colorize(data.branch, colors.branch);
|
|
861
|
-
},
|
|
1494
|
+
var activeToolsStyles = {
|
|
1495
|
+
/**
|
|
1496
|
+
* balanced: Running tools with ◐ spinner, completed aggregated with ✓ ×count
|
|
1497
|
+
*/
|
|
862
1498
|
balanced: (data, colors) => {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1499
|
+
const parts = [];
|
|
1500
|
+
for (const tool of data.running.slice(-2)) {
|
|
1501
|
+
const indicator = colors ? colorize("\u25D0", colors.tools.running) : "\u25D0";
|
|
1502
|
+
parts.push(
|
|
1503
|
+
`${indicator} ${formatTool(tool.name, tool.target, colors ?? getDefaultColors())}`
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
const sorted = Array.from(data.completed.entries()).sort((a, b) => b[1] - a[1]).slice(0, 4);
|
|
1507
|
+
for (const [name, count] of sorted) {
|
|
1508
|
+
const check = colors ? colorize("\u2713", colors.tools.completed) : "\u2713";
|
|
1509
|
+
const countStr = colors ? colorize(`\xD7${count}`, colors.tools.count) : `\xD7${count}`;
|
|
1510
|
+
parts.push(`${check} ${name} ${countStr}`);
|
|
1511
|
+
}
|
|
1512
|
+
if (parts.length === 0) {
|
|
1513
|
+
return "";
|
|
1514
|
+
}
|
|
1515
|
+
return parts.join(" | ");
|
|
874
1516
|
},
|
|
1517
|
+
/**
|
|
1518
|
+
* compact: [ToolName] format for all tools
|
|
1519
|
+
*/
|
|
875
1520
|
compact: (data, colors) => {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
if (parts.length > 0) {
|
|
881
|
-
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
882
|
-
const changesStr = parts.join("/");
|
|
883
|
-
return `${branch} ${changesStr}`;
|
|
884
|
-
}
|
|
1521
|
+
const parts = [];
|
|
1522
|
+
const c = colors ?? getDefaultColors();
|
|
1523
|
+
for (const tool of data.running) {
|
|
1524
|
+
parts.push(`[${colorize(tool.name, c.tools.name)}]`);
|
|
885
1525
|
}
|
|
886
|
-
|
|
1526
|
+
for (const [name] of Array.from(data.completed.entries()).slice(0, 3)) {
|
|
1527
|
+
parts.push(`[${colorize(name, c.tools.completed)}]`);
|
|
1528
|
+
}
|
|
1529
|
+
if (parts.length === 0) {
|
|
1530
|
+
return "";
|
|
1531
|
+
}
|
|
1532
|
+
return parts.join(" ");
|
|
1533
|
+
},
|
|
1534
|
+
/**
|
|
1535
|
+
* minimal: Same as compact
|
|
1536
|
+
*/
|
|
1537
|
+
minimal: (data, colors) => {
|
|
1538
|
+
const compactStyle = activeToolsStyles.compact;
|
|
1539
|
+
if (!compactStyle) return "";
|
|
1540
|
+
return compactStyle(data, colors);
|
|
887
1541
|
},
|
|
1542
|
+
/**
|
|
1543
|
+
* playful: Emojis (📖✏️✨🔄🔍📁) with tool names
|
|
1544
|
+
*/
|
|
888
1545
|
playful: (data, colors) => {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
}
|
|
1546
|
+
const parts = [];
|
|
1547
|
+
const emojis = {
|
|
1548
|
+
Read: "\u{1F4D6}",
|
|
1549
|
+
Write: "\u270F\uFE0F",
|
|
1550
|
+
Edit: "\u2728",
|
|
1551
|
+
Bash: "\u{1F504}",
|
|
1552
|
+
Grep: "\u{1F50D}",
|
|
1553
|
+
Glob: "\u{1F4C1}"
|
|
1554
|
+
};
|
|
1555
|
+
for (const tool of data.running.slice(-3)) {
|
|
1556
|
+
const emoji = emojis[tool.name] ?? "\u{1F527}";
|
|
1557
|
+
const nameStr = colors ? colorize(tool.name, colors.tools.name) : tool.name;
|
|
1558
|
+
parts.push(`${emoji} ${nameStr}`);
|
|
897
1559
|
}
|
|
898
|
-
|
|
899
|
-
|
|
1560
|
+
if (parts.length === 0) {
|
|
1561
|
+
return "";
|
|
1562
|
+
}
|
|
1563
|
+
return parts.join(", ");
|
|
900
1564
|
},
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
}
|
|
1565
|
+
/**
|
|
1566
|
+
* verbose: Full text labels "Running:" and "Completed:"
|
|
1567
|
+
*/
|
|
1568
|
+
verbose: (data, colors) => {
|
|
1569
|
+
const parts = [];
|
|
1570
|
+
const c = colors ?? getDefaultColors();
|
|
1571
|
+
for (const tool of data.running) {
|
|
1572
|
+
const label = colorize("Running:", c.tools.running);
|
|
1573
|
+
parts.push(`${label} ${formatTool(tool.name, tool.target, c)}`);
|
|
911
1574
|
}
|
|
912
|
-
const
|
|
913
|
-
|
|
1575
|
+
const sorted = Array.from(data.completed.entries()).sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
1576
|
+
for (const [name, count] of sorted) {
|
|
1577
|
+
const label = colorize("Completed:", c.tools.completed);
|
|
1578
|
+
const countStr = colorize(`(${count}x)`, c.tools.count);
|
|
1579
|
+
parts.push(`${label} ${name} ${countStr}`);
|
|
1580
|
+
}
|
|
1581
|
+
if (parts.length === 0) {
|
|
1582
|
+
return "";
|
|
1583
|
+
}
|
|
1584
|
+
return parts.join(" | ");
|
|
914
1585
|
},
|
|
1586
|
+
/**
|
|
1587
|
+
* labeled: "Tools:" prefix with all tools
|
|
1588
|
+
*/
|
|
915
1589
|
labeled: (data, colors) => {
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1590
|
+
const c = colors ?? getDefaultColors();
|
|
1591
|
+
const allTools = [
|
|
1592
|
+
...data.running.map((t) => {
|
|
1593
|
+
const indicator = colorize("\u25D0", c.tools.running);
|
|
1594
|
+
return `${indicator} ${formatTool(t.name, t.target, c)}`;
|
|
1595
|
+
}),
|
|
1596
|
+
...Array.from(data.completed.entries()).slice(0, 3).map(([name, count]) => {
|
|
1597
|
+
const indicator = colorize("\u2713", c.tools.completed);
|
|
1598
|
+
const countStr = colorize(`\xD7${count}`, c.tools.count);
|
|
1599
|
+
return `${indicator} ${name} ${countStr}`;
|
|
1600
|
+
})
|
|
1601
|
+
];
|
|
1602
|
+
if (allTools.length === 0) {
|
|
1603
|
+
return "";
|
|
1604
|
+
}
|
|
1605
|
+
const prefix = colors ? colorize("Tools:", c.semantic.info) : "Tools:";
|
|
1606
|
+
return `${prefix}: ${allTools.join(" | ")}`;
|
|
928
1607
|
},
|
|
1608
|
+
/**
|
|
1609
|
+
* indicator: ● bullet indicators
|
|
1610
|
+
*/
|
|
929
1611
|
indicator: (data, colors) => {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
936
|
-
const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
|
|
937
|
-
return `\u25CF ${branch} ${changes}`;
|
|
938
|
-
}
|
|
1612
|
+
const parts = [];
|
|
1613
|
+
const c = colors ?? getDefaultColors();
|
|
1614
|
+
for (const tool of data.running) {
|
|
1615
|
+
const bullet = colorize("\u25CF", c.semantic.info);
|
|
1616
|
+
parts.push(`${bullet} ${formatTool(tool.name, tool.target, c)}`);
|
|
939
1617
|
}
|
|
940
|
-
|
|
1618
|
+
for (const [name] of Array.from(data.completed.entries()).slice(0, 3)) {
|
|
1619
|
+
const bullet = colorize("\u25CF", c.tools.completed);
|
|
1620
|
+
parts.push(`${bullet} ${name}`);
|
|
1621
|
+
}
|
|
1622
|
+
if (parts.length === 0) {
|
|
1623
|
+
return "";
|
|
1624
|
+
}
|
|
1625
|
+
return parts.join(" | ");
|
|
941
1626
|
}
|
|
942
1627
|
};
|
|
1628
|
+
function getDefaultColors() {
|
|
1629
|
+
return {
|
|
1630
|
+
base: {
|
|
1631
|
+
text: "\x1B[37m",
|
|
1632
|
+
muted: "\x1B[90m",
|
|
1633
|
+
accent: "\x1B[36m",
|
|
1634
|
+
border: "\x1B[90m"
|
|
1635
|
+
},
|
|
1636
|
+
semantic: {
|
|
1637
|
+
success: "\x1B[32m",
|
|
1638
|
+
warning: "\x1B[33m",
|
|
1639
|
+
error: "\x1B[31m",
|
|
1640
|
+
info: "\x1B[36m"
|
|
1641
|
+
},
|
|
1642
|
+
git: {
|
|
1643
|
+
branch: "\x1B[36m",
|
|
1644
|
+
changes: "\x1B[33m"
|
|
1645
|
+
},
|
|
1646
|
+
context: {
|
|
1647
|
+
low: "\x1B[32m",
|
|
1648
|
+
medium: "\x1B[33m",
|
|
1649
|
+
high: "\x1B[31m",
|
|
1650
|
+
bar: "\x1B[37m"
|
|
1651
|
+
},
|
|
1652
|
+
lines: {
|
|
1653
|
+
added: "\x1B[32m",
|
|
1654
|
+
removed: "\x1B[31m"
|
|
1655
|
+
},
|
|
1656
|
+
cost: {
|
|
1657
|
+
amount: "\x1B[37m",
|
|
1658
|
+
currency: "\x1B[90m"
|
|
1659
|
+
},
|
|
1660
|
+
duration: {
|
|
1661
|
+
value: "\x1B[37m",
|
|
1662
|
+
unit: "\x1B[90m"
|
|
1663
|
+
},
|
|
1664
|
+
model: {
|
|
1665
|
+
name: "\x1B[36m",
|
|
1666
|
+
version: "\x1B[90m"
|
|
1667
|
+
},
|
|
1668
|
+
poker: {
|
|
1669
|
+
participating: "\x1B[37m",
|
|
1670
|
+
nonParticipating: "\x1B[90m",
|
|
1671
|
+
result: "\x1B[36m"
|
|
1672
|
+
},
|
|
1673
|
+
cache: {
|
|
1674
|
+
high: "\x1B[32m",
|
|
1675
|
+
medium: "\x1B[33m",
|
|
1676
|
+
low: "\x1B[31m",
|
|
1677
|
+
read: "\x1B[34m",
|
|
1678
|
+
write: "\x1B[35m"
|
|
1679
|
+
},
|
|
1680
|
+
tools: {
|
|
1681
|
+
running: "\x1B[33m",
|
|
1682
|
+
completed: "\x1B[32m",
|
|
1683
|
+
error: "\x1B[31m",
|
|
1684
|
+
name: "\x1B[34m",
|
|
1685
|
+
target: "\x1B[90m",
|
|
1686
|
+
count: "\x1B[35m"
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
943
1690
|
|
|
944
|
-
// src/widgets/
|
|
945
|
-
var
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1691
|
+
// src/widgets/active-tools/active-tools-widget.ts
|
|
1692
|
+
var ActiveToolsWidget = class extends StdinDataWidget {
|
|
1693
|
+
constructor(theme, transcriptProvider) {
|
|
1694
|
+
super();
|
|
1695
|
+
this.theme = theme;
|
|
1696
|
+
this.transcriptProvider = transcriptProvider;
|
|
1697
|
+
}
|
|
1698
|
+
id = "active-tools";
|
|
1699
|
+
metadata = {
|
|
1700
|
+
name: "Active Tools",
|
|
1701
|
+
description: "Active tools display from transcript",
|
|
1702
|
+
version: "1.0.0",
|
|
1703
|
+
author: "claude-scope",
|
|
1704
|
+
line: 2
|
|
1705
|
+
// Display on third line (0-indexed)
|
|
1706
|
+
};
|
|
1707
|
+
style = "balanced";
|
|
1708
|
+
tools = [];
|
|
1709
|
+
renderData;
|
|
961
1710
|
/**
|
|
962
|
-
*
|
|
963
|
-
*
|
|
964
|
-
* Tests can inject MockGit factory here
|
|
965
|
-
* @param colors - Optional theme colors
|
|
1711
|
+
* Set display style
|
|
1712
|
+
* @param style - Style to use for rendering
|
|
966
1713
|
*/
|
|
967
|
-
|
|
968
|
-
this.
|
|
969
|
-
this.colors = colors ?? DEFAULT_THEME;
|
|
1714
|
+
setStyle(style) {
|
|
1715
|
+
this.style = style;
|
|
970
1716
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1717
|
+
/**
|
|
1718
|
+
* Aggregate completed tools by name
|
|
1719
|
+
* @param tools - Array of tool entries
|
|
1720
|
+
* @returns Map of tool name to count
|
|
1721
|
+
*/
|
|
1722
|
+
aggregateCompleted(tools) {
|
|
1723
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1724
|
+
for (const tool of tools) {
|
|
1725
|
+
if (tool.status === "completed" || tool.status === "error") {
|
|
1726
|
+
const current = counts.get(tool.name) ?? 0;
|
|
1727
|
+
counts.set(tool.name, current + 1);
|
|
1728
|
+
}
|
|
975
1729
|
}
|
|
1730
|
+
return counts;
|
|
976
1731
|
}
|
|
977
|
-
|
|
978
|
-
|
|
1732
|
+
/**
|
|
1733
|
+
* Prepare render data from tools
|
|
1734
|
+
* @returns Render data with running, completed, and error tools
|
|
1735
|
+
*/
|
|
1736
|
+
prepareRenderData() {
|
|
1737
|
+
const running = this.tools.filter((t) => t.status === "running");
|
|
1738
|
+
const completed = this.aggregateCompleted(this.tools);
|
|
1739
|
+
const errors = this.tools.filter((t) => t.status === "error");
|
|
1740
|
+
return { running, completed, errors };
|
|
979
1741
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1742
|
+
/**
|
|
1743
|
+
* Update widget with new stdin data
|
|
1744
|
+
* @param data - Stdin data from Claude Code
|
|
1745
|
+
*/
|
|
1746
|
+
async update(data) {
|
|
1747
|
+
await super.update(data);
|
|
1748
|
+
if (data.transcript_path) {
|
|
1749
|
+
this.tools = await this.transcriptProvider.parseTools(data.transcript_path);
|
|
1750
|
+
this.renderData = this.prepareRenderData();
|
|
1751
|
+
} else {
|
|
1752
|
+
this.tools = [];
|
|
1753
|
+
this.renderData = void 0;
|
|
983
1754
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
const diffSummary = await this.git.diffSummary();
|
|
993
|
-
if (diffSummary.fileCount > 0) {
|
|
994
|
-
let insertions = 0;
|
|
995
|
-
let deletions = 0;
|
|
996
|
-
for (const file of diffSummary.files) {
|
|
997
|
-
insertions += file.insertions || 0;
|
|
998
|
-
deletions += file.deletions || 0;
|
|
999
|
-
}
|
|
1000
|
-
if (insertions > 0 || deletions > 0) {
|
|
1001
|
-
changes = { files: diffSummary.fileCount, insertions, deletions };
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
} catch {
|
|
1005
|
-
}
|
|
1006
|
-
const renderData = { branch, changes };
|
|
1007
|
-
return this.styleFn(renderData, this.colors.git);
|
|
1008
|
-
} catch {
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Render widget output
|
|
1758
|
+
* @param context - Render context
|
|
1759
|
+
* @returns Rendered string or null if no tools
|
|
1760
|
+
*/
|
|
1761
|
+
renderWithData(data, context) {
|
|
1762
|
+
if (!this.renderData || this.tools.length === 0) {
|
|
1009
1763
|
return null;
|
|
1010
1764
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
this.cwd = data.cwd;
|
|
1015
|
-
this.git = this.gitFactory(data.cwd);
|
|
1765
|
+
const styleFn = activeToolsStyles[this.style] ?? activeToolsStyles.balanced;
|
|
1766
|
+
if (!styleFn) {
|
|
1767
|
+
return null;
|
|
1016
1768
|
}
|
|
1769
|
+
return styleFn(this.renderData, this.theme);
|
|
1017
1770
|
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Check if widget should render
|
|
1773
|
+
* @returns true if there are tools to display
|
|
1774
|
+
*/
|
|
1018
1775
|
isEnabled() {
|
|
1019
|
-
return this.
|
|
1020
|
-
}
|
|
1021
|
-
async cleanup() {
|
|
1776
|
+
return super.isEnabled() && this.tools.length > 0;
|
|
1022
1777
|
}
|
|
1023
1778
|
};
|
|
1024
1779
|
|
|
1025
|
-
// src/
|
|
1026
|
-
|
|
1780
|
+
// src/core/widget-types.ts
|
|
1781
|
+
function createWidgetMetadata(name, description, version = "1.0.0", author = "claude-scope", line = 0) {
|
|
1782
|
+
return {
|
|
1783
|
+
name,
|
|
1784
|
+
description,
|
|
1785
|
+
version,
|
|
1786
|
+
author,
|
|
1787
|
+
line
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// src/widgets/cache-metrics/styles.ts
|
|
1792
|
+
function formatK(n) {
|
|
1793
|
+
if (n < 1e3) {
|
|
1794
|
+
return n.toString();
|
|
1795
|
+
}
|
|
1796
|
+
const k = n / 1e3;
|
|
1797
|
+
return k < 10 ? `${k.toFixed(1)}k` : `${Math.round(k)}k`;
|
|
1798
|
+
}
|
|
1799
|
+
function formatCurrency(usd) {
|
|
1800
|
+
if (usd < 5e-3 && usd > 0) {
|
|
1801
|
+
return "<$0.01";
|
|
1802
|
+
}
|
|
1803
|
+
return `$${usd.toFixed(2)}`;
|
|
1804
|
+
}
|
|
1805
|
+
function createProgressBar(percentage, width) {
|
|
1806
|
+
const filled = Math.round(percentage / 100 * width);
|
|
1807
|
+
const empty = width - filled;
|
|
1808
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
1809
|
+
}
|
|
1810
|
+
function getCacheColor(hitRate, colors) {
|
|
1811
|
+
if (hitRate > 70) {
|
|
1812
|
+
return colors.cache.high;
|
|
1813
|
+
} else if (hitRate >= 40) {
|
|
1814
|
+
return colors.cache.medium;
|
|
1815
|
+
} else {
|
|
1816
|
+
return colors.cache.low;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
var cacheMetricsStyles = {
|
|
1820
|
+
/**
|
|
1821
|
+
* balanced: 💾 70% cached (35.0k tokens) with color coding
|
|
1822
|
+
*/
|
|
1027
1823
|
balanced: (data, colors) => {
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1824
|
+
const { hitRate, cacheRead } = data;
|
|
1825
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1826
|
+
const percentage = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1827
|
+
const tokens = colors ? `${colors.cache.read}${formatK(cacheRead)} tokens` : `${formatK(cacheRead)} tokens`;
|
|
1828
|
+
return `\u{1F4BE} ${percentage} cached (${tokens})`;
|
|
1031
1829
|
},
|
|
1830
|
+
/**
|
|
1831
|
+
* compact: Cache: 70%
|
|
1832
|
+
*/
|
|
1032
1833
|
compact: (data, colors) => {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1834
|
+
const hitRate = data.hitRate.toFixed(0);
|
|
1835
|
+
if (colors) {
|
|
1836
|
+
return `${colors.cache.read}Cache: ${hitRate}%`;
|
|
1837
|
+
}
|
|
1838
|
+
return `Cache: ${hitRate}%`;
|
|
1037
1839
|
},
|
|
1840
|
+
/**
|
|
1841
|
+
* playful: 💾 [███████░] 70% with progress bar
|
|
1842
|
+
*/
|
|
1038
1843
|
playful: (data, colors) => {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1844
|
+
const { hitRate } = data;
|
|
1845
|
+
const bar = createProgressBar(hitRate, 7);
|
|
1846
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1847
|
+
const barAndPercent = color ? `${color}[${bar}] ${hitRate.toFixed(0)}%` : `[${bar}] ${hitRate.toFixed(0)}%`;
|
|
1848
|
+
return `\u{1F4BE} ${barAndPercent}`;
|
|
1042
1849
|
},
|
|
1850
|
+
/**
|
|
1851
|
+
* verbose: Cache: 35.0k tokens (70%) | $0.03 saved
|
|
1852
|
+
*/
|
|
1043
1853
|
verbose: (data, colors) => {
|
|
1044
|
-
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1854
|
+
const { cacheRead, hitRate, savings } = data;
|
|
1855
|
+
const tokens = colors ? `${colors.cache.read}${formatK(cacheRead)} tokens` : `${formatK(cacheRead)} tokens`;
|
|
1856
|
+
const percent = `${hitRate.toFixed(0)}%`;
|
|
1857
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1858
|
+
return `Cache: ${tokens} (${percent}) | ${saved}`;
|
|
1048
1859
|
},
|
|
1860
|
+
/**
|
|
1861
|
+
* labeled: Cache Hit: 70% | $0.03 saved
|
|
1862
|
+
*/
|
|
1049
1863
|
labeled: (data, colors) => {
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1864
|
+
const { hitRate, savings } = data;
|
|
1865
|
+
const percent = colors ? `${colors.cache.read}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1866
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1867
|
+
return `Cache Hit: ${percent} | ${saved}`;
|
|
1053
1868
|
},
|
|
1869
|
+
/**
|
|
1870
|
+
* indicator: ● 70% cached
|
|
1871
|
+
*/
|
|
1054
1872
|
indicator: (data, colors) => {
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1873
|
+
const { hitRate } = data;
|
|
1874
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1875
|
+
const percentage = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1876
|
+
return `\u25CF ${percentage} cached`;
|
|
1877
|
+
},
|
|
1878
|
+
/**
|
|
1879
|
+
* breakdown: Multi-line with ├─ Read: and └─ Write: breakdown
|
|
1880
|
+
*/
|
|
1881
|
+
breakdown: (data, colors) => {
|
|
1882
|
+
const { cacheRead, cacheWrite, hitRate, savings } = data;
|
|
1883
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1884
|
+
const percent = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1885
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1886
|
+
const read = colors ? `${colors.cache.read}${formatK(cacheRead)}` : formatK(cacheRead);
|
|
1887
|
+
const write = colors ? `${colors.cache.write}${formatK(cacheWrite)}` : formatK(cacheWrite);
|
|
1888
|
+
return [`\u{1F4BE} ${percent} cached | ${saved}`, `\u251C\u2500 Read: ${read}`, `\u2514\u2500 Write: ${write}`].join("\n");
|
|
1058
1889
|
}
|
|
1059
1890
|
};
|
|
1060
1891
|
|
|
1061
|
-
// src/widgets/
|
|
1062
|
-
var
|
|
1063
|
-
id = "
|
|
1892
|
+
// src/widgets/cache-metrics/cache-metrics-widget.ts
|
|
1893
|
+
var CacheMetricsWidget = class extends StdinDataWidget {
|
|
1894
|
+
id = "cache-metrics";
|
|
1064
1895
|
metadata = createWidgetMetadata(
|
|
1065
|
-
"
|
|
1066
|
-
"
|
|
1896
|
+
"Cache Metrics",
|
|
1897
|
+
"Cache hit rate and savings display",
|
|
1067
1898
|
"1.0.0",
|
|
1068
1899
|
"claude-scope",
|
|
1069
|
-
|
|
1070
|
-
//
|
|
1900
|
+
2
|
|
1901
|
+
// Third line
|
|
1071
1902
|
);
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1903
|
+
theme;
|
|
1904
|
+
style = "balanced";
|
|
1905
|
+
renderData;
|
|
1906
|
+
constructor(theme) {
|
|
1907
|
+
super();
|
|
1908
|
+
this.theme = theme ?? DEFAULT_THEME;
|
|
1909
|
+
}
|
|
1078
1910
|
/**
|
|
1079
|
-
*
|
|
1080
|
-
* If not provided, uses default createGit (production)
|
|
1081
|
-
* Tests can inject MockGit factory here
|
|
1082
|
-
* @param colors - Optional theme colors
|
|
1911
|
+
* Set display style
|
|
1083
1912
|
*/
|
|
1084
|
-
|
|
1085
|
-
this.
|
|
1086
|
-
this.colors = colors ?? DEFAULT_THEME;
|
|
1913
|
+
setStyle(style) {
|
|
1914
|
+
this.style = style;
|
|
1087
1915
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1916
|
+
/**
|
|
1917
|
+
* Calculate cache metrics from context usage data
|
|
1918
|
+
* Returns null if no usage data is available
|
|
1919
|
+
*/
|
|
1920
|
+
calculateMetrics(data) {
|
|
1921
|
+
const usage = data.context_window?.current_usage;
|
|
1922
|
+
if (!usage) {
|
|
1923
|
+
return null;
|
|
1092
1924
|
}
|
|
1925
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
1926
|
+
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
|
1927
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
1928
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
1929
|
+
const totalTokens = inputTokens + outputTokens;
|
|
1930
|
+
const hitRate = inputTokens > 0 ? Math.round(cacheRead / inputTokens * 100) : 0;
|
|
1931
|
+
const costPerToken = 3e-6;
|
|
1932
|
+
const savings = cacheRead * 0.9 * costPerToken;
|
|
1933
|
+
return {
|
|
1934
|
+
cacheRead,
|
|
1935
|
+
cacheWrite,
|
|
1936
|
+
totalTokens,
|
|
1937
|
+
hitRate,
|
|
1938
|
+
savings
|
|
1939
|
+
};
|
|
1093
1940
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1941
|
+
/**
|
|
1942
|
+
* Update widget with new data and calculate metrics
|
|
1943
|
+
*/
|
|
1944
|
+
async update(data) {
|
|
1945
|
+
await super.update(data);
|
|
1946
|
+
const metrics = this.calculateMetrics(data);
|
|
1947
|
+
this.renderData = metrics ?? void 0;
|
|
1096
1948
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
const latestTag = await (this.git.latestTag?.() ?? Promise.resolve(null));
|
|
1103
|
-
const renderData = { tag: latestTag };
|
|
1104
|
-
return this.styleFn(renderData, this.colors.git);
|
|
1105
|
-
} catch {
|
|
1949
|
+
/**
|
|
1950
|
+
* Render the cache metrics display
|
|
1951
|
+
*/
|
|
1952
|
+
renderWithData(_data, _context) {
|
|
1953
|
+
if (!this.renderData) {
|
|
1106
1954
|
return null;
|
|
1107
1955
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
this.cwd = data.cwd;
|
|
1112
|
-
this.git = this.gitFactory(data.cwd);
|
|
1956
|
+
const styleFn = cacheMetricsStyles[this.style] ?? cacheMetricsStyles.balanced;
|
|
1957
|
+
if (!styleFn) {
|
|
1958
|
+
return null;
|
|
1113
1959
|
}
|
|
1960
|
+
return styleFn(this.renderData, this.theme);
|
|
1114
1961
|
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Widget is enabled when we have cache metrics data
|
|
1964
|
+
*/
|
|
1115
1965
|
isEnabled() {
|
|
1116
|
-
return this.
|
|
1117
|
-
}
|
|
1118
|
-
async cleanup() {
|
|
1966
|
+
return this.renderData !== void 0;
|
|
1119
1967
|
}
|
|
1120
1968
|
};
|
|
1121
1969
|
|
|
1122
|
-
// src/
|
|
1123
|
-
var
|
|
1970
|
+
// src/core/style-types.ts
|
|
1971
|
+
var DEFAULT_WIDGET_STYLE = "balanced";
|
|
1972
|
+
|
|
1973
|
+
// src/providers/config-provider.ts
|
|
1974
|
+
var fs = __toESM(require("fs/promises"), 1);
|
|
1975
|
+
var os = __toESM(require("os"), 1);
|
|
1976
|
+
var path = __toESM(require("path"), 1);
|
|
1977
|
+
var ConfigProvider = class {
|
|
1978
|
+
cachedCounts;
|
|
1979
|
+
lastScan = 0;
|
|
1980
|
+
cacheInterval = 5e3;
|
|
1981
|
+
// 5 seconds
|
|
1124
1982
|
/**
|
|
1125
|
-
*
|
|
1983
|
+
* Get config counts with hybrid caching
|
|
1984
|
+
* Scans filesystem if cache is stale (>5 seconds)
|
|
1126
1985
|
*/
|
|
1127
|
-
|
|
1986
|
+
async getConfigs(options = {}) {
|
|
1987
|
+
const now = Date.now();
|
|
1988
|
+
if (this.cachedCounts && now - this.lastScan < this.cacheInterval) {
|
|
1989
|
+
return this.cachedCounts;
|
|
1990
|
+
}
|
|
1991
|
+
this.cachedCounts = await this.scanConfigs(options);
|
|
1992
|
+
this.lastScan = now;
|
|
1993
|
+
return this.cachedCounts;
|
|
1994
|
+
}
|
|
1128
1995
|
/**
|
|
1129
|
-
*
|
|
1996
|
+
* Scan filesystem for Claude Code configurations
|
|
1130
1997
|
*/
|
|
1131
|
-
|
|
1998
|
+
async scanConfigs(options) {
|
|
1999
|
+
let claudeMdCount = 0;
|
|
2000
|
+
let rulesCount = 0;
|
|
2001
|
+
let mcpCount = 0;
|
|
2002
|
+
let hooksCount = 0;
|
|
2003
|
+
const homeDir = os.homedir();
|
|
2004
|
+
const claudeDir = path.join(homeDir, ".claude");
|
|
2005
|
+
const cwd = options.cwd;
|
|
2006
|
+
if (await this.fileExists(path.join(claudeDir, "CLAUDE.md"))) {
|
|
2007
|
+
claudeMdCount++;
|
|
2008
|
+
}
|
|
2009
|
+
rulesCount += await this.countRulesInDir(path.join(claudeDir, "rules"));
|
|
2010
|
+
const userSettings = path.join(claudeDir, "settings.json");
|
|
2011
|
+
const userSettingsData = await this.readJsonFile(userSettings);
|
|
2012
|
+
if (userSettingsData) {
|
|
2013
|
+
mcpCount += this.countMcpServers(userSettingsData);
|
|
2014
|
+
hooksCount += this.countHooks(userSettingsData);
|
|
2015
|
+
}
|
|
2016
|
+
const userClaudeJson = path.join(homeDir, ".claude.json");
|
|
2017
|
+
const userClaudeData = await this.readJsonFile(userClaudeJson);
|
|
2018
|
+
if (userClaudeData) {
|
|
2019
|
+
const userMcpCount = this.countMcpServers(userClaudeData);
|
|
2020
|
+
mcpCount += Math.max(0, userMcpCount - this.countMcpServers(userSettingsData || {}));
|
|
2021
|
+
}
|
|
2022
|
+
if (cwd) {
|
|
2023
|
+
if (await this.fileExists(path.join(cwd, "CLAUDE.md"))) {
|
|
2024
|
+
claudeMdCount++;
|
|
2025
|
+
}
|
|
2026
|
+
if (await this.fileExists(path.join(cwd, "CLAUDE.local.md"))) {
|
|
2027
|
+
claudeMdCount++;
|
|
2028
|
+
}
|
|
2029
|
+
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.md"))) {
|
|
2030
|
+
claudeMdCount++;
|
|
2031
|
+
}
|
|
2032
|
+
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.local.md"))) {
|
|
2033
|
+
claudeMdCount++;
|
|
2034
|
+
}
|
|
2035
|
+
rulesCount += await this.countRulesInDir(path.join(cwd, ".claude", "rules"));
|
|
2036
|
+
const mcpJson = path.join(cwd, ".mcp.json");
|
|
2037
|
+
const mcpData = await this.readJsonFile(mcpJson);
|
|
2038
|
+
if (mcpData) {
|
|
2039
|
+
mcpCount += this.countMcpServers(mcpData);
|
|
2040
|
+
}
|
|
2041
|
+
const projectSettings = path.join(cwd, ".claude", "settings.json");
|
|
2042
|
+
const projectSettingsData = await this.readJsonFile(projectSettings);
|
|
2043
|
+
if (projectSettingsData) {
|
|
2044
|
+
mcpCount += this.countMcpServers(projectSettingsData);
|
|
2045
|
+
hooksCount += this.countHooks(projectSettingsData);
|
|
2046
|
+
}
|
|
2047
|
+
const localSettings = path.join(cwd, ".claude", "settings.local.json");
|
|
2048
|
+
const localSettingsData = await this.readJsonFile(localSettings);
|
|
2049
|
+
if (localSettingsData) {
|
|
2050
|
+
mcpCount += this.countMcpServers(localSettingsData);
|
|
2051
|
+
hooksCount += this.countHooks(localSettingsData);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
return { claudeMdCount, rulesCount, mcpCount, hooksCount };
|
|
2055
|
+
}
|
|
1132
2056
|
/**
|
|
1133
|
-
*
|
|
1134
|
-
* @param context - Widget initialization context
|
|
2057
|
+
* Check if file exists
|
|
1135
2058
|
*/
|
|
1136
|
-
async
|
|
1137
|
-
|
|
2059
|
+
async fileExists(filePath) {
|
|
2060
|
+
try {
|
|
2061
|
+
await fs.access(filePath);
|
|
2062
|
+
return true;
|
|
2063
|
+
} catch {
|
|
2064
|
+
return false;
|
|
2065
|
+
}
|
|
1138
2066
|
}
|
|
1139
2067
|
/**
|
|
1140
|
-
*
|
|
1141
|
-
* @param data - Stdin data from Claude Code
|
|
2068
|
+
* Read and parse JSON file
|
|
1142
2069
|
*/
|
|
1143
|
-
async
|
|
1144
|
-
|
|
2070
|
+
async readJsonFile(filePath) {
|
|
2071
|
+
try {
|
|
2072
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
2073
|
+
return JSON.parse(content);
|
|
2074
|
+
} catch {
|
|
2075
|
+
return null;
|
|
2076
|
+
}
|
|
1145
2077
|
}
|
|
1146
2078
|
/**
|
|
1147
|
-
*
|
|
1148
|
-
* @returns Stored stdin data
|
|
1149
|
-
* @throws Error if data has not been initialized (update not called)
|
|
2079
|
+
* Count MCP servers in config object
|
|
1150
2080
|
*/
|
|
1151
|
-
|
|
1152
|
-
if (!
|
|
1153
|
-
|
|
2081
|
+
countMcpServers(config) {
|
|
2082
|
+
if (!config || !config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2083
|
+
return 0;
|
|
1154
2084
|
}
|
|
1155
|
-
return
|
|
2085
|
+
return Object.keys(config.mcpServers).length;
|
|
1156
2086
|
}
|
|
1157
2087
|
/**
|
|
1158
|
-
*
|
|
1159
|
-
* @returns true if widget should render
|
|
2088
|
+
* Count hooks in config object
|
|
1160
2089
|
*/
|
|
1161
|
-
|
|
1162
|
-
|
|
2090
|
+
countHooks(config) {
|
|
2091
|
+
if (!config || !config.hooks || typeof config.hooks !== "object") {
|
|
2092
|
+
return 0;
|
|
2093
|
+
}
|
|
2094
|
+
return Object.keys(config.hooks).length;
|
|
1163
2095
|
}
|
|
1164
2096
|
/**
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1167
|
-
* Handles null data checks and calls renderWithData() hook.
|
|
1168
|
-
*
|
|
1169
|
-
* @param context - Render context
|
|
1170
|
-
* @returns Rendered string, or null if widget should not display
|
|
2097
|
+
* Recursively count .md files in directory
|
|
1171
2098
|
*/
|
|
1172
|
-
async
|
|
1173
|
-
|
|
1174
|
-
|
|
2099
|
+
async countRulesInDir(rulesDir) {
|
|
2100
|
+
const exists = await this.fileExists(rulesDir);
|
|
2101
|
+
if (!exists) return 0;
|
|
2102
|
+
try {
|
|
2103
|
+
let count = 0;
|
|
2104
|
+
const entries = await fs.readdir(rulesDir, { withFileTypes: true });
|
|
2105
|
+
for (const entry of entries) {
|
|
2106
|
+
const fullPath = path.join(rulesDir, entry.name);
|
|
2107
|
+
if (entry.isDirectory()) {
|
|
2108
|
+
count += await this.countRulesInDir(fullPath);
|
|
2109
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2110
|
+
count++;
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
return count;
|
|
2114
|
+
} catch {
|
|
2115
|
+
return 0;
|
|
1175
2116
|
}
|
|
1176
|
-
return this.renderWithData(this.data, context);
|
|
1177
2117
|
}
|
|
1178
2118
|
};
|
|
1179
2119
|
|
|
1180
|
-
// src/widgets/
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
if (
|
|
1192
|
-
|
|
2120
|
+
// src/widgets/config-count/styles.ts
|
|
2121
|
+
var configCountStyles = {
|
|
2122
|
+
balanced: (data) => {
|
|
2123
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2124
|
+
const parts = [];
|
|
2125
|
+
if (claudeMdCount > 0) {
|
|
2126
|
+
parts.push(`CLAUDE.md:${claudeMdCount}`);
|
|
2127
|
+
}
|
|
2128
|
+
if (rulesCount > 0) {
|
|
2129
|
+
parts.push(`rules:${rulesCount}`);
|
|
2130
|
+
}
|
|
2131
|
+
if (mcpCount > 0) {
|
|
2132
|
+
parts.push(`MCPs:${mcpCount}`);
|
|
2133
|
+
}
|
|
2134
|
+
if (hooksCount > 0) {
|
|
2135
|
+
parts.push(`hooks:${hooksCount}`);
|
|
2136
|
+
}
|
|
2137
|
+
return parts.join(" \u2502 ");
|
|
1193
2138
|
},
|
|
1194
|
-
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1197
|
-
|
|
2139
|
+
compact: (data) => {
|
|
2140
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2141
|
+
const parts = [];
|
|
2142
|
+
if (claudeMdCount > 0) {
|
|
2143
|
+
parts.push(`${claudeMdCount} docs`);
|
|
2144
|
+
}
|
|
2145
|
+
if (rulesCount > 0) {
|
|
2146
|
+
parts.push(`${rulesCount} rules`);
|
|
2147
|
+
}
|
|
2148
|
+
if (mcpCount > 0) {
|
|
2149
|
+
parts.push(`${mcpCount} MCPs`);
|
|
2150
|
+
}
|
|
2151
|
+
if (hooksCount > 0) {
|
|
2152
|
+
const hookLabel = hooksCount === 1 ? "hook" : "hooks";
|
|
2153
|
+
parts.push(`${hooksCount} ${hookLabel}`);
|
|
2154
|
+
}
|
|
2155
|
+
return parts.join(" \u2502 ");
|
|
1198
2156
|
},
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
const
|
|
1202
|
-
if (
|
|
1203
|
-
|
|
2157
|
+
playful: (data) => {
|
|
2158
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2159
|
+
const parts = [];
|
|
2160
|
+
if (claudeMdCount > 0) {
|
|
2161
|
+
parts.push(`\u{1F4C4} CLAUDE.md:${claudeMdCount}`);
|
|
1204
2162
|
}
|
|
1205
|
-
|
|
2163
|
+
if (rulesCount > 0) {
|
|
2164
|
+
parts.push(`\u{1F4DC} rules:${rulesCount}`);
|
|
2165
|
+
}
|
|
2166
|
+
if (mcpCount > 0) {
|
|
2167
|
+
parts.push(`\u{1F50C} MCPs:${mcpCount}`);
|
|
2168
|
+
}
|
|
2169
|
+
if (hooksCount > 0) {
|
|
2170
|
+
parts.push(`\u{1FA9D} hooks:${hooksCount}`);
|
|
2171
|
+
}
|
|
2172
|
+
return parts.join(" \u2502 ");
|
|
1206
2173
|
},
|
|
1207
|
-
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
if (
|
|
1220
|
-
|
|
2174
|
+
verbose: (data) => {
|
|
2175
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2176
|
+
const parts = [];
|
|
2177
|
+
if (claudeMdCount > 0) {
|
|
2178
|
+
parts.push(`${claudeMdCount} CLAUDE.md`);
|
|
2179
|
+
}
|
|
2180
|
+
if (rulesCount > 0) {
|
|
2181
|
+
parts.push(`${rulesCount} rules`);
|
|
2182
|
+
}
|
|
2183
|
+
if (mcpCount > 0) {
|
|
2184
|
+
parts.push(`${mcpCount} MCP servers`);
|
|
2185
|
+
}
|
|
2186
|
+
if (hooksCount > 0) {
|
|
2187
|
+
parts.push(`${hooksCount} hook`);
|
|
2188
|
+
}
|
|
2189
|
+
return parts.join(" \u2502 ");
|
|
1221
2190
|
}
|
|
1222
2191
|
};
|
|
1223
2192
|
|
|
1224
|
-
// src/widgets/
|
|
1225
|
-
var
|
|
1226
|
-
id = "
|
|
2193
|
+
// src/widgets/config-count-widget.ts
|
|
2194
|
+
var ConfigCountWidget = class {
|
|
2195
|
+
id = "config-count";
|
|
1227
2196
|
metadata = createWidgetMetadata(
|
|
1228
|
-
"
|
|
1229
|
-
"Displays
|
|
2197
|
+
"Config Count",
|
|
2198
|
+
"Displays Claude Code configuration counts",
|
|
1230
2199
|
"1.0.0",
|
|
1231
2200
|
"claude-scope",
|
|
1232
|
-
|
|
1233
|
-
//
|
|
2201
|
+
1
|
|
2202
|
+
// Second line
|
|
1234
2203
|
);
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
setStyle(style = "balanced") {
|
|
1242
|
-
const fn = modelStyles[style];
|
|
2204
|
+
configProvider = new ConfigProvider();
|
|
2205
|
+
configs;
|
|
2206
|
+
cwd;
|
|
2207
|
+
styleFn = configCountStyles.balanced;
|
|
2208
|
+
setStyle(style = DEFAULT_WIDGET_STYLE) {
|
|
2209
|
+
const fn = configCountStyles[style];
|
|
1243
2210
|
if (fn) {
|
|
1244
2211
|
this.styleFn = fn;
|
|
1245
2212
|
}
|
|
1246
2213
|
}
|
|
1247
|
-
|
|
2214
|
+
async initialize() {
|
|
2215
|
+
}
|
|
2216
|
+
async update(data) {
|
|
2217
|
+
this.cwd = data.cwd;
|
|
2218
|
+
this.configs = await this.configProvider.getConfigs({ cwd: data.cwd });
|
|
2219
|
+
}
|
|
2220
|
+
isEnabled() {
|
|
2221
|
+
if (!this.configs) {
|
|
2222
|
+
return false;
|
|
2223
|
+
}
|
|
2224
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
2225
|
+
return claudeMdCount > 0 || rulesCount > 0 || mcpCount > 0 || hooksCount > 0;
|
|
2226
|
+
}
|
|
2227
|
+
async render(context) {
|
|
2228
|
+
if (!this.configs) {
|
|
2229
|
+
return null;
|
|
2230
|
+
}
|
|
2231
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
1248
2232
|
const renderData = {
|
|
1249
|
-
|
|
1250
|
-
|
|
2233
|
+
claudeMdCount,
|
|
2234
|
+
rulesCount,
|
|
2235
|
+
mcpCount,
|
|
2236
|
+
hooksCount
|
|
1251
2237
|
};
|
|
1252
|
-
return this.styleFn(renderData
|
|
2238
|
+
return this.styleFn(renderData);
|
|
2239
|
+
}
|
|
2240
|
+
async cleanup() {
|
|
1253
2241
|
}
|
|
1254
2242
|
};
|
|
1255
2243
|
|
|
2244
|
+
// src/ui/utils/style-utils.ts
|
|
2245
|
+
function withLabel(prefix, value) {
|
|
2246
|
+
if (prefix === "") return value;
|
|
2247
|
+
return `${prefix}: ${value}`;
|
|
2248
|
+
}
|
|
2249
|
+
function withIndicator(value) {
|
|
2250
|
+
return `\u25CF ${value}`;
|
|
2251
|
+
}
|
|
2252
|
+
function progressBar(percent, width = 10) {
|
|
2253
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
2254
|
+
const filled = Math.round(clamped / 100 * width);
|
|
2255
|
+
const empty = width - filled;
|
|
2256
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
2257
|
+
}
|
|
2258
|
+
|
|
1256
2259
|
// src/widgets/context/styles.ts
|
|
1257
2260
|
function getContextColor(percent, colors) {
|
|
1258
2261
|
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
@@ -1440,83 +2443,6 @@ var CostWidget = class extends StdinDataWidget {
|
|
|
1440
2443
|
}
|
|
1441
2444
|
};
|
|
1442
2445
|
|
|
1443
|
-
// src/widgets/lines/styles.ts
|
|
1444
|
-
var linesStyles = {
|
|
1445
|
-
balanced: (data, colors) => {
|
|
1446
|
-
if (!colors) return `+${data.added}/-${data.removed}`;
|
|
1447
|
-
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
1448
|
-
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
1449
|
-
return `${addedStr}/${removedStr}`;
|
|
1450
|
-
},
|
|
1451
|
-
compact: (data, colors) => {
|
|
1452
|
-
if (!colors) return `+${data.added}-${data.removed}`;
|
|
1453
|
-
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
1454
|
-
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
1455
|
-
return `${addedStr}${removedStr}`;
|
|
1456
|
-
},
|
|
1457
|
-
playful: (data, colors) => {
|
|
1458
|
-
if (!colors) return `\u2795${data.added} \u2796${data.removed}`;
|
|
1459
|
-
const addedStr = colorize(`\u2795${data.added}`, colors.added);
|
|
1460
|
-
const removedStr = colorize(`\u2796${data.removed}`, colors.removed);
|
|
1461
|
-
return `${addedStr} ${removedStr}`;
|
|
1462
|
-
},
|
|
1463
|
-
verbose: (data, colors) => {
|
|
1464
|
-
const parts = [];
|
|
1465
|
-
if (data.added > 0) {
|
|
1466
|
-
const text = `+${data.added} added`;
|
|
1467
|
-
parts.push(colors ? colorize(text, colors.added) : text);
|
|
1468
|
-
}
|
|
1469
|
-
if (data.removed > 0) {
|
|
1470
|
-
const text = `-${data.removed} removed`;
|
|
1471
|
-
parts.push(colors ? colorize(text, colors.removed) : text);
|
|
1472
|
-
}
|
|
1473
|
-
return parts.join(", ");
|
|
1474
|
-
},
|
|
1475
|
-
labeled: (data, colors) => {
|
|
1476
|
-
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
1477
|
-
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
1478
|
-
const lines = `${addedStr}/${removedStr}`;
|
|
1479
|
-
return withLabel("Lines", lines);
|
|
1480
|
-
},
|
|
1481
|
-
indicator: (data, colors) => {
|
|
1482
|
-
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
1483
|
-
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
1484
|
-
const lines = `${addedStr}/${removedStr}`;
|
|
1485
|
-
return withIndicator(lines);
|
|
1486
|
-
}
|
|
1487
|
-
};
|
|
1488
|
-
|
|
1489
|
-
// src/widgets/lines-widget.ts
|
|
1490
|
-
var LinesWidget = class extends StdinDataWidget {
|
|
1491
|
-
id = "lines";
|
|
1492
|
-
metadata = createWidgetMetadata(
|
|
1493
|
-
"Lines",
|
|
1494
|
-
"Displays lines added/removed in session",
|
|
1495
|
-
"1.0.0",
|
|
1496
|
-
"claude-scope",
|
|
1497
|
-
0
|
|
1498
|
-
// First line
|
|
1499
|
-
);
|
|
1500
|
-
colors;
|
|
1501
|
-
styleFn = linesStyles.balanced;
|
|
1502
|
-
constructor(colors) {
|
|
1503
|
-
super();
|
|
1504
|
-
this.colors = colors ?? DEFAULT_THEME;
|
|
1505
|
-
}
|
|
1506
|
-
setStyle(style = "balanced") {
|
|
1507
|
-
const fn = linesStyles[style];
|
|
1508
|
-
if (fn) {
|
|
1509
|
-
this.styleFn = fn;
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
renderWithData(data, _context) {
|
|
1513
|
-
const added = data.cost?.total_lines_added ?? 0;
|
|
1514
|
-
const removed = data.cost?.total_lines_removed ?? 0;
|
|
1515
|
-
const renderData = { added, removed };
|
|
1516
|
-
return this.styleFn(renderData, this.colors.lines);
|
|
1517
|
-
}
|
|
1518
|
-
};
|
|
1519
|
-
|
|
1520
2446
|
// src/widgets/duration/styles.ts
|
|
1521
2447
|
var durationStyles = {
|
|
1522
2448
|
balanced: (data, colors) => {
|
|
@@ -1629,277 +2555,505 @@ var DurationWidget = class extends StdinDataWidget {
|
|
|
1629
2555
|
}
|
|
1630
2556
|
};
|
|
1631
2557
|
|
|
1632
|
-
// src/
|
|
1633
|
-
var
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
2558
|
+
// src/widgets/empty-line-widget.ts
|
|
2559
|
+
var EmptyLineWidget = class extends StdinDataWidget {
|
|
2560
|
+
id = "empty-line";
|
|
2561
|
+
metadata = createWidgetMetadata(
|
|
2562
|
+
"Empty Line",
|
|
2563
|
+
"Empty line separator",
|
|
2564
|
+
"1.0.0",
|
|
2565
|
+
"claude-scope",
|
|
2566
|
+
5
|
|
2567
|
+
// Sixth line (0-indexed)
|
|
2568
|
+
);
|
|
1641
2569
|
/**
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
2570
|
+
* All styles return the same value (Braille Pattern Blank).
|
|
2571
|
+
* This method exists for API consistency with other widgets.
|
|
1644
2572
|
*/
|
|
1645
|
-
|
|
1646
|
-
const now = Date.now();
|
|
1647
|
-
if (this.cachedCounts && now - this.lastScan < this.cacheInterval) {
|
|
1648
|
-
return this.cachedCounts;
|
|
1649
|
-
}
|
|
1650
|
-
this.cachedCounts = await this.scanConfigs(options);
|
|
1651
|
-
this.lastScan = now;
|
|
1652
|
-
return this.cachedCounts;
|
|
2573
|
+
setStyle(_style) {
|
|
1653
2574
|
}
|
|
1654
2575
|
/**
|
|
1655
|
-
*
|
|
2576
|
+
* Return Braille Pattern Blank to create a visible empty separator line.
|
|
2577
|
+
* U+2800 occupies cell width but appears blank, ensuring the line renders.
|
|
1656
2578
|
*/
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
2579
|
+
renderWithData(_data, _context) {
|
|
2580
|
+
return "\u2800";
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2584
|
+
// src/providers/git-provider.ts
|
|
2585
|
+
var import_node_child_process = require("node:child_process");
|
|
2586
|
+
var import_node_util = require("node:util");
|
|
2587
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
2588
|
+
var NativeGit = class {
|
|
2589
|
+
cwd;
|
|
2590
|
+
constructor(cwd) {
|
|
2591
|
+
this.cwd = cwd;
|
|
2592
|
+
}
|
|
2593
|
+
async status() {
|
|
2594
|
+
try {
|
|
2595
|
+
const { stdout } = await execFileAsync("git", ["status", "--branch", "--short"], {
|
|
2596
|
+
cwd: this.cwd
|
|
2597
|
+
});
|
|
2598
|
+
const match = stdout.match(/^##\s+(\S+)/m);
|
|
2599
|
+
const current = match ? match[1] : null;
|
|
2600
|
+
return { current };
|
|
2601
|
+
} catch {
|
|
2602
|
+
return { current: null };
|
|
1667
2603
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
const
|
|
1671
|
-
if (
|
|
1672
|
-
|
|
1673
|
-
hooksCount += this.countHooks(userSettingsData);
|
|
2604
|
+
}
|
|
2605
|
+
async diffSummary(options) {
|
|
2606
|
+
const args = ["diff", "--shortstat"];
|
|
2607
|
+
if (options) {
|
|
2608
|
+
args.push(...options);
|
|
1674
2609
|
}
|
|
1675
|
-
const userClaudeJson = path.join(homeDir, ".claude.json");
|
|
1676
|
-
const userClaudeData = await this.readJsonFile(userClaudeJson);
|
|
1677
|
-
if (userClaudeData) {
|
|
1678
|
-
const userMcpCount = this.countMcpServers(userClaudeData);
|
|
1679
|
-
mcpCount += Math.max(0, userMcpCount - this.countMcpServers(userSettingsData || {}));
|
|
1680
|
-
}
|
|
1681
|
-
if (cwd) {
|
|
1682
|
-
if (await this.fileExists(path.join(cwd, "CLAUDE.md"))) {
|
|
1683
|
-
claudeMdCount++;
|
|
1684
|
-
}
|
|
1685
|
-
if (await this.fileExists(path.join(cwd, "CLAUDE.local.md"))) {
|
|
1686
|
-
claudeMdCount++;
|
|
1687
|
-
}
|
|
1688
|
-
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.md"))) {
|
|
1689
|
-
claudeMdCount++;
|
|
1690
|
-
}
|
|
1691
|
-
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.local.md"))) {
|
|
1692
|
-
claudeMdCount++;
|
|
1693
|
-
}
|
|
1694
|
-
rulesCount += await this.countRulesInDir(path.join(cwd, ".claude", "rules"));
|
|
1695
|
-
const mcpJson = path.join(cwd, ".mcp.json");
|
|
1696
|
-
const mcpData = await this.readJsonFile(mcpJson);
|
|
1697
|
-
if (mcpData) {
|
|
1698
|
-
mcpCount += this.countMcpServers(mcpData);
|
|
1699
|
-
}
|
|
1700
|
-
const projectSettings = path.join(cwd, ".claude", "settings.json");
|
|
1701
|
-
const projectSettingsData = await this.readJsonFile(projectSettings);
|
|
1702
|
-
if (projectSettingsData) {
|
|
1703
|
-
mcpCount += this.countMcpServers(projectSettingsData);
|
|
1704
|
-
hooksCount += this.countHooks(projectSettingsData);
|
|
1705
|
-
}
|
|
1706
|
-
const localSettings = path.join(cwd, ".claude", "settings.local.json");
|
|
1707
|
-
const localSettingsData = await this.readJsonFile(localSettings);
|
|
1708
|
-
if (localSettingsData) {
|
|
1709
|
-
mcpCount += this.countMcpServers(localSettingsData);
|
|
1710
|
-
hooksCount += this.countHooks(localSettingsData);
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
return { claudeMdCount, rulesCount, mcpCount, hooksCount };
|
|
1714
|
-
}
|
|
1715
|
-
/**
|
|
1716
|
-
* Check if file exists
|
|
1717
|
-
*/
|
|
1718
|
-
async fileExists(filePath) {
|
|
1719
2610
|
try {
|
|
1720
|
-
await
|
|
1721
|
-
|
|
2611
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
2612
|
+
cwd: this.cwd
|
|
2613
|
+
});
|
|
2614
|
+
const fileMatch = stdout.match(/(\d+)\s+file(s?)\s+changed/);
|
|
2615
|
+
const insertionMatch = stdout.match(/(\d+)\s+insertion/);
|
|
2616
|
+
const deletionMatch = stdout.match(/(\d+)\s+deletion/);
|
|
2617
|
+
const fileCount = fileMatch ? parseInt(fileMatch[1], 10) : 0;
|
|
2618
|
+
const insertions = insertionMatch ? parseInt(insertionMatch[1], 10) : 0;
|
|
2619
|
+
const deletions = deletionMatch ? parseInt(deletionMatch[1], 10) : 0;
|
|
2620
|
+
const files = insertions > 0 || deletions > 0 ? [{ file: "(total)", insertions, deletions }] : [];
|
|
2621
|
+
return { fileCount, files };
|
|
1722
2622
|
} catch {
|
|
1723
|
-
return
|
|
2623
|
+
return { fileCount: 0, files: [] };
|
|
1724
2624
|
}
|
|
1725
2625
|
}
|
|
1726
|
-
|
|
1727
|
-
* Read and parse JSON file
|
|
1728
|
-
*/
|
|
1729
|
-
async readJsonFile(filePath) {
|
|
2626
|
+
async latestTag() {
|
|
1730
2627
|
try {
|
|
1731
|
-
const
|
|
1732
|
-
|
|
2628
|
+
const { stdout } = await execFileAsync("git", ["describe", "--tags", "--abbrev=0"], {
|
|
2629
|
+
cwd: this.cwd
|
|
2630
|
+
});
|
|
2631
|
+
return stdout.trim();
|
|
1733
2632
|
} catch {
|
|
1734
2633
|
return null;
|
|
1735
2634
|
}
|
|
1736
2635
|
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2636
|
+
};
|
|
2637
|
+
function createGit(cwd) {
|
|
2638
|
+
return new NativeGit(cwd);
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
// src/widgets/git-tag/styles.ts
|
|
2642
|
+
var gitTagStyles = {
|
|
2643
|
+
balanced: (data, colors) => {
|
|
2644
|
+
const tag = data.tag || "\u2014";
|
|
2645
|
+
if (!colors) return tag;
|
|
2646
|
+
return colorize(tag, colors.branch);
|
|
2647
|
+
},
|
|
2648
|
+
compact: (data, colors) => {
|
|
2649
|
+
if (!data.tag) return "\u2014";
|
|
2650
|
+
const tag = data.tag.replace(/^v/, "");
|
|
2651
|
+
if (!colors) return tag;
|
|
2652
|
+
return colorize(tag, colors.branch);
|
|
2653
|
+
},
|
|
2654
|
+
playful: (data, colors) => {
|
|
2655
|
+
const tag = data.tag || "\u2014";
|
|
2656
|
+
if (!colors) return `\u{1F3F7}\uFE0F ${tag}`;
|
|
2657
|
+
return `\u{1F3F7}\uFE0F ${colorize(tag, colors.branch)}`;
|
|
2658
|
+
},
|
|
2659
|
+
verbose: (data, colors) => {
|
|
2660
|
+
if (!data.tag) return "version: none";
|
|
2661
|
+
const tag = `version ${data.tag}`;
|
|
2662
|
+
if (!colors) return tag;
|
|
2663
|
+
return `version ${colorize(data.tag, colors.branch)}`;
|
|
2664
|
+
},
|
|
2665
|
+
labeled: (data, colors) => {
|
|
2666
|
+
const tag = data.tag || "none";
|
|
2667
|
+
if (!colors) return withLabel("Tag", tag);
|
|
2668
|
+
return withLabel("Tag", colorize(tag, colors.branch));
|
|
2669
|
+
},
|
|
2670
|
+
indicator: (data, colors) => {
|
|
2671
|
+
const tag = data.tag || "\u2014";
|
|
2672
|
+
if (!colors) return withIndicator(tag);
|
|
2673
|
+
return withIndicator(colorize(tag, colors.branch));
|
|
1745
2674
|
}
|
|
2675
|
+
};
|
|
2676
|
+
|
|
2677
|
+
// src/widgets/git/git-tag-widget.ts
|
|
2678
|
+
var GitTagWidget = class {
|
|
2679
|
+
id = "git-tag";
|
|
2680
|
+
metadata = createWidgetMetadata(
|
|
2681
|
+
"Git Tag Widget",
|
|
2682
|
+
"Displays the latest git tag",
|
|
2683
|
+
"1.0.0",
|
|
2684
|
+
"claude-scope",
|
|
2685
|
+
1
|
|
2686
|
+
// Second line
|
|
2687
|
+
);
|
|
2688
|
+
gitFactory;
|
|
2689
|
+
git = null;
|
|
2690
|
+
enabled = true;
|
|
2691
|
+
cwd = null;
|
|
2692
|
+
colors;
|
|
2693
|
+
styleFn = gitTagStyles.balanced;
|
|
1746
2694
|
/**
|
|
1747
|
-
*
|
|
2695
|
+
* @param gitFactory - Optional factory function for creating IGit instances
|
|
2696
|
+
* If not provided, uses default createGit (production)
|
|
2697
|
+
* Tests can inject MockGit factory here
|
|
2698
|
+
* @param colors - Optional theme colors
|
|
1748
2699
|
*/
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
2700
|
+
constructor(gitFactory, colors) {
|
|
2701
|
+
this.gitFactory = gitFactory || createGit;
|
|
2702
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2703
|
+
}
|
|
2704
|
+
setStyle(style = "balanced") {
|
|
2705
|
+
const fn = gitTagStyles[style];
|
|
2706
|
+
if (fn) {
|
|
2707
|
+
this.styleFn = fn;
|
|
1752
2708
|
}
|
|
1753
|
-
return Object.keys(config.hooks).length;
|
|
1754
2709
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
async
|
|
1759
|
-
|
|
1760
|
-
|
|
2710
|
+
async initialize(context) {
|
|
2711
|
+
this.enabled = context.config?.enabled !== false;
|
|
2712
|
+
}
|
|
2713
|
+
async render(context) {
|
|
2714
|
+
if (!this.enabled || !this.git || !this.cwd) {
|
|
2715
|
+
return null;
|
|
2716
|
+
}
|
|
1761
2717
|
try {
|
|
1762
|
-
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
-
const fullPath = path.join(rulesDir, entry.name);
|
|
1766
|
-
if (entry.isDirectory()) {
|
|
1767
|
-
count += await this.countRulesInDir(fullPath);
|
|
1768
|
-
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1769
|
-
count++;
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
return count;
|
|
2718
|
+
const latestTag = await (this.git.latestTag?.() ?? Promise.resolve(null));
|
|
2719
|
+
const renderData = { tag: latestTag };
|
|
2720
|
+
return this.styleFn(renderData, this.colors.git);
|
|
1773
2721
|
} catch {
|
|
1774
|
-
return
|
|
2722
|
+
return null;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
async update(data) {
|
|
2726
|
+
if (data.cwd !== this.cwd) {
|
|
2727
|
+
this.cwd = data.cwd;
|
|
2728
|
+
this.git = this.gitFactory(data.cwd);
|
|
1775
2729
|
}
|
|
1776
2730
|
}
|
|
2731
|
+
isEnabled() {
|
|
2732
|
+
return this.enabled;
|
|
2733
|
+
}
|
|
2734
|
+
async cleanup() {
|
|
2735
|
+
}
|
|
1777
2736
|
};
|
|
1778
2737
|
|
|
1779
|
-
// src/widgets/
|
|
1780
|
-
var
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
if (claudeMdCount > 0) {
|
|
1785
|
-
parts.push(`CLAUDE.md:${claudeMdCount}`);
|
|
1786
|
-
}
|
|
1787
|
-
if (rulesCount > 0) {
|
|
1788
|
-
parts.push(`rules:${rulesCount}`);
|
|
1789
|
-
}
|
|
1790
|
-
if (mcpCount > 0) {
|
|
1791
|
-
parts.push(`MCPs:${mcpCount}`);
|
|
1792
|
-
}
|
|
1793
|
-
if (hooksCount > 0) {
|
|
1794
|
-
parts.push(`hooks:${hooksCount}`);
|
|
1795
|
-
}
|
|
1796
|
-
return parts.join(" \u2502 ");
|
|
2738
|
+
// src/widgets/git/styles.ts
|
|
2739
|
+
var gitStyles = {
|
|
2740
|
+
minimal: (data, colors) => {
|
|
2741
|
+
if (!colors) return data.branch;
|
|
2742
|
+
return colorize(data.branch, colors.branch);
|
|
1797
2743
|
},
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
parts.push(
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
parts.push(`${mcpCount} MCPs`);
|
|
2744
|
+
balanced: (data, colors) => {
|
|
2745
|
+
if (data.changes && data.changes.files > 0) {
|
|
2746
|
+
const parts = [];
|
|
2747
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2748
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2749
|
+
if (parts.length > 0) {
|
|
2750
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2751
|
+
const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
|
|
2752
|
+
return `${branch} ${changes}`;
|
|
2753
|
+
}
|
|
1809
2754
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2755
|
+
return colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2756
|
+
},
|
|
2757
|
+
compact: (data, colors) => {
|
|
2758
|
+
if (data.changes && data.changes.files > 0) {
|
|
2759
|
+
const parts = [];
|
|
2760
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2761
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2762
|
+
if (parts.length > 0) {
|
|
2763
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2764
|
+
const changesStr = parts.join("/");
|
|
2765
|
+
return `${branch} ${changesStr}`;
|
|
2766
|
+
}
|
|
1813
2767
|
}
|
|
1814
|
-
return
|
|
2768
|
+
return colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
1815
2769
|
},
|
|
1816
|
-
playful: (data) => {
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
parts.push(`\
|
|
2770
|
+
playful: (data, colors) => {
|
|
2771
|
+
if (data.changes && data.changes.files > 0) {
|
|
2772
|
+
const parts = [];
|
|
2773
|
+
if (data.changes.insertions > 0) parts.push(`\u2B06${data.changes.insertions}`);
|
|
2774
|
+
if (data.changes.deletions > 0) parts.push(`\u2B07${data.changes.deletions}`);
|
|
2775
|
+
if (parts.length > 0) {
|
|
2776
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2777
|
+
return `\u{1F500} ${branch2} ${parts.join(" ")}`;
|
|
2778
|
+
}
|
|
1821
2779
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
2780
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2781
|
+
return `\u{1F500} ${branch}`;
|
|
2782
|
+
},
|
|
2783
|
+
verbose: (data, colors) => {
|
|
2784
|
+
if (data.changes && data.changes.files > 0) {
|
|
2785
|
+
const parts = [];
|
|
2786
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions} insertions`);
|
|
2787
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions} deletions`);
|
|
2788
|
+
if (parts.length > 0) {
|
|
2789
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2790
|
+
const changes = colors ? colorize(`[${parts.join(", ")}]`, colors.changes) : `[${parts.join(", ")}]`;
|
|
2791
|
+
return `branch: ${branch2} ${changes}`;
|
|
2792
|
+
}
|
|
1824
2793
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
2794
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2795
|
+
return `branch: ${branch} (HEAD)`;
|
|
2796
|
+
},
|
|
2797
|
+
labeled: (data, colors) => {
|
|
2798
|
+
if (data.changes && data.changes.files > 0) {
|
|
2799
|
+
const parts = [];
|
|
2800
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2801
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2802
|
+
if (parts.length > 0) {
|
|
2803
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2804
|
+
const changes = `${data.changes.files} files: ${parts.join("/")}`;
|
|
2805
|
+
return `Git: ${branch2} [${changes}]`;
|
|
2806
|
+
}
|
|
1827
2807
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
2808
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2809
|
+
return `Git: ${branch}`;
|
|
2810
|
+
},
|
|
2811
|
+
indicator: (data, colors) => {
|
|
2812
|
+
if (data.changes && data.changes.files > 0) {
|
|
2813
|
+
const parts = [];
|
|
2814
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2815
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2816
|
+
if (parts.length > 0) {
|
|
2817
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2818
|
+
const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
|
|
2819
|
+
return `\u25CF ${branch} ${changes}`;
|
|
2820
|
+
}
|
|
1830
2821
|
}
|
|
1831
|
-
return
|
|
2822
|
+
return withIndicator(colors ? colorize(data.branch, colors.branch) : data.branch);
|
|
2823
|
+
}
|
|
2824
|
+
};
|
|
2825
|
+
|
|
2826
|
+
// src/widgets/git/git-widget.ts
|
|
2827
|
+
var GitWidget = class {
|
|
2828
|
+
id = "git";
|
|
2829
|
+
metadata = createWidgetMetadata(
|
|
2830
|
+
"Git Widget",
|
|
2831
|
+
"Displays current git branch",
|
|
2832
|
+
"1.0.0",
|
|
2833
|
+
"claude-scope",
|
|
2834
|
+
0
|
|
2835
|
+
// First line
|
|
2836
|
+
);
|
|
2837
|
+
gitFactory;
|
|
2838
|
+
git = null;
|
|
2839
|
+
enabled = true;
|
|
2840
|
+
cwd = null;
|
|
2841
|
+
colors;
|
|
2842
|
+
styleFn = gitStyles.balanced;
|
|
2843
|
+
/**
|
|
2844
|
+
* @param gitFactory - Optional factory function for creating IGit instances
|
|
2845
|
+
* If not provided, uses default createGit (production)
|
|
2846
|
+
* Tests can inject MockGit factory here
|
|
2847
|
+
* @param colors - Optional theme colors
|
|
2848
|
+
*/
|
|
2849
|
+
constructor(gitFactory, colors) {
|
|
2850
|
+
this.gitFactory = gitFactory || createGit;
|
|
2851
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2852
|
+
}
|
|
2853
|
+
setStyle(style = "balanced") {
|
|
2854
|
+
const fn = gitStyles[style];
|
|
2855
|
+
if (fn) {
|
|
2856
|
+
this.styleFn = fn;
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
async initialize(context) {
|
|
2860
|
+
this.enabled = context.config?.enabled !== false;
|
|
2861
|
+
}
|
|
2862
|
+
async render(context) {
|
|
2863
|
+
if (!this.enabled || !this.git || !this.cwd) {
|
|
2864
|
+
return null;
|
|
2865
|
+
}
|
|
2866
|
+
try {
|
|
2867
|
+
const status = await this.git.status();
|
|
2868
|
+
const branch = status.current || null;
|
|
2869
|
+
if (!branch) {
|
|
2870
|
+
return null;
|
|
2871
|
+
}
|
|
2872
|
+
let changes;
|
|
2873
|
+
try {
|
|
2874
|
+
const diffSummary = await this.git.diffSummary();
|
|
2875
|
+
if (diffSummary.fileCount > 0) {
|
|
2876
|
+
let insertions = 0;
|
|
2877
|
+
let deletions = 0;
|
|
2878
|
+
for (const file of diffSummary.files) {
|
|
2879
|
+
insertions += file.insertions || 0;
|
|
2880
|
+
deletions += file.deletions || 0;
|
|
2881
|
+
}
|
|
2882
|
+
if (insertions > 0 || deletions > 0) {
|
|
2883
|
+
changes = { files: diffSummary.fileCount, insertions, deletions };
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
} catch {
|
|
2887
|
+
}
|
|
2888
|
+
const renderData = { branch, changes };
|
|
2889
|
+
return this.styleFn(renderData, this.colors.git);
|
|
2890
|
+
} catch {
|
|
2891
|
+
return null;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
async update(data) {
|
|
2895
|
+
if (data.cwd !== this.cwd) {
|
|
2896
|
+
this.cwd = data.cwd;
|
|
2897
|
+
this.git = this.gitFactory(data.cwd);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
isEnabled() {
|
|
2901
|
+
return this.enabled;
|
|
2902
|
+
}
|
|
2903
|
+
async cleanup() {
|
|
2904
|
+
}
|
|
2905
|
+
};
|
|
2906
|
+
|
|
2907
|
+
// src/widgets/lines/styles.ts
|
|
2908
|
+
var linesStyles = {
|
|
2909
|
+
balanced: (data, colors) => {
|
|
2910
|
+
if (!colors) return `+${data.added}/-${data.removed}`;
|
|
2911
|
+
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
2912
|
+
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
2913
|
+
return `${addedStr}/${removedStr}`;
|
|
1832
2914
|
},
|
|
1833
|
-
|
|
1834
|
-
|
|
2915
|
+
compact: (data, colors) => {
|
|
2916
|
+
if (!colors) return `+${data.added}-${data.removed}`;
|
|
2917
|
+
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
2918
|
+
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
2919
|
+
return `${addedStr}${removedStr}`;
|
|
2920
|
+
},
|
|
2921
|
+
playful: (data, colors) => {
|
|
2922
|
+
if (!colors) return `\u2795${data.added} \u2796${data.removed}`;
|
|
2923
|
+
const addedStr = colorize(`\u2795${data.added}`, colors.added);
|
|
2924
|
+
const removedStr = colorize(`\u2796${data.removed}`, colors.removed);
|
|
2925
|
+
return `${addedStr} ${removedStr}`;
|
|
2926
|
+
},
|
|
2927
|
+
verbose: (data, colors) => {
|
|
1835
2928
|
const parts = [];
|
|
1836
|
-
if (
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
if (rulesCount > 0) {
|
|
1840
|
-
parts.push(`${rulesCount} rules`);
|
|
2929
|
+
if (data.added > 0) {
|
|
2930
|
+
const text = `+${data.added} added`;
|
|
2931
|
+
parts.push(colors ? colorize(text, colors.added) : text);
|
|
1841
2932
|
}
|
|
1842
|
-
if (
|
|
1843
|
-
|
|
2933
|
+
if (data.removed > 0) {
|
|
2934
|
+
const text = `-${data.removed} removed`;
|
|
2935
|
+
parts.push(colors ? colorize(text, colors.removed) : text);
|
|
1844
2936
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
2937
|
+
return parts.join(", ");
|
|
2938
|
+
},
|
|
2939
|
+
labeled: (data, colors) => {
|
|
2940
|
+
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
2941
|
+
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
2942
|
+
const lines = `${addedStr}/${removedStr}`;
|
|
2943
|
+
return withLabel("Lines", lines);
|
|
2944
|
+
},
|
|
2945
|
+
indicator: (data, colors) => {
|
|
2946
|
+
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
2947
|
+
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
2948
|
+
const lines = `${addedStr}/${removedStr}`;
|
|
2949
|
+
return withIndicator(lines);
|
|
2950
|
+
}
|
|
2951
|
+
};
|
|
2952
|
+
|
|
2953
|
+
// src/widgets/lines-widget.ts
|
|
2954
|
+
var LinesWidget = class extends StdinDataWidget {
|
|
2955
|
+
id = "lines";
|
|
2956
|
+
metadata = createWidgetMetadata(
|
|
2957
|
+
"Lines",
|
|
2958
|
+
"Displays lines added/removed in session",
|
|
2959
|
+
"1.0.0",
|
|
2960
|
+
"claude-scope",
|
|
2961
|
+
0
|
|
2962
|
+
// First line
|
|
2963
|
+
);
|
|
2964
|
+
colors;
|
|
2965
|
+
styleFn = linesStyles.balanced;
|
|
2966
|
+
constructor(colors) {
|
|
2967
|
+
super();
|
|
2968
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2969
|
+
}
|
|
2970
|
+
setStyle(style = "balanced") {
|
|
2971
|
+
const fn = linesStyles[style];
|
|
2972
|
+
if (fn) {
|
|
2973
|
+
this.styleFn = fn;
|
|
1847
2974
|
}
|
|
1848
|
-
|
|
2975
|
+
}
|
|
2976
|
+
renderWithData(data, _context) {
|
|
2977
|
+
const added = data.cost?.total_lines_added ?? 0;
|
|
2978
|
+
const removed = data.cost?.total_lines_removed ?? 0;
|
|
2979
|
+
const renderData = { added, removed };
|
|
2980
|
+
return this.styleFn(renderData, this.colors.lines);
|
|
1849
2981
|
}
|
|
1850
2982
|
};
|
|
1851
2983
|
|
|
1852
|
-
// src/
|
|
1853
|
-
|
|
2984
|
+
// src/widgets/model/styles.ts
|
|
2985
|
+
function getShortName(displayName) {
|
|
2986
|
+
return displayName.replace(/^Claude\s+/, "");
|
|
2987
|
+
}
|
|
2988
|
+
var modelStyles = {
|
|
2989
|
+
balanced: (data, colors) => {
|
|
2990
|
+
if (!colors) return data.displayName;
|
|
2991
|
+
return colorize(data.displayName, colors.name);
|
|
2992
|
+
},
|
|
2993
|
+
compact: (data, colors) => {
|
|
2994
|
+
const shortName = getShortName(data.displayName);
|
|
2995
|
+
if (!colors) return shortName;
|
|
2996
|
+
return colorize(shortName, colors.name);
|
|
2997
|
+
},
|
|
2998
|
+
playful: (data, colors) => {
|
|
2999
|
+
const shortName = getShortName(data.displayName);
|
|
3000
|
+
if (!colors) return `\u{1F916} ${shortName}`;
|
|
3001
|
+
return `\u{1F916} ${colorize(shortName, colors.name)}`;
|
|
3002
|
+
},
|
|
3003
|
+
technical: (data, colors) => {
|
|
3004
|
+
if (!colors) return data.id;
|
|
3005
|
+
const match = data.id.match(/^(.+?)-(\d[\d.]*)$/);
|
|
3006
|
+
if (match) {
|
|
3007
|
+
return colorize(match[1], colors.name) + colorize(`-${match[2]}`, colors.version);
|
|
3008
|
+
}
|
|
3009
|
+
return colorize(data.id, colors.name);
|
|
3010
|
+
},
|
|
3011
|
+
symbolic: (data, colors) => {
|
|
3012
|
+
const shortName = getShortName(data.displayName);
|
|
3013
|
+
if (!colors) return `\u25C6 ${shortName}`;
|
|
3014
|
+
return `\u25C6 ${colorize(shortName, colors.name)}`;
|
|
3015
|
+
},
|
|
3016
|
+
labeled: (data, colors) => {
|
|
3017
|
+
const shortName = getShortName(data.displayName);
|
|
3018
|
+
if (!colors) return withLabel("Model", shortName);
|
|
3019
|
+
return withLabel("Model", colorize(shortName, colors.name));
|
|
3020
|
+
},
|
|
3021
|
+
indicator: (data, colors) => {
|
|
3022
|
+
const shortName = getShortName(data.displayName);
|
|
3023
|
+
if (!colors) return withIndicator(shortName);
|
|
3024
|
+
return withIndicator(colorize(shortName, colors.name));
|
|
3025
|
+
}
|
|
3026
|
+
};
|
|
1854
3027
|
|
|
1855
|
-
// src/widgets/
|
|
1856
|
-
var
|
|
1857
|
-
id = "
|
|
3028
|
+
// src/widgets/model-widget.ts
|
|
3029
|
+
var ModelWidget = class extends StdinDataWidget {
|
|
3030
|
+
id = "model";
|
|
1858
3031
|
metadata = createWidgetMetadata(
|
|
1859
|
-
"
|
|
1860
|
-
"Displays Claude
|
|
3032
|
+
"Model",
|
|
3033
|
+
"Displays the current Claude model name",
|
|
1861
3034
|
"1.0.0",
|
|
1862
3035
|
"claude-scope",
|
|
1863
|
-
|
|
1864
|
-
//
|
|
3036
|
+
0
|
|
3037
|
+
// First line
|
|
1865
3038
|
);
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
3039
|
+
colors;
|
|
3040
|
+
styleFn = modelStyles.balanced;
|
|
3041
|
+
constructor(colors) {
|
|
3042
|
+
super();
|
|
3043
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
3044
|
+
}
|
|
3045
|
+
setStyle(style = "balanced") {
|
|
3046
|
+
const fn = modelStyles[style];
|
|
1872
3047
|
if (fn) {
|
|
1873
3048
|
this.styleFn = fn;
|
|
1874
3049
|
}
|
|
1875
3050
|
}
|
|
1876
|
-
|
|
1877
|
-
}
|
|
1878
|
-
async update(data) {
|
|
1879
|
-
this.cwd = data.cwd;
|
|
1880
|
-
this.configs = await this.configProvider.getConfigs({ cwd: data.cwd });
|
|
1881
|
-
}
|
|
1882
|
-
isEnabled() {
|
|
1883
|
-
if (!this.configs) {
|
|
1884
|
-
return false;
|
|
1885
|
-
}
|
|
1886
|
-
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
1887
|
-
return claudeMdCount > 0 || rulesCount > 0 || mcpCount > 0 || hooksCount > 0;
|
|
1888
|
-
}
|
|
1889
|
-
async render(context) {
|
|
1890
|
-
if (!this.configs) {
|
|
1891
|
-
return null;
|
|
1892
|
-
}
|
|
1893
|
-
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
3051
|
+
renderWithData(data, _context) {
|
|
1894
3052
|
const renderData = {
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
mcpCount,
|
|
1898
|
-
hooksCount
|
|
3053
|
+
displayName: data.model.display_name,
|
|
3054
|
+
id: data.model.id
|
|
1899
3055
|
};
|
|
1900
|
-
return this.styleFn(renderData);
|
|
1901
|
-
}
|
|
1902
|
-
async cleanup() {
|
|
3056
|
+
return this.styleFn(renderData, this.colors.model);
|
|
1903
3057
|
}
|
|
1904
3058
|
};
|
|
1905
3059
|
|
|
@@ -2451,8 +3605,8 @@ var PokerWidget = class extends StdinDataWidget {
|
|
|
2451
3605
|
"Displays random Texas Hold'em hands for entertainment",
|
|
2452
3606
|
"1.0.0",
|
|
2453
3607
|
"claude-scope",
|
|
2454
|
-
|
|
2455
|
-
//
|
|
3608
|
+
4
|
|
3609
|
+
// Fifth line (0-indexed)
|
|
2456
3610
|
);
|
|
2457
3611
|
holeCards = [];
|
|
2458
3612
|
boardCards = [];
|
|
@@ -2545,207 +3699,6 @@ var PokerWidget = class extends StdinDataWidget {
|
|
|
2545
3699
|
}
|
|
2546
3700
|
};
|
|
2547
3701
|
|
|
2548
|
-
// src/widgets/empty-line-widget.ts
|
|
2549
|
-
var EmptyLineWidget = class extends StdinDataWidget {
|
|
2550
|
-
id = "empty-line";
|
|
2551
|
-
metadata = createWidgetMetadata(
|
|
2552
|
-
"Empty Line",
|
|
2553
|
-
"Empty line separator",
|
|
2554
|
-
"1.0.0",
|
|
2555
|
-
"claude-scope",
|
|
2556
|
-
3
|
|
2557
|
-
// Fourth line (0-indexed)
|
|
2558
|
-
);
|
|
2559
|
-
/**
|
|
2560
|
-
* All styles return the same value (Braille Pattern Blank).
|
|
2561
|
-
* This method exists for API consistency with other widgets.
|
|
2562
|
-
*/
|
|
2563
|
-
setStyle(_style) {
|
|
2564
|
-
}
|
|
2565
|
-
/**
|
|
2566
|
-
* Return Braille Pattern Blank to create a visible empty separator line.
|
|
2567
|
-
* U+2800 occupies cell width but appears blank, ensuring the line renders.
|
|
2568
|
-
*/
|
|
2569
|
-
renderWithData(_data, _context) {
|
|
2570
|
-
return "\u2800";
|
|
2571
|
-
}
|
|
2572
|
-
};
|
|
2573
|
-
|
|
2574
|
-
// src/validation/result.ts
|
|
2575
|
-
function success(data) {
|
|
2576
|
-
return { success: true, data };
|
|
2577
|
-
}
|
|
2578
|
-
function failure(path2, message, value) {
|
|
2579
|
-
return { success: false, error: { path: path2, message, value } };
|
|
2580
|
-
}
|
|
2581
|
-
function formatError(error) {
|
|
2582
|
-
const path2 = error.path.length > 0 ? error.path.join(".") : "root";
|
|
2583
|
-
return `${path2}: ${error.message}`;
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
// src/validation/validators.ts
|
|
2587
|
-
function string() {
|
|
2588
|
-
return {
|
|
2589
|
-
validate(value) {
|
|
2590
|
-
if (typeof value === "string") return success(value);
|
|
2591
|
-
return failure([], "Expected string", value);
|
|
2592
|
-
}
|
|
2593
|
-
};
|
|
2594
|
-
}
|
|
2595
|
-
function number() {
|
|
2596
|
-
return {
|
|
2597
|
-
validate(value) {
|
|
2598
|
-
if (typeof value === "number" && !Number.isNaN(value)) return success(value);
|
|
2599
|
-
return failure([], "Expected number", value);
|
|
2600
|
-
}
|
|
2601
|
-
};
|
|
2602
|
-
}
|
|
2603
|
-
function literal(expected) {
|
|
2604
|
-
return {
|
|
2605
|
-
validate(value) {
|
|
2606
|
-
if (value === expected) return success(expected);
|
|
2607
|
-
return failure([], `Expected '${expected}'`, value);
|
|
2608
|
-
}
|
|
2609
|
-
};
|
|
2610
|
-
}
|
|
2611
|
-
|
|
2612
|
-
// src/validation/combinators.ts
|
|
2613
|
-
function object(shape) {
|
|
2614
|
-
return {
|
|
2615
|
-
validate(value) {
|
|
2616
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2617
|
-
return failure([], "Expected object", value);
|
|
2618
|
-
}
|
|
2619
|
-
const result = {};
|
|
2620
|
-
for (const [key, validator] of Object.entries(shape)) {
|
|
2621
|
-
const fieldValue = value[key];
|
|
2622
|
-
const validationResult = validator.validate(fieldValue);
|
|
2623
|
-
if (!validationResult.success) {
|
|
2624
|
-
return {
|
|
2625
|
-
success: false,
|
|
2626
|
-
error: { ...validationResult.error, path: [key, ...validationResult.error.path] }
|
|
2627
|
-
};
|
|
2628
|
-
}
|
|
2629
|
-
result[key] = validationResult.data;
|
|
2630
|
-
}
|
|
2631
|
-
return success(result);
|
|
2632
|
-
}
|
|
2633
|
-
};
|
|
2634
|
-
}
|
|
2635
|
-
function optional(validator) {
|
|
2636
|
-
return {
|
|
2637
|
-
validate(value) {
|
|
2638
|
-
if (value === void 0) return success(void 0);
|
|
2639
|
-
return validator.validate(value);
|
|
2640
|
-
}
|
|
2641
|
-
};
|
|
2642
|
-
}
|
|
2643
|
-
function nullable(validator) {
|
|
2644
|
-
return {
|
|
2645
|
-
validate(value) {
|
|
2646
|
-
if (value === null) return success(null);
|
|
2647
|
-
return validator.validate(value);
|
|
2648
|
-
}
|
|
2649
|
-
};
|
|
2650
|
-
}
|
|
2651
|
-
|
|
2652
|
-
// src/schemas/stdin-schema.ts
|
|
2653
|
-
var ContextUsageSchema = object({
|
|
2654
|
-
input_tokens: number(),
|
|
2655
|
-
output_tokens: number(),
|
|
2656
|
-
cache_creation_input_tokens: number(),
|
|
2657
|
-
cache_read_input_tokens: number()
|
|
2658
|
-
});
|
|
2659
|
-
var CostInfoSchema = object({
|
|
2660
|
-
total_cost_usd: optional(number()),
|
|
2661
|
-
total_duration_ms: optional(number()),
|
|
2662
|
-
total_api_duration_ms: optional(number()),
|
|
2663
|
-
total_lines_added: optional(number()),
|
|
2664
|
-
total_lines_removed: optional(number())
|
|
2665
|
-
});
|
|
2666
|
-
var ContextWindowSchema = object({
|
|
2667
|
-
total_input_tokens: number(),
|
|
2668
|
-
total_output_tokens: number(),
|
|
2669
|
-
context_window_size: number(),
|
|
2670
|
-
current_usage: nullable(ContextUsageSchema)
|
|
2671
|
-
});
|
|
2672
|
-
var ModelInfoSchema = object({
|
|
2673
|
-
id: string(),
|
|
2674
|
-
display_name: string()
|
|
2675
|
-
});
|
|
2676
|
-
var WorkspaceSchema = object({
|
|
2677
|
-
current_dir: string(),
|
|
2678
|
-
project_dir: string()
|
|
2679
|
-
});
|
|
2680
|
-
var OutputStyleSchema = object({
|
|
2681
|
-
name: string()
|
|
2682
|
-
});
|
|
2683
|
-
var StdinDataSchema = object({
|
|
2684
|
-
hook_event_name: optional(literal("Status")),
|
|
2685
|
-
session_id: string(),
|
|
2686
|
-
transcript_path: string(),
|
|
2687
|
-
cwd: string(),
|
|
2688
|
-
model: ModelInfoSchema,
|
|
2689
|
-
workspace: WorkspaceSchema,
|
|
2690
|
-
version: string(),
|
|
2691
|
-
output_style: OutputStyleSchema,
|
|
2692
|
-
cost: optional(CostInfoSchema),
|
|
2693
|
-
context_window: ContextWindowSchema
|
|
2694
|
-
});
|
|
2695
|
-
|
|
2696
|
-
// src/data/stdin-provider.ts
|
|
2697
|
-
var StdinParseError = class extends Error {
|
|
2698
|
-
constructor(message) {
|
|
2699
|
-
super(message);
|
|
2700
|
-
this.name = "StdinParseError";
|
|
2701
|
-
}
|
|
2702
|
-
};
|
|
2703
|
-
var StdinValidationError = class extends Error {
|
|
2704
|
-
constructor(message) {
|
|
2705
|
-
super(message);
|
|
2706
|
-
this.name = "StdinValidationError";
|
|
2707
|
-
}
|
|
2708
|
-
};
|
|
2709
|
-
var StdinProvider = class {
|
|
2710
|
-
/**
|
|
2711
|
-
* Parse and validate JSON string from stdin
|
|
2712
|
-
* @param input JSON string to parse
|
|
2713
|
-
* @returns Validated StdinData object
|
|
2714
|
-
* @throws StdinParseError if JSON is malformed
|
|
2715
|
-
* @throws StdinValidationError if data doesn't match schema
|
|
2716
|
-
*/
|
|
2717
|
-
async parse(input) {
|
|
2718
|
-
if (!input || input.trim().length === 0) {
|
|
2719
|
-
throw new StdinParseError("stdin data is empty");
|
|
2720
|
-
}
|
|
2721
|
-
let data;
|
|
2722
|
-
try {
|
|
2723
|
-
data = JSON.parse(input);
|
|
2724
|
-
} catch (error) {
|
|
2725
|
-
throw new StdinParseError(`Invalid JSON: ${error.message}`);
|
|
2726
|
-
}
|
|
2727
|
-
const result = StdinDataSchema.validate(data);
|
|
2728
|
-
if (!result.success) {
|
|
2729
|
-
throw new StdinValidationError(`Validation failed: ${formatError(result.error)}`);
|
|
2730
|
-
}
|
|
2731
|
-
return result.data;
|
|
2732
|
-
}
|
|
2733
|
-
/**
|
|
2734
|
-
* Safe parse that returns result instead of throwing
|
|
2735
|
-
* Useful for testing and optional validation
|
|
2736
|
-
* @param input JSON string to parse
|
|
2737
|
-
* @returns Result object with success flag
|
|
2738
|
-
*/
|
|
2739
|
-
async safeParse(input) {
|
|
2740
|
-
try {
|
|
2741
|
-
const data = await this.parse(input);
|
|
2742
|
-
return { success: true, data };
|
|
2743
|
-
} catch (error) {
|
|
2744
|
-
return { success: false, error: error.message };
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
};
|
|
2748
|
-
|
|
2749
3702
|
// src/index.ts
|
|
2750
3703
|
async function readStdin() {
|
|
2751
3704
|
const chunks = [];
|
|
@@ -2764,6 +3717,7 @@ async function main() {
|
|
|
2764
3717
|
const provider = new StdinProvider();
|
|
2765
3718
|
const stdinData = await provider.parse(stdin);
|
|
2766
3719
|
const registry = new WidgetRegistry();
|
|
3720
|
+
const transcriptProvider = new TranscriptProvider();
|
|
2767
3721
|
await registry.register(new ModelWidget());
|
|
2768
3722
|
await registry.register(new ContextWidget());
|
|
2769
3723
|
await registry.register(new CostWidget());
|
|
@@ -2772,6 +3726,12 @@ async function main() {
|
|
|
2772
3726
|
await registry.register(new GitWidget());
|
|
2773
3727
|
await registry.register(new GitTagWidget());
|
|
2774
3728
|
await registry.register(new ConfigCountWidget());
|
|
3729
|
+
if (isWidgetEnabled("cacheMetrics")) {
|
|
3730
|
+
await registry.register(new CacheMetricsWidget(DEFAULT_THEME));
|
|
3731
|
+
}
|
|
3732
|
+
if (isWidgetEnabled("activeTools")) {
|
|
3733
|
+
await registry.register(new ActiveToolsWidget(DEFAULT_THEME, transcriptProvider));
|
|
3734
|
+
}
|
|
2775
3735
|
await registry.register(new PokerWidget());
|
|
2776
3736
|
await registry.register(new EmptyLineWidget());
|
|
2777
3737
|
const renderer = new Renderer({
|