claude-scope 0.6.2 → 0.6.10
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 +1981 -1018
- 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,904 @@ 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/ui/utils/formatters.ts
|
|
1792
|
+
function formatDuration(ms) {
|
|
1793
|
+
if (ms <= 0) return "0s";
|
|
1794
|
+
const seconds = Math.floor(ms / TIME.MS_PER_SECOND);
|
|
1795
|
+
const hours = Math.floor(seconds / TIME.SECONDS_PER_HOUR);
|
|
1796
|
+
const minutes = Math.floor(seconds % TIME.SECONDS_PER_HOUR / TIME.SECONDS_PER_MINUTE);
|
|
1797
|
+
const secs = seconds % TIME.SECONDS_PER_MINUTE;
|
|
1798
|
+
const parts = [];
|
|
1799
|
+
if (hours > 0) {
|
|
1800
|
+
parts.push(`${hours}h`);
|
|
1801
|
+
parts.push(`${minutes}m`);
|
|
1802
|
+
parts.push(`${secs}s`);
|
|
1803
|
+
} else if (minutes > 0) {
|
|
1804
|
+
parts.push(`${minutes}m`);
|
|
1805
|
+
parts.push(`${secs}s`);
|
|
1806
|
+
} else {
|
|
1807
|
+
parts.push(`${secs}s`);
|
|
1808
|
+
}
|
|
1809
|
+
return parts.join(" ");
|
|
1810
|
+
}
|
|
1811
|
+
function formatCostUSD(usd) {
|
|
1812
|
+
return `$${usd.toFixed(2)}`;
|
|
1813
|
+
}
|
|
1814
|
+
function colorize2(text, color) {
|
|
1815
|
+
return `${color}${text}${ANSI_COLORS.RESET}`;
|
|
1816
|
+
}
|
|
1817
|
+
function formatK(n) {
|
|
1818
|
+
const absN = Math.abs(n);
|
|
1819
|
+
if (absN < 1e3) {
|
|
1820
|
+
return n.toString();
|
|
1821
|
+
}
|
|
1822
|
+
const k = n / 1e3;
|
|
1823
|
+
return Math.abs(k) < 10 ? `${k.toFixed(1)}k` : `${Math.round(k)}k`;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// src/widgets/cache-metrics/styles.ts
|
|
1827
|
+
function formatCurrency(usd) {
|
|
1828
|
+
if (usd < 5e-3 && usd > 0) {
|
|
1829
|
+
return "<$0.01";
|
|
1830
|
+
}
|
|
1831
|
+
return `$${usd.toFixed(2)}`;
|
|
1832
|
+
}
|
|
1833
|
+
function createProgressBar(percentage, width) {
|
|
1834
|
+
const filled = Math.round(percentage / 100 * width);
|
|
1835
|
+
const empty = width - filled;
|
|
1836
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
1837
|
+
}
|
|
1838
|
+
function getCacheColor(hitRate, colors) {
|
|
1839
|
+
if (hitRate > 70) {
|
|
1840
|
+
return colors.cache.high;
|
|
1841
|
+
} else if (hitRate >= 40) {
|
|
1842
|
+
return colors.cache.medium;
|
|
1843
|
+
} else {
|
|
1844
|
+
return colors.cache.low;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
var cacheMetricsStyles = {
|
|
1848
|
+
/**
|
|
1849
|
+
* balanced: 💾 70% cached (35.0k tokens) with color coding
|
|
1850
|
+
*/
|
|
1027
1851
|
balanced: (data, colors) => {
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1852
|
+
const { hitRate, cacheRead } = data;
|
|
1853
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1854
|
+
const percentage = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1855
|
+
const tokens = colors ? `${colors.cache.read}${formatK(cacheRead)} tokens` : `${formatK(cacheRead)} tokens`;
|
|
1856
|
+
return `\u{1F4BE} ${percentage} cached (${tokens})`;
|
|
1031
1857
|
},
|
|
1858
|
+
/**
|
|
1859
|
+
* compact: Cache: 70%
|
|
1860
|
+
*/
|
|
1032
1861
|
compact: (data, colors) => {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1862
|
+
const hitRate = data.hitRate.toFixed(0);
|
|
1863
|
+
if (colors) {
|
|
1864
|
+
return `${colors.cache.read}Cache: ${hitRate}%`;
|
|
1865
|
+
}
|
|
1866
|
+
return `Cache: ${hitRate}%`;
|
|
1037
1867
|
},
|
|
1868
|
+
/**
|
|
1869
|
+
* playful: 💾 [███████░] 70% with progress bar
|
|
1870
|
+
*/
|
|
1038
1871
|
playful: (data, colors) => {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1872
|
+
const { hitRate } = data;
|
|
1873
|
+
const bar = createProgressBar(hitRate, 7);
|
|
1874
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1875
|
+
const barAndPercent = color ? `${color}[${bar}] ${hitRate.toFixed(0)}%` : `[${bar}] ${hitRate.toFixed(0)}%`;
|
|
1876
|
+
return `\u{1F4BE} ${barAndPercent}`;
|
|
1042
1877
|
},
|
|
1878
|
+
/**
|
|
1879
|
+
* verbose: Cache: 35.0k tokens (70%) | $0.03 saved
|
|
1880
|
+
*/
|
|
1043
1881
|
verbose: (data, colors) => {
|
|
1044
|
-
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1882
|
+
const { cacheRead, hitRate, savings } = data;
|
|
1883
|
+
const tokens = colors ? `${colors.cache.read}${formatK(cacheRead)} tokens` : `${formatK(cacheRead)} tokens`;
|
|
1884
|
+
const percent = `${hitRate.toFixed(0)}%`;
|
|
1885
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1886
|
+
return `Cache: ${tokens} (${percent}) | ${saved}`;
|
|
1048
1887
|
},
|
|
1888
|
+
/**
|
|
1889
|
+
* labeled: Cache Hit: 70% | $0.03 saved
|
|
1890
|
+
*/
|
|
1049
1891
|
labeled: (data, colors) => {
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1892
|
+
const { hitRate, savings } = data;
|
|
1893
|
+
const percent = colors ? `${colors.cache.read}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1894
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1895
|
+
return `Cache Hit: ${percent} | ${saved}`;
|
|
1053
1896
|
},
|
|
1897
|
+
/**
|
|
1898
|
+
* indicator: ● 70% cached
|
|
1899
|
+
*/
|
|
1054
1900
|
indicator: (data, colors) => {
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1901
|
+
const { hitRate } = data;
|
|
1902
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1903
|
+
const percentage = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1904
|
+
return `\u25CF ${percentage} cached`;
|
|
1905
|
+
},
|
|
1906
|
+
/**
|
|
1907
|
+
* breakdown: Multi-line with ├─ Read: and └─ Write: breakdown
|
|
1908
|
+
*/
|
|
1909
|
+
breakdown: (data, colors) => {
|
|
1910
|
+
const { cacheRead, cacheWrite, hitRate, savings } = data;
|
|
1911
|
+
const color = colors ? getCacheColor(hitRate, colors) : "";
|
|
1912
|
+
const percent = color ? `${color}${hitRate.toFixed(0)}%` : `${hitRate.toFixed(0)}%`;
|
|
1913
|
+
const saved = colors ? `${colors.cache.write}${formatCurrency(savings)} saved` : `${formatCurrency(savings)} saved`;
|
|
1914
|
+
const read = colors ? `${colors.cache.read}${formatK(cacheRead)}` : formatK(cacheRead);
|
|
1915
|
+
const write = colors ? `${colors.cache.write}${formatK(cacheWrite)}` : formatK(cacheWrite);
|
|
1916
|
+
return [`\u{1F4BE} ${percent} cached | ${saved}`, `\u251C\u2500 Read: ${read}`, `\u2514\u2500 Write: ${write}`].join("\n");
|
|
1058
1917
|
}
|
|
1059
1918
|
};
|
|
1060
1919
|
|
|
1061
|
-
// src/widgets/
|
|
1062
|
-
var
|
|
1063
|
-
id = "
|
|
1920
|
+
// src/widgets/cache-metrics/cache-metrics-widget.ts
|
|
1921
|
+
var CacheMetricsWidget = class extends StdinDataWidget {
|
|
1922
|
+
id = "cache-metrics";
|
|
1064
1923
|
metadata = createWidgetMetadata(
|
|
1065
|
-
"
|
|
1066
|
-
"
|
|
1924
|
+
"Cache Metrics",
|
|
1925
|
+
"Cache hit rate and savings display",
|
|
1067
1926
|
"1.0.0",
|
|
1068
1927
|
"claude-scope",
|
|
1069
|
-
|
|
1070
|
-
//
|
|
1928
|
+
2
|
|
1929
|
+
// Third line
|
|
1071
1930
|
);
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
*
|
|
1081
|
-
* Tests can inject MockGit factory here
|
|
1082
|
-
* @param colors - Optional theme colors
|
|
1931
|
+
theme;
|
|
1932
|
+
style = "balanced";
|
|
1933
|
+
renderData;
|
|
1934
|
+
constructor(theme) {
|
|
1935
|
+
super();
|
|
1936
|
+
this.theme = theme ?? DEFAULT_THEME;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Set display style
|
|
1083
1940
|
*/
|
|
1084
|
-
|
|
1085
|
-
this.
|
|
1086
|
-
this.colors = colors ?? DEFAULT_THEME;
|
|
1941
|
+
setStyle(style) {
|
|
1942
|
+
this.style = style;
|
|
1087
1943
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1944
|
+
/**
|
|
1945
|
+
* Calculate cache metrics from context usage data
|
|
1946
|
+
* Returns null if no usage data is available
|
|
1947
|
+
*/
|
|
1948
|
+
calculateMetrics(data) {
|
|
1949
|
+
const usage = data.context_window?.current_usage;
|
|
1950
|
+
if (!usage) {
|
|
1951
|
+
return null;
|
|
1092
1952
|
}
|
|
1953
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
1954
|
+
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
|
1955
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
1956
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
1957
|
+
const totalInputTokens = cacheRead + cacheWrite + inputTokens;
|
|
1958
|
+
const totalTokens = totalInputTokens + outputTokens;
|
|
1959
|
+
const hitRate = totalInputTokens > 0 ? Math.min(100, Math.round(cacheRead / totalInputTokens * 100)) : 0;
|
|
1960
|
+
const costPerToken = 3e-6;
|
|
1961
|
+
const savings = cacheRead * 0.9 * costPerToken;
|
|
1962
|
+
return {
|
|
1963
|
+
cacheRead,
|
|
1964
|
+
cacheWrite,
|
|
1965
|
+
totalTokens,
|
|
1966
|
+
hitRate,
|
|
1967
|
+
savings
|
|
1968
|
+
};
|
|
1093
1969
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1970
|
+
/**
|
|
1971
|
+
* Update widget with new data and calculate metrics
|
|
1972
|
+
*/
|
|
1973
|
+
async update(data) {
|
|
1974
|
+
await super.update(data);
|
|
1975
|
+
const metrics = this.calculateMetrics(data);
|
|
1976
|
+
this.renderData = metrics ?? void 0;
|
|
1096
1977
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1978
|
+
/**
|
|
1979
|
+
* Render the cache metrics display
|
|
1980
|
+
*/
|
|
1981
|
+
renderWithData(_data, _context) {
|
|
1982
|
+
if (!this.renderData) {
|
|
1099
1983
|
return null;
|
|
1100
1984
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
const renderData = { tag: latestTag };
|
|
1104
|
-
return this.styleFn(renderData, this.colors.git);
|
|
1105
|
-
} catch {
|
|
1985
|
+
const styleFn = cacheMetricsStyles[this.style] ?? cacheMetricsStyles.balanced;
|
|
1986
|
+
if (!styleFn) {
|
|
1106
1987
|
return null;
|
|
1107
1988
|
}
|
|
1989
|
+
return styleFn(this.renderData, this.theme);
|
|
1108
1990
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
this.git = this.gitFactory(data.cwd);
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Widget is enabled when we have cache metrics data
|
|
1993
|
+
*/
|
|
1115
1994
|
isEnabled() {
|
|
1116
|
-
return this.
|
|
1117
|
-
}
|
|
1118
|
-
async cleanup() {
|
|
1995
|
+
return this.renderData !== void 0;
|
|
1119
1996
|
}
|
|
1120
1997
|
};
|
|
1121
1998
|
|
|
1122
|
-
// src/
|
|
1123
|
-
var
|
|
1999
|
+
// src/core/style-types.ts
|
|
2000
|
+
var DEFAULT_WIDGET_STYLE = "balanced";
|
|
2001
|
+
|
|
2002
|
+
// src/providers/config-provider.ts
|
|
2003
|
+
var fs = __toESM(require("fs/promises"), 1);
|
|
2004
|
+
var os = __toESM(require("os"), 1);
|
|
2005
|
+
var path = __toESM(require("path"), 1);
|
|
2006
|
+
var ConfigProvider = class {
|
|
2007
|
+
cachedCounts;
|
|
2008
|
+
lastScan = 0;
|
|
2009
|
+
cacheInterval = 5e3;
|
|
2010
|
+
// 5 seconds
|
|
1124
2011
|
/**
|
|
1125
|
-
*
|
|
2012
|
+
* Get config counts with hybrid caching
|
|
2013
|
+
* Scans filesystem if cache is stale (>5 seconds)
|
|
1126
2014
|
*/
|
|
1127
|
-
|
|
2015
|
+
async getConfigs(options = {}) {
|
|
2016
|
+
const now = Date.now();
|
|
2017
|
+
if (this.cachedCounts && now - this.lastScan < this.cacheInterval) {
|
|
2018
|
+
return this.cachedCounts;
|
|
2019
|
+
}
|
|
2020
|
+
this.cachedCounts = await this.scanConfigs(options);
|
|
2021
|
+
this.lastScan = now;
|
|
2022
|
+
return this.cachedCounts;
|
|
2023
|
+
}
|
|
1128
2024
|
/**
|
|
1129
|
-
*
|
|
2025
|
+
* Scan filesystem for Claude Code configurations
|
|
1130
2026
|
*/
|
|
1131
|
-
|
|
2027
|
+
async scanConfigs(options) {
|
|
2028
|
+
let claudeMdCount = 0;
|
|
2029
|
+
let rulesCount = 0;
|
|
2030
|
+
let mcpCount = 0;
|
|
2031
|
+
let hooksCount = 0;
|
|
2032
|
+
const homeDir = os.homedir();
|
|
2033
|
+
const claudeDir = path.join(homeDir, ".claude");
|
|
2034
|
+
const cwd = options.cwd;
|
|
2035
|
+
if (await this.fileExists(path.join(claudeDir, "CLAUDE.md"))) {
|
|
2036
|
+
claudeMdCount++;
|
|
2037
|
+
}
|
|
2038
|
+
rulesCount += await this.countRulesInDir(path.join(claudeDir, "rules"));
|
|
2039
|
+
const userSettings = path.join(claudeDir, "settings.json");
|
|
2040
|
+
const userSettingsData = await this.readJsonFile(userSettings);
|
|
2041
|
+
if (userSettingsData) {
|
|
2042
|
+
mcpCount += this.countMcpServers(userSettingsData);
|
|
2043
|
+
hooksCount += this.countHooks(userSettingsData);
|
|
2044
|
+
}
|
|
2045
|
+
const userClaudeJson = path.join(homeDir, ".claude.json");
|
|
2046
|
+
const userClaudeData = await this.readJsonFile(userClaudeJson);
|
|
2047
|
+
if (userClaudeData) {
|
|
2048
|
+
const userMcpCount = this.countMcpServers(userClaudeData);
|
|
2049
|
+
mcpCount += Math.max(0, userMcpCount - this.countMcpServers(userSettingsData || {}));
|
|
2050
|
+
}
|
|
2051
|
+
if (cwd) {
|
|
2052
|
+
if (await this.fileExists(path.join(cwd, "CLAUDE.md"))) {
|
|
2053
|
+
claudeMdCount++;
|
|
2054
|
+
}
|
|
2055
|
+
if (await this.fileExists(path.join(cwd, "CLAUDE.local.md"))) {
|
|
2056
|
+
claudeMdCount++;
|
|
2057
|
+
}
|
|
2058
|
+
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.md"))) {
|
|
2059
|
+
claudeMdCount++;
|
|
2060
|
+
}
|
|
2061
|
+
if (await this.fileExists(path.join(cwd, ".claude", "CLAUDE.local.md"))) {
|
|
2062
|
+
claudeMdCount++;
|
|
2063
|
+
}
|
|
2064
|
+
rulesCount += await this.countRulesInDir(path.join(cwd, ".claude", "rules"));
|
|
2065
|
+
const mcpJson = path.join(cwd, ".mcp.json");
|
|
2066
|
+
const mcpData = await this.readJsonFile(mcpJson);
|
|
2067
|
+
if (mcpData) {
|
|
2068
|
+
mcpCount += this.countMcpServers(mcpData);
|
|
2069
|
+
}
|
|
2070
|
+
const projectSettings = path.join(cwd, ".claude", "settings.json");
|
|
2071
|
+
const projectSettingsData = await this.readJsonFile(projectSettings);
|
|
2072
|
+
if (projectSettingsData) {
|
|
2073
|
+
mcpCount += this.countMcpServers(projectSettingsData);
|
|
2074
|
+
hooksCount += this.countHooks(projectSettingsData);
|
|
2075
|
+
}
|
|
2076
|
+
const localSettings = path.join(cwd, ".claude", "settings.local.json");
|
|
2077
|
+
const localSettingsData = await this.readJsonFile(localSettings);
|
|
2078
|
+
if (localSettingsData) {
|
|
2079
|
+
mcpCount += this.countMcpServers(localSettingsData);
|
|
2080
|
+
hooksCount += this.countHooks(localSettingsData);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return { claudeMdCount, rulesCount, mcpCount, hooksCount };
|
|
2084
|
+
}
|
|
1132
2085
|
/**
|
|
1133
|
-
*
|
|
1134
|
-
* @param context - Widget initialization context
|
|
2086
|
+
* Check if file exists
|
|
1135
2087
|
*/
|
|
1136
|
-
async
|
|
1137
|
-
|
|
2088
|
+
async fileExists(filePath) {
|
|
2089
|
+
try {
|
|
2090
|
+
await fs.access(filePath);
|
|
2091
|
+
return true;
|
|
2092
|
+
} catch {
|
|
2093
|
+
return false;
|
|
2094
|
+
}
|
|
1138
2095
|
}
|
|
1139
2096
|
/**
|
|
1140
|
-
*
|
|
1141
|
-
* @param data - Stdin data from Claude Code
|
|
2097
|
+
* Read and parse JSON file
|
|
1142
2098
|
*/
|
|
1143
|
-
async
|
|
1144
|
-
|
|
2099
|
+
async readJsonFile(filePath) {
|
|
2100
|
+
try {
|
|
2101
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
2102
|
+
return JSON.parse(content);
|
|
2103
|
+
} catch {
|
|
2104
|
+
return null;
|
|
2105
|
+
}
|
|
1145
2106
|
}
|
|
1146
2107
|
/**
|
|
1147
|
-
*
|
|
1148
|
-
* @returns Stored stdin data
|
|
1149
|
-
* @throws Error if data has not been initialized (update not called)
|
|
2108
|
+
* Count MCP servers in config object
|
|
1150
2109
|
*/
|
|
1151
|
-
|
|
1152
|
-
if (!
|
|
1153
|
-
|
|
2110
|
+
countMcpServers(config) {
|
|
2111
|
+
if (!config || !config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2112
|
+
return 0;
|
|
1154
2113
|
}
|
|
1155
|
-
return
|
|
2114
|
+
return Object.keys(config.mcpServers).length;
|
|
1156
2115
|
}
|
|
1157
2116
|
/**
|
|
1158
|
-
*
|
|
1159
|
-
* @returns true if widget should render
|
|
2117
|
+
* Count hooks in config object
|
|
1160
2118
|
*/
|
|
1161
|
-
|
|
1162
|
-
|
|
2119
|
+
countHooks(config) {
|
|
2120
|
+
if (!config || !config.hooks || typeof config.hooks !== "object") {
|
|
2121
|
+
return 0;
|
|
2122
|
+
}
|
|
2123
|
+
return Object.keys(config.hooks).length;
|
|
1163
2124
|
}
|
|
1164
2125
|
/**
|
|
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
|
|
2126
|
+
* Recursively count .md files in directory
|
|
1171
2127
|
*/
|
|
1172
|
-
async
|
|
1173
|
-
|
|
1174
|
-
|
|
2128
|
+
async countRulesInDir(rulesDir) {
|
|
2129
|
+
const exists = await this.fileExists(rulesDir);
|
|
2130
|
+
if (!exists) return 0;
|
|
2131
|
+
try {
|
|
2132
|
+
let count = 0;
|
|
2133
|
+
const entries = await fs.readdir(rulesDir, { withFileTypes: true });
|
|
2134
|
+
for (const entry of entries) {
|
|
2135
|
+
const fullPath = path.join(rulesDir, entry.name);
|
|
2136
|
+
if (entry.isDirectory()) {
|
|
2137
|
+
count += await this.countRulesInDir(fullPath);
|
|
2138
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2139
|
+
count++;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return count;
|
|
2143
|
+
} catch {
|
|
2144
|
+
return 0;
|
|
1175
2145
|
}
|
|
1176
|
-
return this.renderWithData(this.data, context);
|
|
1177
2146
|
}
|
|
1178
2147
|
};
|
|
1179
2148
|
|
|
1180
|
-
// src/widgets/
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
return colorize(data.displayName, colors.name);
|
|
1188
|
-
},
|
|
1189
|
-
compact: (data, colors) => {
|
|
1190
|
-
const shortName = getShortName(data.displayName);
|
|
1191
|
-
if (!colors) return shortName;
|
|
1192
|
-
return colorize(shortName, colors.name);
|
|
1193
|
-
},
|
|
1194
|
-
playful: (data, colors) => {
|
|
1195
|
-
const shortName = getShortName(data.displayName);
|
|
1196
|
-
if (!colors) return `\u{1F916} ${shortName}`;
|
|
1197
|
-
return `\u{1F916} ${colorize(shortName, colors.name)}`;
|
|
1198
|
-
},
|
|
1199
|
-
technical: (data, colors) => {
|
|
1200
|
-
if (!colors) return data.id;
|
|
1201
|
-
const match = data.id.match(/^(.+?)-(\d[\d.]*)$/);
|
|
1202
|
-
if (match) {
|
|
1203
|
-
return colorize(match[1], colors.name) + colorize(`-${match[2]}`, colors.version);
|
|
2149
|
+
// src/widgets/config-count/styles.ts
|
|
2150
|
+
var configCountStyles = {
|
|
2151
|
+
balanced: (data) => {
|
|
2152
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2153
|
+
const parts = [];
|
|
2154
|
+
if (claudeMdCount > 0) {
|
|
2155
|
+
parts.push(`CLAUDE.md:${claudeMdCount}`);
|
|
1204
2156
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
2157
|
+
if (rulesCount > 0) {
|
|
2158
|
+
parts.push(`rules:${rulesCount}`);
|
|
2159
|
+
}
|
|
2160
|
+
if (mcpCount > 0) {
|
|
2161
|
+
parts.push(`MCPs:${mcpCount}`);
|
|
2162
|
+
}
|
|
2163
|
+
if (hooksCount > 0) {
|
|
2164
|
+
parts.push(`hooks:${hooksCount}`);
|
|
2165
|
+
}
|
|
2166
|
+
return parts.join(" \u2502 ");
|
|
1211
2167
|
},
|
|
1212
|
-
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
2168
|
+
compact: (data) => {
|
|
2169
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2170
|
+
const parts = [];
|
|
2171
|
+
if (claudeMdCount > 0) {
|
|
2172
|
+
parts.push(`${claudeMdCount} docs`);
|
|
2173
|
+
}
|
|
2174
|
+
if (rulesCount > 0) {
|
|
2175
|
+
parts.push(`${rulesCount} rules`);
|
|
2176
|
+
}
|
|
2177
|
+
if (mcpCount > 0) {
|
|
2178
|
+
parts.push(`${mcpCount} MCPs`);
|
|
2179
|
+
}
|
|
2180
|
+
if (hooksCount > 0) {
|
|
2181
|
+
const hookLabel = hooksCount === 1 ? "hook" : "hooks";
|
|
2182
|
+
parts.push(`${hooksCount} ${hookLabel}`);
|
|
2183
|
+
}
|
|
2184
|
+
return parts.join(" \u2502 ");
|
|
1216
2185
|
},
|
|
1217
|
-
|
|
1218
|
-
const
|
|
1219
|
-
|
|
1220
|
-
|
|
2186
|
+
playful: (data) => {
|
|
2187
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2188
|
+
const parts = [];
|
|
2189
|
+
if (claudeMdCount > 0) {
|
|
2190
|
+
parts.push(`\u{1F4C4} CLAUDE.md:${claudeMdCount}`);
|
|
2191
|
+
}
|
|
2192
|
+
if (rulesCount > 0) {
|
|
2193
|
+
parts.push(`\u{1F4DC} rules:${rulesCount}`);
|
|
2194
|
+
}
|
|
2195
|
+
if (mcpCount > 0) {
|
|
2196
|
+
parts.push(`\u{1F50C} MCPs:${mcpCount}`);
|
|
2197
|
+
}
|
|
2198
|
+
if (hooksCount > 0) {
|
|
2199
|
+
parts.push(`\u{1FA9D} hooks:${hooksCount}`);
|
|
2200
|
+
}
|
|
2201
|
+
return parts.join(" \u2502 ");
|
|
2202
|
+
},
|
|
2203
|
+
verbose: (data) => {
|
|
2204
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = data;
|
|
2205
|
+
const parts = [];
|
|
2206
|
+
if (claudeMdCount > 0) {
|
|
2207
|
+
parts.push(`${claudeMdCount} CLAUDE.md`);
|
|
2208
|
+
}
|
|
2209
|
+
if (rulesCount > 0) {
|
|
2210
|
+
parts.push(`${rulesCount} rules`);
|
|
2211
|
+
}
|
|
2212
|
+
if (mcpCount > 0) {
|
|
2213
|
+
parts.push(`${mcpCount} MCP servers`);
|
|
2214
|
+
}
|
|
2215
|
+
if (hooksCount > 0) {
|
|
2216
|
+
parts.push(`${hooksCount} hook`);
|
|
2217
|
+
}
|
|
2218
|
+
return parts.join(" \u2502 ");
|
|
1221
2219
|
}
|
|
1222
2220
|
};
|
|
1223
2221
|
|
|
1224
|
-
// src/widgets/
|
|
1225
|
-
var
|
|
1226
|
-
id = "
|
|
2222
|
+
// src/widgets/config-count-widget.ts
|
|
2223
|
+
var ConfigCountWidget = class {
|
|
2224
|
+
id = "config-count";
|
|
1227
2225
|
metadata = createWidgetMetadata(
|
|
1228
|
-
"
|
|
1229
|
-
"Displays
|
|
2226
|
+
"Config Count",
|
|
2227
|
+
"Displays Claude Code configuration counts",
|
|
1230
2228
|
"1.0.0",
|
|
1231
2229
|
"claude-scope",
|
|
1232
|
-
|
|
1233
|
-
//
|
|
2230
|
+
1
|
|
2231
|
+
// Second line
|
|
1234
2232
|
);
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
setStyle(style = "balanced") {
|
|
1242
|
-
const fn = modelStyles[style];
|
|
2233
|
+
configProvider = new ConfigProvider();
|
|
2234
|
+
configs;
|
|
2235
|
+
cwd;
|
|
2236
|
+
styleFn = configCountStyles.balanced;
|
|
2237
|
+
setStyle(style = DEFAULT_WIDGET_STYLE) {
|
|
2238
|
+
const fn = configCountStyles[style];
|
|
1243
2239
|
if (fn) {
|
|
1244
2240
|
this.styleFn = fn;
|
|
1245
2241
|
}
|
|
1246
2242
|
}
|
|
1247
|
-
|
|
2243
|
+
async initialize() {
|
|
2244
|
+
}
|
|
2245
|
+
async update(data) {
|
|
2246
|
+
this.cwd = data.cwd;
|
|
2247
|
+
this.configs = await this.configProvider.getConfigs({ cwd: data.cwd });
|
|
2248
|
+
}
|
|
2249
|
+
isEnabled() {
|
|
2250
|
+
if (!this.configs) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
2254
|
+
return claudeMdCount > 0 || rulesCount > 0 || mcpCount > 0 || hooksCount > 0;
|
|
2255
|
+
}
|
|
2256
|
+
async render(context) {
|
|
2257
|
+
if (!this.configs) {
|
|
2258
|
+
return null;
|
|
2259
|
+
}
|
|
2260
|
+
const { claudeMdCount, rulesCount, mcpCount, hooksCount } = this.configs;
|
|
1248
2261
|
const renderData = {
|
|
1249
|
-
|
|
1250
|
-
|
|
2262
|
+
claudeMdCount,
|
|
2263
|
+
rulesCount,
|
|
2264
|
+
mcpCount,
|
|
2265
|
+
hooksCount
|
|
1251
2266
|
};
|
|
1252
|
-
return this.styleFn(renderData
|
|
2267
|
+
return this.styleFn(renderData);
|
|
2268
|
+
}
|
|
2269
|
+
async cleanup() {
|
|
1253
2270
|
}
|
|
1254
2271
|
};
|
|
1255
2272
|
|
|
2273
|
+
// src/ui/utils/style-utils.ts
|
|
2274
|
+
function withLabel(prefix, value) {
|
|
2275
|
+
if (prefix === "") return value;
|
|
2276
|
+
return `${prefix}: ${value}`;
|
|
2277
|
+
}
|
|
2278
|
+
function withIndicator(value) {
|
|
2279
|
+
return `\u25CF ${value}`;
|
|
2280
|
+
}
|
|
2281
|
+
function progressBar(percent, width = 10) {
|
|
2282
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
2283
|
+
const filled = Math.round(clamped / 100 * width);
|
|
2284
|
+
const empty = width - filled;
|
|
2285
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
1256
2288
|
// src/widgets/context/styles.ts
|
|
1257
2289
|
function getContextColor(percent, colors) {
|
|
1258
2290
|
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
@@ -1347,33 +2379,6 @@ var ContextWidget = class extends StdinDataWidget {
|
|
|
1347
2379
|
}
|
|
1348
2380
|
};
|
|
1349
2381
|
|
|
1350
|
-
// src/ui/utils/formatters.ts
|
|
1351
|
-
function formatDuration(ms) {
|
|
1352
|
-
if (ms <= 0) return "0s";
|
|
1353
|
-
const seconds = Math.floor(ms / TIME.MS_PER_SECOND);
|
|
1354
|
-
const hours = Math.floor(seconds / TIME.SECONDS_PER_HOUR);
|
|
1355
|
-
const minutes = Math.floor(seconds % TIME.SECONDS_PER_HOUR / TIME.SECONDS_PER_MINUTE);
|
|
1356
|
-
const secs = seconds % TIME.SECONDS_PER_MINUTE;
|
|
1357
|
-
const parts = [];
|
|
1358
|
-
if (hours > 0) {
|
|
1359
|
-
parts.push(`${hours}h`);
|
|
1360
|
-
parts.push(`${minutes}m`);
|
|
1361
|
-
parts.push(`${secs}s`);
|
|
1362
|
-
} else if (minutes > 0) {
|
|
1363
|
-
parts.push(`${minutes}m`);
|
|
1364
|
-
parts.push(`${secs}s`);
|
|
1365
|
-
} else {
|
|
1366
|
-
parts.push(`${secs}s`);
|
|
1367
|
-
}
|
|
1368
|
-
return parts.join(" ");
|
|
1369
|
-
}
|
|
1370
|
-
function formatCostUSD(usd) {
|
|
1371
|
-
return `$${usd.toFixed(2)}`;
|
|
1372
|
-
}
|
|
1373
|
-
function colorize2(text, color) {
|
|
1374
|
-
return `${color}${text}${ANSI_COLORS.RESET}`;
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
2382
|
// src/widgets/cost/styles.ts
|
|
1378
2383
|
var costStyles = {
|
|
1379
2384
|
balanced: (data, colors) => {
|
|
@@ -1440,83 +2445,6 @@ var CostWidget = class extends StdinDataWidget {
|
|
|
1440
2445
|
}
|
|
1441
2446
|
};
|
|
1442
2447
|
|
|
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
2448
|
// src/widgets/duration/styles.ts
|
|
1521
2449
|
var durationStyles = {
|
|
1522
2450
|
balanced: (data, colors) => {
|
|
@@ -1629,277 +2557,505 @@ var DurationWidget = class extends StdinDataWidget {
|
|
|
1629
2557
|
}
|
|
1630
2558
|
};
|
|
1631
2559
|
|
|
1632
|
-
// src/
|
|
1633
|
-
var
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
2560
|
+
// src/widgets/empty-line-widget.ts
|
|
2561
|
+
var EmptyLineWidget = class extends StdinDataWidget {
|
|
2562
|
+
id = "empty-line";
|
|
2563
|
+
metadata = createWidgetMetadata(
|
|
2564
|
+
"Empty Line",
|
|
2565
|
+
"Empty line separator",
|
|
2566
|
+
"1.0.0",
|
|
2567
|
+
"claude-scope",
|
|
2568
|
+
5
|
|
2569
|
+
// Sixth line (0-indexed)
|
|
2570
|
+
);
|
|
1641
2571
|
/**
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
2572
|
+
* All styles return the same value (Braille Pattern Blank).
|
|
2573
|
+
* This method exists for API consistency with other widgets.
|
|
1644
2574
|
*/
|
|
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;
|
|
2575
|
+
setStyle(_style) {
|
|
1653
2576
|
}
|
|
1654
2577
|
/**
|
|
1655
|
-
*
|
|
2578
|
+
* Return Braille Pattern Blank to create a visible empty separator line.
|
|
2579
|
+
* U+2800 occupies cell width but appears blank, ensuring the line renders.
|
|
1656
2580
|
*/
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
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
|
-
}
|
|
2581
|
+
renderWithData(_data, _context) {
|
|
2582
|
+
return "\u2800";
|
|
2583
|
+
}
|
|
2584
|
+
};
|
|
2585
|
+
|
|
2586
|
+
// src/providers/git-provider.ts
|
|
2587
|
+
var import_node_child_process = require("node:child_process");
|
|
2588
|
+
var import_node_util = require("node:util");
|
|
2589
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
2590
|
+
var NativeGit = class {
|
|
2591
|
+
cwd;
|
|
2592
|
+
constructor(cwd) {
|
|
2593
|
+
this.cwd = cwd;
|
|
2594
|
+
}
|
|
2595
|
+
async status() {
|
|
2596
|
+
try {
|
|
2597
|
+
const { stdout } = await execFileAsync("git", ["status", "--branch", "--short"], {
|
|
2598
|
+
cwd: this.cwd
|
|
2599
|
+
});
|
|
2600
|
+
const match = stdout.match(/^##\s+(\S+)/m);
|
|
2601
|
+
const current = match ? match[1] : null;
|
|
2602
|
+
return { current };
|
|
2603
|
+
} catch {
|
|
2604
|
+
return { current: null };
|
|
1712
2605
|
}
|
|
1713
|
-
return { claudeMdCount, rulesCount, mcpCount, hooksCount };
|
|
1714
2606
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
2607
|
+
async diffSummary(options) {
|
|
2608
|
+
const args = ["diff", "--shortstat"];
|
|
2609
|
+
if (options) {
|
|
2610
|
+
args.push(...options);
|
|
2611
|
+
}
|
|
1719
2612
|
try {
|
|
1720
|
-
await
|
|
1721
|
-
|
|
2613
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
2614
|
+
cwd: this.cwd
|
|
2615
|
+
});
|
|
2616
|
+
const fileMatch = stdout.match(/(\d+)\s+file(s?)\s+changed/);
|
|
2617
|
+
const insertionMatch = stdout.match(/(\d+)\s+insertion/);
|
|
2618
|
+
const deletionMatch = stdout.match(/(\d+)\s+deletion/);
|
|
2619
|
+
const fileCount = fileMatch ? parseInt(fileMatch[1], 10) : 0;
|
|
2620
|
+
const insertions = insertionMatch ? parseInt(insertionMatch[1], 10) : 0;
|
|
2621
|
+
const deletions = deletionMatch ? parseInt(deletionMatch[1], 10) : 0;
|
|
2622
|
+
const files = insertions > 0 || deletions > 0 ? [{ file: "(total)", insertions, deletions }] : [];
|
|
2623
|
+
return { fileCount, files };
|
|
1722
2624
|
} catch {
|
|
1723
|
-
return
|
|
2625
|
+
return { fileCount: 0, files: [] };
|
|
1724
2626
|
}
|
|
1725
2627
|
}
|
|
1726
|
-
|
|
1727
|
-
* Read and parse JSON file
|
|
1728
|
-
*/
|
|
1729
|
-
async readJsonFile(filePath) {
|
|
2628
|
+
async latestTag() {
|
|
1730
2629
|
try {
|
|
1731
|
-
const
|
|
1732
|
-
|
|
2630
|
+
const { stdout } = await execFileAsync("git", ["describe", "--tags", "--abbrev=0"], {
|
|
2631
|
+
cwd: this.cwd
|
|
2632
|
+
});
|
|
2633
|
+
return stdout.trim();
|
|
1733
2634
|
} catch {
|
|
1734
2635
|
return null;
|
|
1735
2636
|
}
|
|
1736
2637
|
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2638
|
+
};
|
|
2639
|
+
function createGit(cwd) {
|
|
2640
|
+
return new NativeGit(cwd);
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// src/widgets/git-tag/styles.ts
|
|
2644
|
+
var gitTagStyles = {
|
|
2645
|
+
balanced: (data, colors) => {
|
|
2646
|
+
const tag = data.tag || "\u2014";
|
|
2647
|
+
if (!colors) return tag;
|
|
2648
|
+
return colorize(tag, colors.branch);
|
|
2649
|
+
},
|
|
2650
|
+
compact: (data, colors) => {
|
|
2651
|
+
if (!data.tag) return "\u2014";
|
|
2652
|
+
const tag = data.tag.replace(/^v/, "");
|
|
2653
|
+
if (!colors) return tag;
|
|
2654
|
+
return colorize(tag, colors.branch);
|
|
2655
|
+
},
|
|
2656
|
+
playful: (data, colors) => {
|
|
2657
|
+
const tag = data.tag || "\u2014";
|
|
2658
|
+
if (!colors) return `\u{1F3F7}\uFE0F ${tag}`;
|
|
2659
|
+
return `\u{1F3F7}\uFE0F ${colorize(tag, colors.branch)}`;
|
|
2660
|
+
},
|
|
2661
|
+
verbose: (data, colors) => {
|
|
2662
|
+
if (!data.tag) return "version: none";
|
|
2663
|
+
const tag = `version ${data.tag}`;
|
|
2664
|
+
if (!colors) return tag;
|
|
2665
|
+
return `version ${colorize(data.tag, colors.branch)}`;
|
|
2666
|
+
},
|
|
2667
|
+
labeled: (data, colors) => {
|
|
2668
|
+
const tag = data.tag || "none";
|
|
2669
|
+
if (!colors) return withLabel("Tag", tag);
|
|
2670
|
+
return withLabel("Tag", colorize(tag, colors.branch));
|
|
2671
|
+
},
|
|
2672
|
+
indicator: (data, colors) => {
|
|
2673
|
+
const tag = data.tag || "\u2014";
|
|
2674
|
+
if (!colors) return withIndicator(tag);
|
|
2675
|
+
return withIndicator(colorize(tag, colors.branch));
|
|
1745
2676
|
}
|
|
2677
|
+
};
|
|
2678
|
+
|
|
2679
|
+
// src/widgets/git/git-tag-widget.ts
|
|
2680
|
+
var GitTagWidget = class {
|
|
2681
|
+
id = "git-tag";
|
|
2682
|
+
metadata = createWidgetMetadata(
|
|
2683
|
+
"Git Tag Widget",
|
|
2684
|
+
"Displays the latest git tag",
|
|
2685
|
+
"1.0.0",
|
|
2686
|
+
"claude-scope",
|
|
2687
|
+
1
|
|
2688
|
+
// Second line
|
|
2689
|
+
);
|
|
2690
|
+
gitFactory;
|
|
2691
|
+
git = null;
|
|
2692
|
+
enabled = true;
|
|
2693
|
+
cwd = null;
|
|
2694
|
+
colors;
|
|
2695
|
+
styleFn = gitTagStyles.balanced;
|
|
1746
2696
|
/**
|
|
1747
|
-
*
|
|
2697
|
+
* @param gitFactory - Optional factory function for creating IGit instances
|
|
2698
|
+
* If not provided, uses default createGit (production)
|
|
2699
|
+
* Tests can inject MockGit factory here
|
|
2700
|
+
* @param colors - Optional theme colors
|
|
1748
2701
|
*/
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
2702
|
+
constructor(gitFactory, colors) {
|
|
2703
|
+
this.gitFactory = gitFactory || createGit;
|
|
2704
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2705
|
+
}
|
|
2706
|
+
setStyle(style = "balanced") {
|
|
2707
|
+
const fn = gitTagStyles[style];
|
|
2708
|
+
if (fn) {
|
|
2709
|
+
this.styleFn = fn;
|
|
1752
2710
|
}
|
|
1753
|
-
return Object.keys(config.hooks).length;
|
|
1754
2711
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
async
|
|
1759
|
-
|
|
1760
|
-
|
|
2712
|
+
async initialize(context) {
|
|
2713
|
+
this.enabled = context.config?.enabled !== false;
|
|
2714
|
+
}
|
|
2715
|
+
async render(context) {
|
|
2716
|
+
if (!this.enabled || !this.git || !this.cwd) {
|
|
2717
|
+
return null;
|
|
2718
|
+
}
|
|
1761
2719
|
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;
|
|
2720
|
+
const latestTag = await (this.git.latestTag?.() ?? Promise.resolve(null));
|
|
2721
|
+
const renderData = { tag: latestTag };
|
|
2722
|
+
return this.styleFn(renderData, this.colors.git);
|
|
1773
2723
|
} catch {
|
|
1774
|
-
return
|
|
2724
|
+
return null;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
async update(data) {
|
|
2728
|
+
if (data.cwd !== this.cwd) {
|
|
2729
|
+
this.cwd = data.cwd;
|
|
2730
|
+
this.git = this.gitFactory(data.cwd);
|
|
1775
2731
|
}
|
|
1776
2732
|
}
|
|
2733
|
+
isEnabled() {
|
|
2734
|
+
return this.enabled;
|
|
2735
|
+
}
|
|
2736
|
+
async cleanup() {
|
|
2737
|
+
}
|
|
1777
2738
|
};
|
|
1778
2739
|
|
|
1779
|
-
// src/widgets/
|
|
1780
|
-
var
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
parts.push(
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
2740
|
+
// src/widgets/git/styles.ts
|
|
2741
|
+
var gitStyles = {
|
|
2742
|
+
minimal: (data, colors) => {
|
|
2743
|
+
if (!colors) return data.branch;
|
|
2744
|
+
return colorize(data.branch, colors.branch);
|
|
2745
|
+
},
|
|
2746
|
+
balanced: (data, colors) => {
|
|
2747
|
+
if (data.changes && data.changes.files > 0) {
|
|
2748
|
+
const parts = [];
|
|
2749
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2750
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2751
|
+
if (parts.length > 0) {
|
|
2752
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2753
|
+
const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
|
|
2754
|
+
return `${branch} ${changes}`;
|
|
2755
|
+
}
|
|
1795
2756
|
}
|
|
1796
|
-
return
|
|
2757
|
+
return colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
1797
2758
|
},
|
|
1798
|
-
compact: (data) => {
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
parts.push(
|
|
2759
|
+
compact: (data, colors) => {
|
|
2760
|
+
if (data.changes && data.changes.files > 0) {
|
|
2761
|
+
const parts = [];
|
|
2762
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2763
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2764
|
+
if (parts.length > 0) {
|
|
2765
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2766
|
+
const changesStr = parts.join("/");
|
|
2767
|
+
return `${branch} ${changesStr}`;
|
|
2768
|
+
}
|
|
1803
2769
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
2770
|
+
return colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2771
|
+
},
|
|
2772
|
+
playful: (data, colors) => {
|
|
2773
|
+
if (data.changes && data.changes.files > 0) {
|
|
2774
|
+
const parts = [];
|
|
2775
|
+
if (data.changes.insertions > 0) parts.push(`\u2B06${data.changes.insertions}`);
|
|
2776
|
+
if (data.changes.deletions > 0) parts.push(`\u2B07${data.changes.deletions}`);
|
|
2777
|
+
if (parts.length > 0) {
|
|
2778
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2779
|
+
return `\u{1F500} ${branch2} ${parts.join(" ")}`;
|
|
2780
|
+
}
|
|
1806
2781
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
2782
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2783
|
+
return `\u{1F500} ${branch}`;
|
|
2784
|
+
},
|
|
2785
|
+
verbose: (data, colors) => {
|
|
2786
|
+
if (data.changes && data.changes.files > 0) {
|
|
2787
|
+
const parts = [];
|
|
2788
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions} insertions`);
|
|
2789
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions} deletions`);
|
|
2790
|
+
if (parts.length > 0) {
|
|
2791
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2792
|
+
const changes = colors ? colorize(`[${parts.join(", ")}]`, colors.changes) : `[${parts.join(", ")}]`;
|
|
2793
|
+
return `branch: ${branch2} ${changes}`;
|
|
2794
|
+
}
|
|
1809
2795
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2796
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2797
|
+
return `branch: ${branch} (HEAD)`;
|
|
2798
|
+
},
|
|
2799
|
+
labeled: (data, colors) => {
|
|
2800
|
+
if (data.changes && data.changes.files > 0) {
|
|
2801
|
+
const parts = [];
|
|
2802
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2803
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2804
|
+
if (parts.length > 0) {
|
|
2805
|
+
const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2806
|
+
const changes = `${data.changes.files} files: ${parts.join("/")}`;
|
|
2807
|
+
return `Git: ${branch2} [${changes}]`;
|
|
2808
|
+
}
|
|
1813
2809
|
}
|
|
1814
|
-
|
|
2810
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2811
|
+
return `Git: ${branch}`;
|
|
1815
2812
|
},
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
parts.push(
|
|
2813
|
+
indicator: (data, colors) => {
|
|
2814
|
+
if (data.changes && data.changes.files > 0) {
|
|
2815
|
+
const parts = [];
|
|
2816
|
+
if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
|
|
2817
|
+
if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
|
|
2818
|
+
if (parts.length > 0) {
|
|
2819
|
+
const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
|
|
2820
|
+
const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
|
|
2821
|
+
return `\u25CF ${branch} ${changes}`;
|
|
2822
|
+
}
|
|
1821
2823
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
2824
|
+
return withIndicator(colors ? colorize(data.branch, colors.branch) : data.branch);
|
|
2825
|
+
}
|
|
2826
|
+
};
|
|
2827
|
+
|
|
2828
|
+
// src/widgets/git/git-widget.ts
|
|
2829
|
+
var GitWidget = class {
|
|
2830
|
+
id = "git";
|
|
2831
|
+
metadata = createWidgetMetadata(
|
|
2832
|
+
"Git Widget",
|
|
2833
|
+
"Displays current git branch",
|
|
2834
|
+
"1.0.0",
|
|
2835
|
+
"claude-scope",
|
|
2836
|
+
0
|
|
2837
|
+
// First line
|
|
2838
|
+
);
|
|
2839
|
+
gitFactory;
|
|
2840
|
+
git = null;
|
|
2841
|
+
enabled = true;
|
|
2842
|
+
cwd = null;
|
|
2843
|
+
colors;
|
|
2844
|
+
styleFn = gitStyles.balanced;
|
|
2845
|
+
/**
|
|
2846
|
+
* @param gitFactory - Optional factory function for creating IGit instances
|
|
2847
|
+
* If not provided, uses default createGit (production)
|
|
2848
|
+
* Tests can inject MockGit factory here
|
|
2849
|
+
* @param colors - Optional theme colors
|
|
2850
|
+
*/
|
|
2851
|
+
constructor(gitFactory, colors) {
|
|
2852
|
+
this.gitFactory = gitFactory || createGit;
|
|
2853
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2854
|
+
}
|
|
2855
|
+
setStyle(style = "balanced") {
|
|
2856
|
+
const fn = gitStyles[style];
|
|
2857
|
+
if (fn) {
|
|
2858
|
+
this.styleFn = fn;
|
|
1824
2859
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
2860
|
+
}
|
|
2861
|
+
async initialize(context) {
|
|
2862
|
+
this.enabled = context.config?.enabled !== false;
|
|
2863
|
+
}
|
|
2864
|
+
async render(context) {
|
|
2865
|
+
if (!this.enabled || !this.git || !this.cwd) {
|
|
2866
|
+
return null;
|
|
1827
2867
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
2868
|
+
try {
|
|
2869
|
+
const status = await this.git.status();
|
|
2870
|
+
const branch = status.current || null;
|
|
2871
|
+
if (!branch) {
|
|
2872
|
+
return null;
|
|
2873
|
+
}
|
|
2874
|
+
let changes;
|
|
2875
|
+
try {
|
|
2876
|
+
const diffSummary = await this.git.diffSummary();
|
|
2877
|
+
if (diffSummary.fileCount > 0) {
|
|
2878
|
+
let insertions = 0;
|
|
2879
|
+
let deletions = 0;
|
|
2880
|
+
for (const file of diffSummary.files) {
|
|
2881
|
+
insertions += file.insertions || 0;
|
|
2882
|
+
deletions += file.deletions || 0;
|
|
2883
|
+
}
|
|
2884
|
+
if (insertions > 0 || deletions > 0) {
|
|
2885
|
+
changes = { files: diffSummary.fileCount, insertions, deletions };
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
} catch {
|
|
2889
|
+
}
|
|
2890
|
+
const renderData = { branch, changes };
|
|
2891
|
+
return this.styleFn(renderData, this.colors.git);
|
|
2892
|
+
} catch {
|
|
2893
|
+
return null;
|
|
1830
2894
|
}
|
|
1831
|
-
|
|
2895
|
+
}
|
|
2896
|
+
async update(data) {
|
|
2897
|
+
if (data.cwd !== this.cwd) {
|
|
2898
|
+
this.cwd = data.cwd;
|
|
2899
|
+
this.git = this.gitFactory(data.cwd);
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
isEnabled() {
|
|
2903
|
+
return this.enabled;
|
|
2904
|
+
}
|
|
2905
|
+
async cleanup() {
|
|
2906
|
+
}
|
|
2907
|
+
};
|
|
2908
|
+
|
|
2909
|
+
// src/widgets/lines/styles.ts
|
|
2910
|
+
var linesStyles = {
|
|
2911
|
+
balanced: (data, colors) => {
|
|
2912
|
+
if (!colors) return `+${data.added}/-${data.removed}`;
|
|
2913
|
+
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
2914
|
+
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
2915
|
+
return `${addedStr}/${removedStr}`;
|
|
1832
2916
|
},
|
|
1833
|
-
|
|
1834
|
-
|
|
2917
|
+
compact: (data, colors) => {
|
|
2918
|
+
if (!colors) return `+${data.added}-${data.removed}`;
|
|
2919
|
+
const addedStr = colorize(`+${data.added}`, colors.added);
|
|
2920
|
+
const removedStr = colorize(`-${data.removed}`, colors.removed);
|
|
2921
|
+
return `${addedStr}${removedStr}`;
|
|
2922
|
+
},
|
|
2923
|
+
playful: (data, colors) => {
|
|
2924
|
+
if (!colors) return `\u2795${data.added} \u2796${data.removed}`;
|
|
2925
|
+
const addedStr = colorize(`\u2795${data.added}`, colors.added);
|
|
2926
|
+
const removedStr = colorize(`\u2796${data.removed}`, colors.removed);
|
|
2927
|
+
return `${addedStr} ${removedStr}`;
|
|
2928
|
+
},
|
|
2929
|
+
verbose: (data, colors) => {
|
|
1835
2930
|
const parts = [];
|
|
1836
|
-
if (
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
if (rulesCount > 0) {
|
|
1840
|
-
parts.push(`${rulesCount} rules`);
|
|
2931
|
+
if (data.added > 0) {
|
|
2932
|
+
const text = `+${data.added} added`;
|
|
2933
|
+
parts.push(colors ? colorize(text, colors.added) : text);
|
|
1841
2934
|
}
|
|
1842
|
-
if (
|
|
1843
|
-
|
|
2935
|
+
if (data.removed > 0) {
|
|
2936
|
+
const text = `-${data.removed} removed`;
|
|
2937
|
+
parts.push(colors ? colorize(text, colors.removed) : text);
|
|
1844
2938
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
2939
|
+
return parts.join(", ");
|
|
2940
|
+
},
|
|
2941
|
+
labeled: (data, colors) => {
|
|
2942
|
+
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
2943
|
+
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
2944
|
+
const lines = `${addedStr}/${removedStr}`;
|
|
2945
|
+
return withLabel("Lines", lines);
|
|
2946
|
+
},
|
|
2947
|
+
indicator: (data, colors) => {
|
|
2948
|
+
const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
|
|
2949
|
+
const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
|
|
2950
|
+
const lines = `${addedStr}/${removedStr}`;
|
|
2951
|
+
return withIndicator(lines);
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
|
|
2955
|
+
// src/widgets/lines-widget.ts
|
|
2956
|
+
var LinesWidget = class extends StdinDataWidget {
|
|
2957
|
+
id = "lines";
|
|
2958
|
+
metadata = createWidgetMetadata(
|
|
2959
|
+
"Lines",
|
|
2960
|
+
"Displays lines added/removed in session",
|
|
2961
|
+
"1.0.0",
|
|
2962
|
+
"claude-scope",
|
|
2963
|
+
0
|
|
2964
|
+
// First line
|
|
2965
|
+
);
|
|
2966
|
+
colors;
|
|
2967
|
+
styleFn = linesStyles.balanced;
|
|
2968
|
+
constructor(colors) {
|
|
2969
|
+
super();
|
|
2970
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
2971
|
+
}
|
|
2972
|
+
setStyle(style = "balanced") {
|
|
2973
|
+
const fn = linesStyles[style];
|
|
2974
|
+
if (fn) {
|
|
2975
|
+
this.styleFn = fn;
|
|
1847
2976
|
}
|
|
1848
|
-
|
|
2977
|
+
}
|
|
2978
|
+
renderWithData(data, _context) {
|
|
2979
|
+
const added = data.cost?.total_lines_added ?? 0;
|
|
2980
|
+
const removed = data.cost?.total_lines_removed ?? 0;
|
|
2981
|
+
const renderData = { added, removed };
|
|
2982
|
+
return this.styleFn(renderData, this.colors.lines);
|
|
1849
2983
|
}
|
|
1850
2984
|
};
|
|
1851
2985
|
|
|
1852
|
-
// src/
|
|
1853
|
-
|
|
2986
|
+
// src/widgets/model/styles.ts
|
|
2987
|
+
function getShortName(displayName) {
|
|
2988
|
+
return displayName.replace(/^Claude\s+/, "");
|
|
2989
|
+
}
|
|
2990
|
+
var modelStyles = {
|
|
2991
|
+
balanced: (data, colors) => {
|
|
2992
|
+
if (!colors) return data.displayName;
|
|
2993
|
+
return colorize(data.displayName, colors.name);
|
|
2994
|
+
},
|
|
2995
|
+
compact: (data, colors) => {
|
|
2996
|
+
const shortName = getShortName(data.displayName);
|
|
2997
|
+
if (!colors) return shortName;
|
|
2998
|
+
return colorize(shortName, colors.name);
|
|
2999
|
+
},
|
|
3000
|
+
playful: (data, colors) => {
|
|
3001
|
+
const shortName = getShortName(data.displayName);
|
|
3002
|
+
if (!colors) return `\u{1F916} ${shortName}`;
|
|
3003
|
+
return `\u{1F916} ${colorize(shortName, colors.name)}`;
|
|
3004
|
+
},
|
|
3005
|
+
technical: (data, colors) => {
|
|
3006
|
+
if (!colors) return data.id;
|
|
3007
|
+
const match = data.id.match(/^(.+?)-(\d[\d.]*)$/);
|
|
3008
|
+
if (match) {
|
|
3009
|
+
return colorize(match[1], colors.name) + colorize(`-${match[2]}`, colors.version);
|
|
3010
|
+
}
|
|
3011
|
+
return colorize(data.id, colors.name);
|
|
3012
|
+
},
|
|
3013
|
+
symbolic: (data, colors) => {
|
|
3014
|
+
const shortName = getShortName(data.displayName);
|
|
3015
|
+
if (!colors) return `\u25C6 ${shortName}`;
|
|
3016
|
+
return `\u25C6 ${colorize(shortName, colors.name)}`;
|
|
3017
|
+
},
|
|
3018
|
+
labeled: (data, colors) => {
|
|
3019
|
+
const shortName = getShortName(data.displayName);
|
|
3020
|
+
if (!colors) return withLabel("Model", shortName);
|
|
3021
|
+
return withLabel("Model", colorize(shortName, colors.name));
|
|
3022
|
+
},
|
|
3023
|
+
indicator: (data, colors) => {
|
|
3024
|
+
const shortName = getShortName(data.displayName);
|
|
3025
|
+
if (!colors) return withIndicator(shortName);
|
|
3026
|
+
return withIndicator(colorize(shortName, colors.name));
|
|
3027
|
+
}
|
|
3028
|
+
};
|
|
1854
3029
|
|
|
1855
|
-
// src/widgets/
|
|
1856
|
-
var
|
|
1857
|
-
id = "
|
|
3030
|
+
// src/widgets/model-widget.ts
|
|
3031
|
+
var ModelWidget = class extends StdinDataWidget {
|
|
3032
|
+
id = "model";
|
|
1858
3033
|
metadata = createWidgetMetadata(
|
|
1859
|
-
"
|
|
1860
|
-
"Displays Claude
|
|
3034
|
+
"Model",
|
|
3035
|
+
"Displays the current Claude model name",
|
|
1861
3036
|
"1.0.0",
|
|
1862
3037
|
"claude-scope",
|
|
1863
|
-
|
|
1864
|
-
//
|
|
3038
|
+
0
|
|
3039
|
+
// First line
|
|
1865
3040
|
);
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
3041
|
+
colors;
|
|
3042
|
+
styleFn = modelStyles.balanced;
|
|
3043
|
+
constructor(colors) {
|
|
3044
|
+
super();
|
|
3045
|
+
this.colors = colors ?? DEFAULT_THEME;
|
|
3046
|
+
}
|
|
3047
|
+
setStyle(style = "balanced") {
|
|
3048
|
+
const fn = modelStyles[style];
|
|
1872
3049
|
if (fn) {
|
|
1873
3050
|
this.styleFn = fn;
|
|
1874
3051
|
}
|
|
1875
3052
|
}
|
|
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;
|
|
3053
|
+
renderWithData(data, _context) {
|
|
1894
3054
|
const renderData = {
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
mcpCount,
|
|
1898
|
-
hooksCount
|
|
3055
|
+
displayName: data.model.display_name,
|
|
3056
|
+
id: data.model.id
|
|
1899
3057
|
};
|
|
1900
|
-
return this.styleFn(renderData);
|
|
1901
|
-
}
|
|
1902
|
-
async cleanup() {
|
|
3058
|
+
return this.styleFn(renderData, this.colors.model);
|
|
1903
3059
|
}
|
|
1904
3060
|
};
|
|
1905
3061
|
|
|
@@ -2114,7 +3270,8 @@ function getStraightIndices(cards, highCard) {
|
|
|
2114
3270
|
indices.push(cardIndicesByRank.get(next1)[0]);
|
|
2115
3271
|
indices.push(cardIndicesByRank.get(next2)[0]);
|
|
2116
3272
|
indices.push(cardIndicesByRank.get(next3)[0]);
|
|
2117
|
-
|
|
3273
|
+
const rank4 = next4 === 1 ? 14 : next4;
|
|
3274
|
+
indices.push(cardIndicesByRank.get(rank4)[0]);
|
|
2118
3275
|
return indices;
|
|
2119
3276
|
}
|
|
2120
3277
|
}
|
|
@@ -2451,8 +3608,8 @@ var PokerWidget = class extends StdinDataWidget {
|
|
|
2451
3608
|
"Displays random Texas Hold'em hands for entertainment",
|
|
2452
3609
|
"1.0.0",
|
|
2453
3610
|
"claude-scope",
|
|
2454
|
-
|
|
2455
|
-
//
|
|
3611
|
+
4
|
|
3612
|
+
// Fifth line (0-indexed)
|
|
2456
3613
|
);
|
|
2457
3614
|
holeCards = [];
|
|
2458
3615
|
boardCards = [];
|
|
@@ -2478,7 +3635,7 @@ var PokerWidget = class extends StdinDataWidget {
|
|
|
2478
3635
|
async update(data) {
|
|
2479
3636
|
await super.update(data);
|
|
2480
3637
|
const now = Date.now();
|
|
2481
|
-
if (now - this.lastUpdateTimestamp < this.THROTTLE_MS) {
|
|
3638
|
+
if (this.lastUpdateTimestamp > 0 && now - this.lastUpdateTimestamp < this.THROTTLE_MS) {
|
|
2482
3639
|
return;
|
|
2483
3640
|
}
|
|
2484
3641
|
const deck = new Deck();
|
|
@@ -2545,207 +3702,6 @@ var PokerWidget = class extends StdinDataWidget {
|
|
|
2545
3702
|
}
|
|
2546
3703
|
};
|
|
2547
3704
|
|
|
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
3705
|
// src/index.ts
|
|
2750
3706
|
async function readStdin() {
|
|
2751
3707
|
const chunks = [];
|
|
@@ -2764,6 +3720,7 @@ async function main() {
|
|
|
2764
3720
|
const provider = new StdinProvider();
|
|
2765
3721
|
const stdinData = await provider.parse(stdin);
|
|
2766
3722
|
const registry = new WidgetRegistry();
|
|
3723
|
+
const transcriptProvider = new TranscriptProvider();
|
|
2767
3724
|
await registry.register(new ModelWidget());
|
|
2768
3725
|
await registry.register(new ContextWidget());
|
|
2769
3726
|
await registry.register(new CostWidget());
|
|
@@ -2772,6 +3729,12 @@ async function main() {
|
|
|
2772
3729
|
await registry.register(new GitWidget());
|
|
2773
3730
|
await registry.register(new GitTagWidget());
|
|
2774
3731
|
await registry.register(new ConfigCountWidget());
|
|
3732
|
+
if (isWidgetEnabled("cacheMetrics")) {
|
|
3733
|
+
await registry.register(new CacheMetricsWidget(DEFAULT_THEME));
|
|
3734
|
+
}
|
|
3735
|
+
if (isWidgetEnabled("activeTools")) {
|
|
3736
|
+
await registry.register(new ActiveToolsWidget(DEFAULT_THEME, transcriptProvider));
|
|
3737
|
+
}
|
|
2775
3738
|
await registry.register(new PokerWidget());
|
|
2776
3739
|
await registry.register(new EmptyLineWidget());
|
|
2777
3740
|
const renderer = new Renderer({
|