claude-scope 0.8.15 → 0.8.18
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/README.md +223 -82
- package/dist/claude-scope.cjs +1207 -401
- package/package.json +1 -1
package/dist/claude-scope.cjs
CHANGED
|
@@ -38,12 +38,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
38
38
|
function colorize(text, color) {
|
|
39
39
|
return `${color}${text}${reset}`;
|
|
40
40
|
}
|
|
41
|
-
var reset, gray;
|
|
41
|
+
var reset, red, gray, lightGray, bold;
|
|
42
42
|
var init_colors = __esm({
|
|
43
43
|
"src/ui/utils/colors.ts"() {
|
|
44
44
|
"use strict";
|
|
45
45
|
reset = "\x1B[0m";
|
|
46
|
+
red = "\x1B[31m";
|
|
46
47
|
gray = "\x1B[90m";
|
|
48
|
+
lightGray = "\x1B[37m";
|
|
49
|
+
bold = "\x1B[1m";
|
|
47
50
|
}
|
|
48
51
|
});
|
|
49
52
|
|
|
@@ -1378,7 +1381,7 @@ var init_theme = __esm({
|
|
|
1378
1381
|
});
|
|
1379
1382
|
|
|
1380
1383
|
// src/constants.ts
|
|
1381
|
-
var TIME, DEFAULTS, DEMO_DATA, DEFAULT_PROGRESS_BAR_WIDTH;
|
|
1384
|
+
var TIME, DEFAULTS, ANSI_COLORS, DEMO_DATA, DEFAULT_PROGRESS_BAR_WIDTH;
|
|
1382
1385
|
var init_constants = __esm({
|
|
1383
1386
|
"src/constants.ts"() {
|
|
1384
1387
|
"use strict";
|
|
@@ -1396,6 +1399,16 @@ var init_constants = __esm({
|
|
|
1396
1399
|
/** Default width for progress bars in characters */
|
|
1397
1400
|
PROGRESS_BAR_WIDTH: 20
|
|
1398
1401
|
};
|
|
1402
|
+
ANSI_COLORS = {
|
|
1403
|
+
/** Green color */
|
|
1404
|
+
GREEN: "\x1B[32m",
|
|
1405
|
+
/** Yellow color */
|
|
1406
|
+
YELLOW: "\x1B[33m",
|
|
1407
|
+
/** Red color */
|
|
1408
|
+
RED: "\x1B[31m",
|
|
1409
|
+
/** Reset color */
|
|
1410
|
+
RESET: "\x1B[0m"
|
|
1411
|
+
};
|
|
1399
1412
|
DEMO_DATA = {
|
|
1400
1413
|
/** Demo session cost in USD */
|
|
1401
1414
|
COST_USD: 0.42,
|
|
@@ -1471,7 +1484,7 @@ var init_renderer = __esm({
|
|
|
1471
1484
|
for (const widget of widgetsForLine) {
|
|
1472
1485
|
try {
|
|
1473
1486
|
const output = await widget.render(context);
|
|
1474
|
-
if (output
|
|
1487
|
+
if (output && output.trim().length > 0) {
|
|
1475
1488
|
outputs.push(output);
|
|
1476
1489
|
}
|
|
1477
1490
|
} catch (error) {
|
|
@@ -1952,27 +1965,58 @@ var init_styles = __esm({
|
|
|
1952
1965
|
return compactStyle(data, colors2);
|
|
1953
1966
|
},
|
|
1954
1967
|
/**
|
|
1955
|
-
* playful: Emojis (📖✏️✨🔄🔍📁) with tool
|
|
1968
|
+
* playful: Emojis (📖✏️✨🔄🔍📁) with tool counts (like balanced but more fun)
|
|
1969
|
+
* - Shows running + completed counts like balanced style
|
|
1970
|
+
* - Uses emojis instead of text labels for a more playful look
|
|
1956
1971
|
*/
|
|
1957
1972
|
playful: (data, colors2) => {
|
|
1958
1973
|
const parts = [];
|
|
1974
|
+
const c = colors2 ?? getDefaultColors();
|
|
1959
1975
|
const emojis = {
|
|
1960
1976
|
Read: "\u{1F4D6}",
|
|
1961
1977
|
Write: "\u270F\uFE0F",
|
|
1962
1978
|
Edit: "\u2728",
|
|
1963
1979
|
Bash: "\u{1F504}",
|
|
1964
1980
|
Grep: "\u{1F50D}",
|
|
1965
|
-
Glob: "\u{1F4C1}"
|
|
1981
|
+
Glob: "\u{1F4C1}",
|
|
1982
|
+
Task: "\u{1F4CB}"
|
|
1966
1983
|
};
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1984
|
+
const allToolNames = /* @__PURE__ */ new Set();
|
|
1985
|
+
for (const tool of data.running) {
|
|
1986
|
+
allToolNames.add(tool.name);
|
|
1987
|
+
}
|
|
1988
|
+
for (const [name] of data.completed.slice(0, 3)) {
|
|
1989
|
+
allToolNames.add(name);
|
|
1990
|
+
}
|
|
1991
|
+
const completedMap = new Map(data.completed);
|
|
1992
|
+
const runningCounts = /* @__PURE__ */ new Map();
|
|
1993
|
+
for (const tool of data.running) {
|
|
1994
|
+
runningCounts.set(tool.name, (runningCounts.get(tool.name) ?? 0) + 1);
|
|
1995
|
+
}
|
|
1996
|
+
for (const name of allToolNames) {
|
|
1997
|
+
const runningCount = runningCounts.get(name) ?? 0;
|
|
1998
|
+
const completedCount = completedMap.get(name) ?? 0;
|
|
1999
|
+
const emoji = emojis[name] ?? "\u{1F527}";
|
|
2000
|
+
if (runningCount > 0 && completedCount > 0) {
|
|
2001
|
+
const nameStr = colorize(name, c.tools.name);
|
|
2002
|
+
const runningStr = colorize(`\u25B6${runningCount}`, c.tools.running);
|
|
2003
|
+
const doneStr = colorize(`\u2713${completedCount}`, c.tools.completed);
|
|
2004
|
+
parts.push(`${emoji} ${nameStr} (${runningStr}, ${doneStr})`);
|
|
2005
|
+
} else if (completedCount > 0) {
|
|
2006
|
+
const pluralName = pluralizeTool(name);
|
|
2007
|
+
const nameStr = colorize(pluralName, c.tools.name);
|
|
2008
|
+
const countStr = colorize(`${completedCount}`, c.tools.count);
|
|
2009
|
+
parts.push(`${emoji} ${nameStr}: ${countStr}`);
|
|
2010
|
+
} else if (runningCount > 0) {
|
|
2011
|
+
const nameStr = colorize(name, c.tools.name);
|
|
2012
|
+
const runningStr = colorize(`\u25B6${runningCount}`, c.tools.running);
|
|
2013
|
+
parts.push(`${emoji} ${nameStr} (${runningStr})`);
|
|
2014
|
+
}
|
|
1971
2015
|
}
|
|
1972
2016
|
if (parts.length === 0) {
|
|
1973
2017
|
return "";
|
|
1974
2018
|
}
|
|
1975
|
-
return parts.join("
|
|
2019
|
+
return parts.join(" | ");
|
|
1976
2020
|
},
|
|
1977
2021
|
/**
|
|
1978
2022
|
* verbose: Full text labels "Running:" and "Completed:"
|
|
@@ -2318,6 +2362,9 @@ function formatDuration(ms) {
|
|
|
2318
2362
|
function formatCostUSD(usd) {
|
|
2319
2363
|
return `$${usd.toFixed(2)}`;
|
|
2320
2364
|
}
|
|
2365
|
+
function colorize2(text, color) {
|
|
2366
|
+
return `${color}${text}${ANSI_COLORS.RESET}`;
|
|
2367
|
+
}
|
|
2321
2368
|
function formatK(n) {
|
|
2322
2369
|
const absN = Math.abs(n);
|
|
2323
2370
|
if (absN < 1e3) {
|
|
@@ -3189,6 +3236,472 @@ var init_cost_widget = __esm({
|
|
|
3189
3236
|
}
|
|
3190
3237
|
});
|
|
3191
3238
|
|
|
3239
|
+
// src/widgets/dev-server/port-detector.ts
|
|
3240
|
+
var import_node_child_process, import_node_util, execFileAsync, PORT_MAPPING, DEV_PORTS, PortDetector;
|
|
3241
|
+
var init_port_detector = __esm({
|
|
3242
|
+
"src/widgets/dev-server/port-detector.ts"() {
|
|
3243
|
+
"use strict";
|
|
3244
|
+
import_node_child_process = require("node:child_process");
|
|
3245
|
+
import_node_util = require("node:util");
|
|
3246
|
+
execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
3247
|
+
PORT_MAPPING = {
|
|
3248
|
+
5173: { name: "Vite", icon: "\u26A1" },
|
|
3249
|
+
4200: { name: "Angular", icon: "\u25B2" },
|
|
3250
|
+
3e3: { name: "Dev", icon: "\u{1F680}" },
|
|
3251
|
+
8080: { name: "Webpack", icon: "\u{1F4E6}" },
|
|
3252
|
+
8e3: { name: "Dev", icon: "\u{1F680}" },
|
|
3253
|
+
8888: { name: "Dev", icon: "\u{1F680}" }
|
|
3254
|
+
};
|
|
3255
|
+
DEV_PORTS = [5173, 4200, 3e3, 8080, 8e3, 8888];
|
|
3256
|
+
PortDetector = class {
|
|
3257
|
+
execFn;
|
|
3258
|
+
/**
|
|
3259
|
+
* Create a new PortDetector
|
|
3260
|
+
* @param execFn - Optional execFile function for testing (dependency injection)
|
|
3261
|
+
*/
|
|
3262
|
+
constructor(execFn) {
|
|
3263
|
+
this.execFn = execFn ?? execFileAsync;
|
|
3264
|
+
}
|
|
3265
|
+
/**
|
|
3266
|
+
* Detect running dev servers by checking listening ports
|
|
3267
|
+
* @returns Detected server info or null
|
|
3268
|
+
*/
|
|
3269
|
+
async detect() {
|
|
3270
|
+
try {
|
|
3271
|
+
const args = [
|
|
3272
|
+
"-nP",
|
|
3273
|
+
// No host names, no port names
|
|
3274
|
+
"-iTCP",
|
|
3275
|
+
// Internet TCP
|
|
3276
|
+
"-sTCP:LISTEN"
|
|
3277
|
+
// TCP LISTEN state only
|
|
3278
|
+
];
|
|
3279
|
+
for (const port of DEV_PORTS) {
|
|
3280
|
+
args.push("-i", `:${port}`);
|
|
3281
|
+
}
|
|
3282
|
+
const { stdout } = await this.execFn("lsof", args, {
|
|
3283
|
+
timeout: 2e3
|
|
3284
|
+
});
|
|
3285
|
+
const lines = stdout.trim().split("\n");
|
|
3286
|
+
for (const line of lines) {
|
|
3287
|
+
if (!line || line.startsWith("COMMAND")) continue;
|
|
3288
|
+
const match = line.match(/:(\d+)\s*\(LISTEN\)/);
|
|
3289
|
+
if (match) {
|
|
3290
|
+
const port = parseInt(match[1], 10);
|
|
3291
|
+
const mapping = PORT_MAPPING[port];
|
|
3292
|
+
if (mapping) {
|
|
3293
|
+
return {
|
|
3294
|
+
name: mapping.name,
|
|
3295
|
+
icon: mapping.icon,
|
|
3296
|
+
port,
|
|
3297
|
+
isRunning: true,
|
|
3298
|
+
isBuilding: false
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
return null;
|
|
3304
|
+
} catch {
|
|
3305
|
+
return null;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
};
|
|
3309
|
+
}
|
|
3310
|
+
});
|
|
3311
|
+
|
|
3312
|
+
// src/widgets/dev-server/process-detector.ts
|
|
3313
|
+
var import_node_child_process2, import_node_util2, execFileAsync2, ProcessDetector;
|
|
3314
|
+
var init_process_detector = __esm({
|
|
3315
|
+
"src/widgets/dev-server/process-detector.ts"() {
|
|
3316
|
+
"use strict";
|
|
3317
|
+
import_node_child_process2 = require("node:child_process");
|
|
3318
|
+
import_node_util2 = require("node:util");
|
|
3319
|
+
execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
3320
|
+
ProcessDetector = class {
|
|
3321
|
+
execFn;
|
|
3322
|
+
processPatterns = [
|
|
3323
|
+
// Generic server patterns - more specific to avoid shell history false positives
|
|
3324
|
+
{ regex: /^[\w\s]+\/npm\s+(exec|run)\s+serve/i, name: "Server", icon: "\u{1F310}" },
|
|
3325
|
+
{ regex: /^[\w\s]+\/npx\s+serve\s+-/i, name: "Server", icon: "\u{1F310}" },
|
|
3326
|
+
{ regex: /^[\w\s]+\/(python|python3)\s+-m\s+http\.server/i, name: "HTTP", icon: "\u{1F310}" },
|
|
3327
|
+
// Generic dev/build patterns - require full command path
|
|
3328
|
+
{ regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+dev\s*$/i, name: "Dev", icon: "\u{1F680}" },
|
|
3329
|
+
{ regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+build\s*$/i, name: "Build", icon: "\u{1F528}" },
|
|
3330
|
+
// Framework-specific patterns - require executable path
|
|
3331
|
+
{ regex: /\/(nuxt|next|astro|remix|svelte)\s+dev/i, name: "Framework", icon: "\u26A1" },
|
|
3332
|
+
{ regex: /\/node.*\/vite\s*$/i, name: "Vite", icon: "\u26A1" },
|
|
3333
|
+
// Fallback: simpler patterns but checked last
|
|
3334
|
+
{ regex: /\s(nuxt|next|vite)\s+dev\s/i, name: "DevServer", icon: "\u26A1" }
|
|
3335
|
+
];
|
|
3336
|
+
/**
|
|
3337
|
+
* Create a new ProcessDetector
|
|
3338
|
+
* @param execFn - Optional execFile function for testing (dependency injection)
|
|
3339
|
+
*/
|
|
3340
|
+
constructor(execFn) {
|
|
3341
|
+
this.execFn = execFn ?? execFileAsync2;
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Detect running dev server by parsing system process list
|
|
3345
|
+
* @returns Detected server status or null
|
|
3346
|
+
*/
|
|
3347
|
+
async detect() {
|
|
3348
|
+
try {
|
|
3349
|
+
const { stdout } = await this.execFn("ps", ["aux"], {
|
|
3350
|
+
timeout: 1e3
|
|
3351
|
+
});
|
|
3352
|
+
for (const pattern of this.processPatterns) {
|
|
3353
|
+
if (pattern.regex.test(stdout)) {
|
|
3354
|
+
const isBuilding = pattern.name.toLowerCase().includes("build");
|
|
3355
|
+
const isRunning = !isBuilding;
|
|
3356
|
+
return {
|
|
3357
|
+
name: pattern.name,
|
|
3358
|
+
icon: pattern.icon,
|
|
3359
|
+
isRunning,
|
|
3360
|
+
isBuilding
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
} catch {
|
|
3365
|
+
}
|
|
3366
|
+
return null;
|
|
3367
|
+
}
|
|
3368
|
+
};
|
|
3369
|
+
}
|
|
3370
|
+
});
|
|
3371
|
+
|
|
3372
|
+
// src/widgets/dev-server/styles.ts
|
|
3373
|
+
var devServerStyles;
|
|
3374
|
+
var init_styles6 = __esm({
|
|
3375
|
+
"src/widgets/dev-server/styles.ts"() {
|
|
3376
|
+
"use strict";
|
|
3377
|
+
init_colors();
|
|
3378
|
+
devServerStyles = {
|
|
3379
|
+
balanced: (data, colors2) => {
|
|
3380
|
+
if (!data.server) return "";
|
|
3381
|
+
const { name, icon, isRunning, isBuilding } = data.server;
|
|
3382
|
+
const status = isRunning ? "running" : isBuilding ? "building" : "stopped";
|
|
3383
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3384
|
+
const coloredStatus = colors2 ? colorize(`(${status})`, colors2.status) : `(${status})`;
|
|
3385
|
+
return `${icon} ${coloredName} ${coloredStatus}`;
|
|
3386
|
+
},
|
|
3387
|
+
compact: (data, colors2) => {
|
|
3388
|
+
if (!data.server) return "";
|
|
3389
|
+
const { name, icon, isRunning, isBuilding } = data.server;
|
|
3390
|
+
const statusIcon = isRunning ? "\u{1F680}" : isBuilding ? "\u{1F528}" : "\u{1F4A4}";
|
|
3391
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3392
|
+
return `${icon} ${coloredName} ${statusIcon}`;
|
|
3393
|
+
},
|
|
3394
|
+
playful: (data, colors2) => {
|
|
3395
|
+
if (!data.server) return "";
|
|
3396
|
+
const { name, isRunning, isBuilding } = data.server;
|
|
3397
|
+
const emoji = isRunning ? "\u{1F3C3}" : isBuilding ? "\u{1F528}" : "\u{1F4A4}";
|
|
3398
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3399
|
+
return `${emoji} ${coloredName}`;
|
|
3400
|
+
},
|
|
3401
|
+
verbose: (data, colors2) => {
|
|
3402
|
+
if (!data.server) return "";
|
|
3403
|
+
const { name, isRunning, isBuilding } = data.server;
|
|
3404
|
+
const status = isRunning ? "running" : isBuilding ? "building" : "stopped";
|
|
3405
|
+
const label = colors2 ? colorize("Dev Server:", colors2.label) : "Dev Server:";
|
|
3406
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3407
|
+
const coloredStatus = colors2 ? colorize(`(${status})`, colors2.status) : `(${status})`;
|
|
3408
|
+
return `${label} ${coloredName} ${coloredStatus}`;
|
|
3409
|
+
},
|
|
3410
|
+
labeled: (data, colors2) => {
|
|
3411
|
+
if (!data.server) return "";
|
|
3412
|
+
const { name, icon, isRunning } = data.server;
|
|
3413
|
+
const status = isRunning ? "\u{1F7E2}" : "\u{1F534}";
|
|
3414
|
+
const label = colors2 ? colorize("Server:", colors2.label) : "Server:";
|
|
3415
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3416
|
+
return `${label} ${icon} ${coloredName} ${status}`;
|
|
3417
|
+
},
|
|
3418
|
+
indicator: (data, colors2) => {
|
|
3419
|
+
if (!data.server) return "";
|
|
3420
|
+
const { name, icon } = data.server;
|
|
3421
|
+
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
3422
|
+
return `\u25CF ${icon} ${coloredName}`;
|
|
3423
|
+
}
|
|
3424
|
+
};
|
|
3425
|
+
}
|
|
3426
|
+
});
|
|
3427
|
+
|
|
3428
|
+
// src/widgets/dev-server/dev-server-widget.ts
|
|
3429
|
+
var DevServerWidget;
|
|
3430
|
+
var init_dev_server_widget = __esm({
|
|
3431
|
+
"src/widgets/dev-server/dev-server-widget.ts"() {
|
|
3432
|
+
"use strict";
|
|
3433
|
+
init_widget_types();
|
|
3434
|
+
init_theme();
|
|
3435
|
+
init_port_detector();
|
|
3436
|
+
init_process_detector();
|
|
3437
|
+
init_styles6();
|
|
3438
|
+
DevServerWidget = class {
|
|
3439
|
+
id = "dev-server";
|
|
3440
|
+
metadata = createWidgetMetadata(
|
|
3441
|
+
"Dev Server",
|
|
3442
|
+
"Detects running dev server processes using hybrid port+process detection",
|
|
3443
|
+
"1.1.0",
|
|
3444
|
+
"claude-scope",
|
|
3445
|
+
0
|
|
3446
|
+
);
|
|
3447
|
+
enabled = true;
|
|
3448
|
+
colors;
|
|
3449
|
+
_lineOverride;
|
|
3450
|
+
styleFn = devServerStyles.balanced;
|
|
3451
|
+
cwd = null;
|
|
3452
|
+
portDetector;
|
|
3453
|
+
processDetector;
|
|
3454
|
+
constructor(colors2) {
|
|
3455
|
+
this.colors = colors2 ?? DEFAULT_THEME;
|
|
3456
|
+
this.portDetector = new PortDetector();
|
|
3457
|
+
this.processDetector = new ProcessDetector();
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* Set display style
|
|
3461
|
+
* @param style - Style to use for rendering
|
|
3462
|
+
*/
|
|
3463
|
+
setStyle(style = "balanced") {
|
|
3464
|
+
const fn = devServerStyles[style];
|
|
3465
|
+
if (fn) {
|
|
3466
|
+
this.styleFn = fn;
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
/**
|
|
3470
|
+
* Set display line override
|
|
3471
|
+
* @param line - Line number (0-indexed)
|
|
3472
|
+
*/
|
|
3473
|
+
setLine(line) {
|
|
3474
|
+
this._lineOverride = line;
|
|
3475
|
+
}
|
|
3476
|
+
/**
|
|
3477
|
+
* Get display line
|
|
3478
|
+
* @returns Line number (0-indexed)
|
|
3479
|
+
*/
|
|
3480
|
+
getLine() {
|
|
3481
|
+
return this._lineOverride ?? this.metadata.line ?? 0;
|
|
3482
|
+
}
|
|
3483
|
+
/**
|
|
3484
|
+
* Initialize widget with context
|
|
3485
|
+
* @param context - Widget initialization context
|
|
3486
|
+
*/
|
|
3487
|
+
async initialize(context) {
|
|
3488
|
+
this.enabled = context.config?.enabled !== false;
|
|
3489
|
+
}
|
|
3490
|
+
/**
|
|
3491
|
+
* Update widget with new stdin data
|
|
3492
|
+
* @param data - Stdin data from Claude Code
|
|
3493
|
+
*/
|
|
3494
|
+
async update(data) {
|
|
3495
|
+
this.cwd = data.cwd;
|
|
3496
|
+
}
|
|
3497
|
+
/**
|
|
3498
|
+
* Check if widget is enabled
|
|
3499
|
+
* @returns true if widget should render
|
|
3500
|
+
*/
|
|
3501
|
+
isEnabled() {
|
|
3502
|
+
return this.enabled;
|
|
3503
|
+
}
|
|
3504
|
+
/**
|
|
3505
|
+
* Cleanup resources
|
|
3506
|
+
*/
|
|
3507
|
+
async cleanup() {
|
|
3508
|
+
}
|
|
3509
|
+
/**
|
|
3510
|
+
* Render widget output
|
|
3511
|
+
* @param context - Render context
|
|
3512
|
+
* @returns Rendered string, or null if no dev server detected
|
|
3513
|
+
*/
|
|
3514
|
+
async render(_context) {
|
|
3515
|
+
if (!this.enabled || !this.cwd) {
|
|
3516
|
+
return null;
|
|
3517
|
+
}
|
|
3518
|
+
const server = await this.detectDevServer();
|
|
3519
|
+
if (!server) {
|
|
3520
|
+
return null;
|
|
3521
|
+
}
|
|
3522
|
+
const renderData = { server };
|
|
3523
|
+
return this.styleFn(renderData, this.colors.devServer);
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Detect running dev server using hybrid approach
|
|
3527
|
+
*
|
|
3528
|
+
* 1. Try port-based detection first (more reliable)
|
|
3529
|
+
* 2. Fall back to process-based detection
|
|
3530
|
+
*
|
|
3531
|
+
* @returns Detected server status or null
|
|
3532
|
+
*/
|
|
3533
|
+
async detectDevServer() {
|
|
3534
|
+
const portResult = await this.portDetector.detect();
|
|
3535
|
+
if (portResult) {
|
|
3536
|
+
return {
|
|
3537
|
+
name: portResult.name,
|
|
3538
|
+
icon: portResult.icon,
|
|
3539
|
+
isRunning: portResult.isRunning,
|
|
3540
|
+
isBuilding: portResult.isBuilding
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3543
|
+
return await this.processDetector.detect();
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
}
|
|
3547
|
+
});
|
|
3548
|
+
|
|
3549
|
+
// src/widgets/docker/styles.ts
|
|
3550
|
+
var dockerStyles;
|
|
3551
|
+
var init_styles7 = __esm({
|
|
3552
|
+
"src/widgets/docker/styles.ts"() {
|
|
3553
|
+
"use strict";
|
|
3554
|
+
init_colors();
|
|
3555
|
+
dockerStyles = {
|
|
3556
|
+
balanced: (data, colors2) => {
|
|
3557
|
+
const { running, total } = data.status;
|
|
3558
|
+
if (running === 0) return "";
|
|
3559
|
+
const status = running > 0 ? "\u{1F7E2}" : "\u26AA";
|
|
3560
|
+
const count = total > running ? `${running}/${total}` : `${running}`;
|
|
3561
|
+
const label = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3562
|
+
const coloredCount = colors2 ? colorize(count, colors2.count) : count;
|
|
3563
|
+
return `${label} ${coloredCount} ${status}`;
|
|
3564
|
+
},
|
|
3565
|
+
compact: (data, colors2) => {
|
|
3566
|
+
const { running, total } = data.status;
|
|
3567
|
+
if (running === 0) return "";
|
|
3568
|
+
const count = total > running ? `${running}/${total}` : `${running}`;
|
|
3569
|
+
const coloredCount = colors2 ? colorize(count, colors2.count) : count;
|
|
3570
|
+
return `\u{1F433} ${coloredCount}`;
|
|
3571
|
+
},
|
|
3572
|
+
playful: (data, colors2) => {
|
|
3573
|
+
const { running, total } = data.status;
|
|
3574
|
+
if (running === 0) return "\u{1F433} Docker: \u{1F4A4}";
|
|
3575
|
+
const status = running > 0 ? "\u{1F7E2}" : "\u26AA";
|
|
3576
|
+
const count = total > running ? `${running}/${total}` : `${running}`;
|
|
3577
|
+
const label = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3578
|
+
const coloredCount = colors2 ? colorize(count, colors2.count) : count;
|
|
3579
|
+
return `\u{1F433} ${label} ${coloredCount} ${status}`;
|
|
3580
|
+
},
|
|
3581
|
+
verbose: (data, colors2) => {
|
|
3582
|
+
const { running, total } = data.status;
|
|
3583
|
+
if (running === 0) {
|
|
3584
|
+
const label2 = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3585
|
+
return `${label2} no containers running`;
|
|
3586
|
+
}
|
|
3587
|
+
const label = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3588
|
+
const coloredRunning = colors2 ? colorize(String(running), colors2.count) : String(running);
|
|
3589
|
+
return `${label} ${coloredRunning} running${total > running ? ` / ${total} total` : ""}`;
|
|
3590
|
+
},
|
|
3591
|
+
labeled: (data, colors2) => {
|
|
3592
|
+
const { running, total } = data.status;
|
|
3593
|
+
if (running === 0) {
|
|
3594
|
+
const label2 = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3595
|
+
return `${label2} --`;
|
|
3596
|
+
}
|
|
3597
|
+
const count = total > running ? `${running}/${total}` : `${running}`;
|
|
3598
|
+
const label = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3599
|
+
const coloredCount = colors2 ? colorize(count, colors2.count) : count;
|
|
3600
|
+
return `${label} ${coloredCount}`;
|
|
3601
|
+
},
|
|
3602
|
+
indicator: (data, colors2) => {
|
|
3603
|
+
const { running, total } = data.status;
|
|
3604
|
+
if (running === 0) {
|
|
3605
|
+
const label2 = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3606
|
+
return `\u25CF ${label2} --`;
|
|
3607
|
+
}
|
|
3608
|
+
const count = total > running ? `${running}/${total}` : `${running}`;
|
|
3609
|
+
const label = colors2 ? colorize("Docker:", colors2.label) : "Docker:";
|
|
3610
|
+
const coloredCount = colors2 ? colorize(count, colors2.count) : count;
|
|
3611
|
+
return `\u25CF ${label} ${coloredCount}`;
|
|
3612
|
+
}
|
|
3613
|
+
};
|
|
3614
|
+
}
|
|
3615
|
+
});
|
|
3616
|
+
|
|
3617
|
+
// src/widgets/docker/docker-widget.ts
|
|
3618
|
+
var import_node_child_process3, import_node_util3, execFileAsync3, DockerWidget;
|
|
3619
|
+
var init_docker_widget = __esm({
|
|
3620
|
+
"src/widgets/docker/docker-widget.ts"() {
|
|
3621
|
+
"use strict";
|
|
3622
|
+
import_node_child_process3 = require("node:child_process");
|
|
3623
|
+
import_node_util3 = require("node:util");
|
|
3624
|
+
init_widget_types();
|
|
3625
|
+
init_theme();
|
|
3626
|
+
init_styles7();
|
|
3627
|
+
execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
|
|
3628
|
+
DockerWidget = class {
|
|
3629
|
+
id = "docker";
|
|
3630
|
+
metadata = createWidgetMetadata(
|
|
3631
|
+
"Docker",
|
|
3632
|
+
"Shows Docker container count and status",
|
|
3633
|
+
"1.0.0",
|
|
3634
|
+
"claude-scope",
|
|
3635
|
+
0
|
|
3636
|
+
);
|
|
3637
|
+
enabled = true;
|
|
3638
|
+
colors;
|
|
3639
|
+
_lineOverride;
|
|
3640
|
+
styleFn = dockerStyles.balanced;
|
|
3641
|
+
cachedStatus = null;
|
|
3642
|
+
lastCheck = 0;
|
|
3643
|
+
CACHE_TTL = 5e3;
|
|
3644
|
+
constructor(colors2) {
|
|
3645
|
+
this.colors = colors2 ?? DEFAULT_THEME;
|
|
3646
|
+
}
|
|
3647
|
+
setStyle(style = "balanced") {
|
|
3648
|
+
const fn = dockerStyles[style];
|
|
3649
|
+
if (fn) {
|
|
3650
|
+
this.styleFn = fn;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
setLine(line) {
|
|
3654
|
+
this._lineOverride = line;
|
|
3655
|
+
}
|
|
3656
|
+
getLine() {
|
|
3657
|
+
return this._lineOverride ?? this.metadata.line ?? 0;
|
|
3658
|
+
}
|
|
3659
|
+
async initialize(context) {
|
|
3660
|
+
this.enabled = context.config?.enabled !== false;
|
|
3661
|
+
}
|
|
3662
|
+
async update(_data) {
|
|
3663
|
+
}
|
|
3664
|
+
isEnabled() {
|
|
3665
|
+
return this.enabled;
|
|
3666
|
+
}
|
|
3667
|
+
async cleanup() {
|
|
3668
|
+
}
|
|
3669
|
+
async render(_context) {
|
|
3670
|
+
if (!this.enabled) {
|
|
3671
|
+
return null;
|
|
3672
|
+
}
|
|
3673
|
+
const now = Date.now();
|
|
3674
|
+
if (this.cachedStatus && now - this.lastCheck < this.CACHE_TTL) {
|
|
3675
|
+
return this.styleFn({ status: this.cachedStatus }, this.colors.docker);
|
|
3676
|
+
}
|
|
3677
|
+
const status = await this.getDockerStatus();
|
|
3678
|
+
this.cachedStatus = status;
|
|
3679
|
+
this.lastCheck = now;
|
|
3680
|
+
if (!status.isAvailable) {
|
|
3681
|
+
return null;
|
|
3682
|
+
}
|
|
3683
|
+
return this.styleFn({ status }, this.colors.docker);
|
|
3684
|
+
}
|
|
3685
|
+
async getDockerStatus() {
|
|
3686
|
+
try {
|
|
3687
|
+
await execFileAsync3("docker", ["info"], { timeout: 2e3 });
|
|
3688
|
+
const { stdout: runningOutput } = await execFileAsync3("docker", ["ps", "-q"], {
|
|
3689
|
+
timeout: 1e3
|
|
3690
|
+
});
|
|
3691
|
+
const running = runningOutput.trim().split("\n").filter((line) => line).length;
|
|
3692
|
+
const { stdout: allOutput } = await execFileAsync3("docker", ["ps", "-aq"], {
|
|
3693
|
+
timeout: 1e3
|
|
3694
|
+
});
|
|
3695
|
+
const total = allOutput.trim().split("\n").filter((line) => line).length;
|
|
3696
|
+
return { running, total, isAvailable: true };
|
|
3697
|
+
} catch {
|
|
3698
|
+
return { running: 0, total: 0, isAvailable: false };
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
});
|
|
3704
|
+
|
|
3192
3705
|
// src/widgets/duration/styles.ts
|
|
3193
3706
|
function formatDurationWithColors(ms, colors2) {
|
|
3194
3707
|
if (ms <= 0) return colorize("0s", colors2.value);
|
|
@@ -3214,7 +3727,7 @@ function formatDurationWithColors(ms, colors2) {
|
|
|
3214
3727
|
return parts.join(" ");
|
|
3215
3728
|
}
|
|
3216
3729
|
var durationStyles;
|
|
3217
|
-
var
|
|
3730
|
+
var init_styles8 = __esm({
|
|
3218
3731
|
"src/widgets/duration/styles.ts"() {
|
|
3219
3732
|
"use strict";
|
|
3220
3733
|
init_colors();
|
|
@@ -3294,7 +3807,7 @@ var init_duration_widget = __esm({
|
|
|
3294
3807
|
init_widget_types();
|
|
3295
3808
|
init_theme();
|
|
3296
3809
|
init_stdin_data_widget();
|
|
3297
|
-
|
|
3810
|
+
init_styles8();
|
|
3298
3811
|
DurationWidget = class extends StdinDataWidget {
|
|
3299
3812
|
id = "duration";
|
|
3300
3813
|
metadata = createWidgetMetadata(
|
|
@@ -3339,13 +3852,13 @@ var init_duration_widget = __esm({
|
|
|
3339
3852
|
function createGit(cwd) {
|
|
3340
3853
|
return new NativeGit(cwd);
|
|
3341
3854
|
}
|
|
3342
|
-
var
|
|
3855
|
+
var import_node_child_process4, import_node_util4, execFileAsync4, NativeGit;
|
|
3343
3856
|
var init_git_provider = __esm({
|
|
3344
3857
|
"src/providers/git-provider.ts"() {
|
|
3345
|
-
"use strict";
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3858
|
+
"use strict";
|
|
3859
|
+
import_node_child_process4 = require("node:child_process");
|
|
3860
|
+
import_node_util4 = require("node:util");
|
|
3861
|
+
execFileAsync4 = (0, import_node_util4.promisify)(import_node_child_process4.execFile);
|
|
3349
3862
|
NativeGit = class {
|
|
3350
3863
|
cwd;
|
|
3351
3864
|
constructor(cwd) {
|
|
@@ -3353,7 +3866,7 @@ var init_git_provider = __esm({
|
|
|
3353
3866
|
}
|
|
3354
3867
|
async status() {
|
|
3355
3868
|
try {
|
|
3356
|
-
const { stdout } = await
|
|
3869
|
+
const { stdout } = await execFileAsync4("git", ["status", "--branch", "--short"], {
|
|
3357
3870
|
cwd: this.cwd
|
|
3358
3871
|
});
|
|
3359
3872
|
const match = stdout.match(/^##\s+(\S+)/m);
|
|
@@ -3369,7 +3882,7 @@ var init_git_provider = __esm({
|
|
|
3369
3882
|
args.push(...options);
|
|
3370
3883
|
}
|
|
3371
3884
|
try {
|
|
3372
|
-
const { stdout } = await
|
|
3885
|
+
const { stdout } = await execFileAsync4("git", args, {
|
|
3373
3886
|
cwd: this.cwd
|
|
3374
3887
|
});
|
|
3375
3888
|
const fileMatch = stdout.match(/(\d+)\s+file(s?)\s+changed/);
|
|
@@ -3386,7 +3899,7 @@ var init_git_provider = __esm({
|
|
|
3386
3899
|
}
|
|
3387
3900
|
async latestTag() {
|
|
3388
3901
|
try {
|
|
3389
|
-
const { stdout } = await
|
|
3902
|
+
const { stdout } = await execFileAsync4("git", ["describe", "--tags", "--abbrev=0"], {
|
|
3390
3903
|
cwd: this.cwd
|
|
3391
3904
|
});
|
|
3392
3905
|
return stdout.trim();
|
|
@@ -3400,7 +3913,7 @@ var init_git_provider = __esm({
|
|
|
3400
3913
|
|
|
3401
3914
|
// src/widgets/git-tag/styles.ts
|
|
3402
3915
|
var gitTagStyles;
|
|
3403
|
-
var
|
|
3916
|
+
var init_styles9 = __esm({
|
|
3404
3917
|
"src/widgets/git-tag/styles.ts"() {
|
|
3405
3918
|
"use strict";
|
|
3406
3919
|
init_colors();
|
|
@@ -3450,7 +3963,7 @@ var init_git_tag_widget = __esm({
|
|
|
3450
3963
|
init_widget_types();
|
|
3451
3964
|
init_git_provider();
|
|
3452
3965
|
init_theme();
|
|
3453
|
-
|
|
3966
|
+
init_styles9();
|
|
3454
3967
|
GitTagWidget = class {
|
|
3455
3968
|
id = "git-tag";
|
|
3456
3969
|
metadata = createWidgetMetadata(
|
|
@@ -3522,7 +4035,7 @@ var init_git_tag_widget = __esm({
|
|
|
3522
4035
|
|
|
3523
4036
|
// src/widgets/git/styles.ts
|
|
3524
4037
|
var gitStyles;
|
|
3525
|
-
var
|
|
4038
|
+
var init_styles10 = __esm({
|
|
3526
4039
|
"src/widgets/git/styles.ts"() {
|
|
3527
4040
|
"use strict";
|
|
3528
4041
|
init_colors();
|
|
@@ -3624,7 +4137,7 @@ var init_git_widget = __esm({
|
|
|
3624
4137
|
init_widget_types();
|
|
3625
4138
|
init_git_provider();
|
|
3626
4139
|
init_theme();
|
|
3627
|
-
|
|
4140
|
+
init_styles10();
|
|
3628
4141
|
GitWidget = class {
|
|
3629
4142
|
id = "git";
|
|
3630
4143
|
metadata = createWidgetMetadata(
|
|
@@ -3716,7 +4229,7 @@ var init_git_widget = __esm({
|
|
|
3716
4229
|
|
|
3717
4230
|
// src/widgets/lines/styles.ts
|
|
3718
4231
|
var linesStyles;
|
|
3719
|
-
var
|
|
4232
|
+
var init_styles11 = __esm({
|
|
3720
4233
|
"src/widgets/lines/styles.ts"() {
|
|
3721
4234
|
"use strict";
|
|
3722
4235
|
init_colors();
|
|
@@ -3776,7 +4289,7 @@ var init_lines_widget = __esm({
|
|
|
3776
4289
|
init_widget_types();
|
|
3777
4290
|
init_theme();
|
|
3778
4291
|
init_stdin_data_widget();
|
|
3779
|
-
|
|
4292
|
+
init_styles11();
|
|
3780
4293
|
LinesWidget = class extends StdinDataWidget {
|
|
3781
4294
|
id = "lines";
|
|
3782
4295
|
metadata = createWidgetMetadata(
|
|
@@ -3821,7 +4334,7 @@ function getShortName(displayName) {
|
|
|
3821
4334
|
return displayName.replace(/^Claude\s+/, "");
|
|
3822
4335
|
}
|
|
3823
4336
|
var modelStyles;
|
|
3824
|
-
var
|
|
4337
|
+
var init_styles12 = __esm({
|
|
3825
4338
|
"src/widgets/model/styles.ts"() {
|
|
3826
4339
|
"use strict";
|
|
3827
4340
|
init_colors();
|
|
@@ -3876,7 +4389,7 @@ var init_model_widget = __esm({
|
|
|
3876
4389
|
init_widget_types();
|
|
3877
4390
|
init_theme();
|
|
3878
4391
|
init_stdin_data_widget();
|
|
3879
|
-
|
|
4392
|
+
init_styles12();
|
|
3880
4393
|
ModelWidget = class extends StdinDataWidget {
|
|
3881
4394
|
id = "model";
|
|
3882
4395
|
metadata = createWidgetMetadata(
|
|
@@ -4018,6 +4531,16 @@ async function registerWidgetsFromConfig(registry, config, style, themeName) {
|
|
|
4018
4531
|
const w = new CacheMetricsWidget(themeColors);
|
|
4019
4532
|
w.setStyle(s);
|
|
4020
4533
|
return w;
|
|
4534
|
+
},
|
|
4535
|
+
"dev-server": (s) => {
|
|
4536
|
+
const w = new DevServerWidget(themeColors);
|
|
4537
|
+
w.setStyle(s);
|
|
4538
|
+
return w;
|
|
4539
|
+
},
|
|
4540
|
+
docker: (s) => {
|
|
4541
|
+
const w = new DockerWidget(themeColors);
|
|
4542
|
+
w.setStyle(s);
|
|
4543
|
+
return w;
|
|
4021
4544
|
}
|
|
4022
4545
|
};
|
|
4023
4546
|
for (const [lineNum, widgets] of Object.entries(config.lines)) {
|
|
@@ -4065,6 +4588,8 @@ var init_layout_preview = __esm({
|
|
|
4065
4588
|
init_config_count_widget();
|
|
4066
4589
|
init_context_widget();
|
|
4067
4590
|
init_cost_widget();
|
|
4591
|
+
init_dev_server_widget();
|
|
4592
|
+
init_docker_widget();
|
|
4068
4593
|
init_duration_widget();
|
|
4069
4594
|
init_git_tag_widget();
|
|
4070
4595
|
init_git_widget();
|
|
@@ -6639,10 +7164,10 @@ var init_esm2 = __esm({
|
|
|
6639
7164
|
});
|
|
6640
7165
|
|
|
6641
7166
|
// node_modules/@inquirer/core/dist/esm/lib/screen-manager.js
|
|
6642
|
-
var
|
|
7167
|
+
var import_node_util5, height, lastLine, ScreenManager;
|
|
6643
7168
|
var init_screen_manager = __esm({
|
|
6644
7169
|
"node_modules/@inquirer/core/dist/esm/lib/screen-manager.js"() {
|
|
6645
|
-
|
|
7170
|
+
import_node_util5 = require("node:util");
|
|
6646
7171
|
init_utils();
|
|
6647
7172
|
init_esm2();
|
|
6648
7173
|
height = (content) => content.split("\n").length;
|
|
@@ -6664,7 +7189,7 @@ var init_screen_manager = __esm({
|
|
|
6664
7189
|
}
|
|
6665
7190
|
render(content, bottomContent = "") {
|
|
6666
7191
|
const promptLine = lastLine(content);
|
|
6667
|
-
const rawPromptLine = (0,
|
|
7192
|
+
const rawPromptLine = (0, import_node_util5.stripVTControlCharacters)(promptLine);
|
|
6668
7193
|
let prompt = rawPromptLine;
|
|
6669
7194
|
if (this.rl.line.length > 0) {
|
|
6670
7195
|
prompt = prompt.slice(0, -this.rl.line.length);
|
|
@@ -6980,6 +7505,7 @@ function generateBalancedLayout(style, themeName) {
|
|
|
6980
7505
|
const theme = getThemeByName(themeName).colors;
|
|
6981
7506
|
return {
|
|
6982
7507
|
version: "1.0.0",
|
|
7508
|
+
$aiDocs: "https://github.com/YuriNachos/claude-scope/blob/main/AI-CONFIG-GUIDE.md",
|
|
6983
7509
|
lines: {
|
|
6984
7510
|
"0": [
|
|
6985
7511
|
{
|
|
@@ -7048,6 +7574,7 @@ function generateCompactLayout(style, themeName) {
|
|
|
7048
7574
|
const theme = getThemeByName(themeName).colors;
|
|
7049
7575
|
return {
|
|
7050
7576
|
version: "1.0.0",
|
|
7577
|
+
$aiDocs: "https://github.com/YuriNachos/claude-scope/blob/main/AI-CONFIG-GUIDE.md",
|
|
7051
7578
|
lines: {
|
|
7052
7579
|
"0": [
|
|
7053
7580
|
{
|
|
@@ -7088,6 +7615,7 @@ function generateRichLayout(style, themeName) {
|
|
|
7088
7615
|
const theme = getThemeByName(themeName).colors;
|
|
7089
7616
|
return {
|
|
7090
7617
|
version: "1.0.0",
|
|
7618
|
+
$aiDocs: "https://github.com/YuriNachos/claude-scope/blob/main/AI-CONFIG-GUIDE.md",
|
|
7091
7619
|
lines: {
|
|
7092
7620
|
"0": [
|
|
7093
7621
|
{
|
|
@@ -7548,7 +8076,7 @@ async function ensureDefaultConfig() {
|
|
|
7548
8076
|
if (!(0, import_node_fs3.existsSync)(configDir)) {
|
|
7549
8077
|
(0, import_node_fs3.mkdirSync)(configDir, { recursive: true });
|
|
7550
8078
|
}
|
|
7551
|
-
const defaultConfig =
|
|
8079
|
+
const defaultConfig = generateRichLayout("balanced", "dracula");
|
|
7552
8080
|
(0, import_node_fs3.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
7553
8081
|
}
|
|
7554
8082
|
|
|
@@ -7590,382 +8118,626 @@ init_config_count_widget();
|
|
|
7590
8118
|
init_context_widget();
|
|
7591
8119
|
init_cost_widget();
|
|
7592
8120
|
|
|
7593
|
-
// src/widgets/dev-server/
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
// src/widgets/dev-server/port-detector.ts
|
|
7598
|
-
var import_node_child_process2 = require("node:child_process");
|
|
7599
|
-
var import_node_util3 = require("node:util");
|
|
7600
|
-
var execFileAsync2 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
7601
|
-
var PORT_MAPPING = {
|
|
7602
|
-
5173: { name: "Vite", icon: "\u26A1" },
|
|
7603
|
-
4200: { name: "Angular", icon: "\u25B2" },
|
|
7604
|
-
3e3: { name: "Dev", icon: "\u{1F680}" },
|
|
7605
|
-
8080: { name: "Webpack", icon: "\u{1F4E6}" },
|
|
7606
|
-
8e3: { name: "Dev", icon: "\u{1F680}" },
|
|
7607
|
-
8888: { name: "Dev", icon: "\u{1F680}" }
|
|
7608
|
-
};
|
|
7609
|
-
var DEV_PORTS = [5173, 4200, 3e3, 8080, 8e3, 8888];
|
|
7610
|
-
var PortDetector = class {
|
|
7611
|
-
execFn;
|
|
7612
|
-
/**
|
|
7613
|
-
* Create a new PortDetector
|
|
7614
|
-
* @param execFn - Optional execFile function for testing (dependency injection)
|
|
7615
|
-
*/
|
|
7616
|
-
constructor(execFn) {
|
|
7617
|
-
this.execFn = execFn ?? execFileAsync2;
|
|
7618
|
-
}
|
|
7619
|
-
/**
|
|
7620
|
-
* Detect running dev servers by checking listening ports
|
|
7621
|
-
* @returns Detected server info or null
|
|
7622
|
-
*/
|
|
7623
|
-
async detect() {
|
|
7624
|
-
try {
|
|
7625
|
-
const args = [
|
|
7626
|
-
"-nP",
|
|
7627
|
-
// No host names, no port names
|
|
7628
|
-
"-iTCP",
|
|
7629
|
-
// Internet TCP
|
|
7630
|
-
"-sTCP:LISTEN"
|
|
7631
|
-
// TCP LISTEN state only
|
|
7632
|
-
];
|
|
7633
|
-
for (const port of DEV_PORTS) {
|
|
7634
|
-
args.push("-i", `:${port}`);
|
|
7635
|
-
}
|
|
7636
|
-
const { stdout } = await this.execFn("lsof", args, {
|
|
7637
|
-
timeout: 2e3
|
|
7638
|
-
});
|
|
7639
|
-
const lines = stdout.trim().split("\n");
|
|
7640
|
-
for (const line of lines) {
|
|
7641
|
-
if (!line || line.startsWith("COMMAND")) continue;
|
|
7642
|
-
const match = line.match(/:(\d+)\s*\(LISTEN\)/);
|
|
7643
|
-
if (match) {
|
|
7644
|
-
const port = parseInt(match[1], 10);
|
|
7645
|
-
const mapping = PORT_MAPPING[port];
|
|
7646
|
-
if (mapping) {
|
|
7647
|
-
return {
|
|
7648
|
-
name: mapping.name,
|
|
7649
|
-
icon: mapping.icon,
|
|
7650
|
-
port,
|
|
7651
|
-
isRunning: true,
|
|
7652
|
-
isBuilding: false
|
|
7653
|
-
};
|
|
7654
|
-
}
|
|
7655
|
-
}
|
|
7656
|
-
}
|
|
7657
|
-
return null;
|
|
7658
|
-
} catch {
|
|
7659
|
-
return null;
|
|
7660
|
-
}
|
|
7661
|
-
}
|
|
7662
|
-
};
|
|
8121
|
+
// src/widgets/dev-server/index.ts
|
|
8122
|
+
init_dev_server_widget();
|
|
8123
|
+
init_port_detector();
|
|
8124
|
+
init_process_detector();
|
|
7663
8125
|
|
|
7664
|
-
// src/widgets/
|
|
7665
|
-
|
|
7666
|
-
var import_node_util4 = require("node:util");
|
|
7667
|
-
var execFileAsync3 = (0, import_node_util4.promisify)(import_node_child_process3.execFile);
|
|
7668
|
-
var ProcessDetector = class {
|
|
7669
|
-
execFn;
|
|
7670
|
-
processPatterns = [
|
|
7671
|
-
// Generic server patterns - more specific to avoid shell history false positives
|
|
7672
|
-
{ regex: /^[\w\s]+\/npm\s+(exec|run)\s+serve/i, name: "Server", icon: "\u{1F310}" },
|
|
7673
|
-
{ regex: /^[\w\s]+\/npx\s+serve\s+-/i, name: "Server", icon: "\u{1F310}" },
|
|
7674
|
-
{ regex: /^[\w\s]+\/(python|python3)\s+-m\s+http\.server/i, name: "HTTP", icon: "\u{1F310}" },
|
|
7675
|
-
// Generic dev/build patterns - require full command path
|
|
7676
|
-
{ regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+dev\s*$/i, name: "Dev", icon: "\u{1F680}" },
|
|
7677
|
-
{ regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+build\s*$/i, name: "Build", icon: "\u{1F528}" },
|
|
7678
|
-
// Framework-specific patterns - require executable path
|
|
7679
|
-
{ regex: /\/(nuxt|next|astro|remix|svelte)\s+dev/i, name: "Framework", icon: "\u26A1" },
|
|
7680
|
-
{ regex: /\/node.*\/vite\s*$/i, name: "Vite", icon: "\u26A1" },
|
|
7681
|
-
// Fallback: simpler patterns but checked last
|
|
7682
|
-
{ regex: /\s(nuxt|next|vite)\s+dev\s/i, name: "DevServer", icon: "\u26A1" }
|
|
7683
|
-
];
|
|
7684
|
-
/**
|
|
7685
|
-
* Create a new ProcessDetector
|
|
7686
|
-
* @param execFn - Optional execFile function for testing (dependency injection)
|
|
7687
|
-
*/
|
|
7688
|
-
constructor(execFn) {
|
|
7689
|
-
this.execFn = execFn ?? execFileAsync3;
|
|
7690
|
-
}
|
|
7691
|
-
/**
|
|
7692
|
-
* Detect running dev server by parsing system process list
|
|
7693
|
-
* @returns Detected server status or null
|
|
7694
|
-
*/
|
|
7695
|
-
async detect() {
|
|
7696
|
-
try {
|
|
7697
|
-
const { stdout } = await this.execFn("ps", ["aux"], {
|
|
7698
|
-
timeout: 1e3
|
|
7699
|
-
});
|
|
7700
|
-
for (const pattern of this.processPatterns) {
|
|
7701
|
-
if (pattern.regex.test(stdout)) {
|
|
7702
|
-
const isBuilding = pattern.name.toLowerCase().includes("build");
|
|
7703
|
-
const isRunning = !isBuilding;
|
|
7704
|
-
return {
|
|
7705
|
-
name: pattern.name,
|
|
7706
|
-
icon: pattern.icon,
|
|
7707
|
-
isRunning,
|
|
7708
|
-
isBuilding
|
|
7709
|
-
};
|
|
7710
|
-
}
|
|
7711
|
-
}
|
|
7712
|
-
} catch {
|
|
7713
|
-
}
|
|
7714
|
-
return null;
|
|
7715
|
-
}
|
|
7716
|
-
};
|
|
8126
|
+
// src/widgets/docker/index.ts
|
|
8127
|
+
init_docker_widget();
|
|
7717
8128
|
|
|
7718
|
-
// src/
|
|
7719
|
-
|
|
7720
|
-
var devServerStyles = {
|
|
7721
|
-
balanced: (data, colors2) => {
|
|
7722
|
-
if (!data.server) return "";
|
|
7723
|
-
const { name, icon, isRunning, isBuilding } = data.server;
|
|
7724
|
-
const status = isRunning ? "running" : isBuilding ? "building" : "stopped";
|
|
7725
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7726
|
-
const coloredStatus = colors2 ? colorize(`(${status})`, colors2.status) : `(${status})`;
|
|
7727
|
-
return `${icon} ${coloredName} ${coloredStatus}`;
|
|
7728
|
-
},
|
|
7729
|
-
compact: (data, colors2) => {
|
|
7730
|
-
if (!data.server) return "";
|
|
7731
|
-
const { name, icon, isRunning, isBuilding } = data.server;
|
|
7732
|
-
const statusIcon = isRunning ? "\u{1F680}" : isBuilding ? "\u{1F528}" : "\u{1F4A4}";
|
|
7733
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7734
|
-
return `${icon} ${coloredName} ${statusIcon}`;
|
|
7735
|
-
},
|
|
7736
|
-
playful: (data, colors2) => {
|
|
7737
|
-
if (!data.server) return "";
|
|
7738
|
-
const { name, isRunning, isBuilding } = data.server;
|
|
7739
|
-
const emoji = isRunning ? "\u{1F3C3}" : isBuilding ? "\u{1F528}" : "\u{1F4A4}";
|
|
7740
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7741
|
-
return `${emoji} ${coloredName}`;
|
|
7742
|
-
},
|
|
7743
|
-
verbose: (data, colors2) => {
|
|
7744
|
-
if (!data.server) return "";
|
|
7745
|
-
const { name, isRunning, isBuilding } = data.server;
|
|
7746
|
-
const status = isRunning ? "running" : isBuilding ? "building" : "stopped";
|
|
7747
|
-
const label = colors2 ? colorize("Dev Server:", colors2.label) : "Dev Server:";
|
|
7748
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7749
|
-
const coloredStatus = colors2 ? colorize(`(${status})`, colors2.status) : `(${status})`;
|
|
7750
|
-
return `${label} ${coloredName} ${coloredStatus}`;
|
|
7751
|
-
},
|
|
7752
|
-
labeled: (data, colors2) => {
|
|
7753
|
-
if (!data.server) return "";
|
|
7754
|
-
const { name, icon, isRunning } = data.server;
|
|
7755
|
-
const status = isRunning ? "\u{1F7E2}" : "\u{1F534}";
|
|
7756
|
-
const label = colors2 ? colorize("Server:", colors2.label) : "Server:";
|
|
7757
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7758
|
-
return `${label} ${icon} ${coloredName} ${status}`;
|
|
7759
|
-
},
|
|
7760
|
-
indicator: (data, colors2) => {
|
|
7761
|
-
if (!data.server) return "";
|
|
7762
|
-
const { name, icon } = data.server;
|
|
7763
|
-
const coloredName = colors2 ? colorize(name, colors2.name) : name;
|
|
7764
|
-
return `\u25CF ${icon} ${coloredName}`;
|
|
7765
|
-
}
|
|
7766
|
-
};
|
|
8129
|
+
// src/core/widget-factory.ts
|
|
8130
|
+
init_duration_widget();
|
|
7767
8131
|
|
|
7768
|
-
// src/widgets/
|
|
7769
|
-
|
|
7770
|
-
|
|
8132
|
+
// src/widgets/empty-line-widget.ts
|
|
8133
|
+
init_widget_types();
|
|
8134
|
+
init_stdin_data_widget();
|
|
8135
|
+
var EmptyLineWidget = class extends StdinDataWidget {
|
|
8136
|
+
id = "empty-line";
|
|
7771
8137
|
metadata = createWidgetMetadata(
|
|
7772
|
-
"
|
|
7773
|
-
"
|
|
7774
|
-
"1.
|
|
8138
|
+
"Empty Line",
|
|
8139
|
+
"Empty line separator",
|
|
8140
|
+
"1.0.0",
|
|
7775
8141
|
"claude-scope",
|
|
7776
|
-
|
|
8142
|
+
5
|
|
8143
|
+
// Sixth line (0-indexed)
|
|
7777
8144
|
);
|
|
7778
|
-
enabled = true;
|
|
7779
|
-
colors;
|
|
7780
8145
|
_lineOverride;
|
|
7781
|
-
styleFn = devServerStyles.balanced;
|
|
7782
|
-
cwd = null;
|
|
7783
|
-
portDetector;
|
|
7784
|
-
processDetector;
|
|
7785
|
-
constructor(colors2) {
|
|
7786
|
-
this.colors = colors2 ?? DEFAULT_THEME;
|
|
7787
|
-
this.portDetector = new PortDetector();
|
|
7788
|
-
this.processDetector = new ProcessDetector();
|
|
7789
|
-
}
|
|
7790
8146
|
/**
|
|
7791
|
-
*
|
|
7792
|
-
*
|
|
8147
|
+
* All styles return the same value (Braille Pattern Blank).
|
|
8148
|
+
* This method exists for API consistency with other widgets.
|
|
7793
8149
|
*/
|
|
7794
|
-
setStyle(
|
|
7795
|
-
const fn = devServerStyles[style];
|
|
7796
|
-
if (fn) {
|
|
7797
|
-
this.styleFn = fn;
|
|
7798
|
-
}
|
|
8150
|
+
setStyle(_style) {
|
|
7799
8151
|
}
|
|
7800
|
-
/**
|
|
7801
|
-
* Set display line override
|
|
7802
|
-
* @param line - Line number (0-indexed)
|
|
7803
|
-
*/
|
|
7804
8152
|
setLine(line) {
|
|
7805
8153
|
this._lineOverride = line;
|
|
7806
8154
|
}
|
|
7807
|
-
/**
|
|
7808
|
-
* Get display line
|
|
7809
|
-
* @returns Line number (0-indexed)
|
|
7810
|
-
*/
|
|
7811
8155
|
getLine() {
|
|
7812
8156
|
return this._lineOverride ?? this.metadata.line ?? 0;
|
|
7813
8157
|
}
|
|
7814
8158
|
/**
|
|
7815
|
-
*
|
|
7816
|
-
*
|
|
8159
|
+
* Return Braille Pattern Blank to create a visible empty separator line.
|
|
8160
|
+
* U+2800 occupies cell width but appears blank, ensuring the line renders.
|
|
7817
8161
|
*/
|
|
7818
|
-
|
|
7819
|
-
|
|
8162
|
+
renderWithData(_data, _context) {
|
|
8163
|
+
return "\u2800";
|
|
8164
|
+
}
|
|
8165
|
+
};
|
|
8166
|
+
|
|
8167
|
+
// src/core/widget-factory.ts
|
|
8168
|
+
init_git_tag_widget();
|
|
8169
|
+
init_git_widget();
|
|
8170
|
+
init_lines_widget();
|
|
8171
|
+
init_model_widget();
|
|
8172
|
+
|
|
8173
|
+
// src/widgets/poker-widget.ts
|
|
8174
|
+
init_style_types();
|
|
8175
|
+
init_widget_types();
|
|
8176
|
+
init_theme();
|
|
8177
|
+
init_stdin_data_widget();
|
|
8178
|
+
|
|
8179
|
+
// src/widgets/poker/deck.ts
|
|
8180
|
+
var import_node_crypto = require("node:crypto");
|
|
8181
|
+
|
|
8182
|
+
// src/widgets/poker/types.ts
|
|
8183
|
+
var Suit = {
|
|
8184
|
+
Spades: "spades",
|
|
8185
|
+
Hearts: "hearts",
|
|
8186
|
+
Diamonds: "diamonds",
|
|
8187
|
+
Clubs: "clubs"
|
|
8188
|
+
};
|
|
8189
|
+
var SUIT_SYMBOLS = {
|
|
8190
|
+
spades: "\u2660",
|
|
8191
|
+
hearts: "\u2665",
|
|
8192
|
+
diamonds: "\u2666",
|
|
8193
|
+
clubs: "\u2663"
|
|
8194
|
+
};
|
|
8195
|
+
var EMOJI_SYMBOLS = {
|
|
8196
|
+
spades: "\u2660\uFE0F",
|
|
8197
|
+
// ♠️
|
|
8198
|
+
hearts: "\u2665\uFE0F",
|
|
8199
|
+
// ♥️
|
|
8200
|
+
diamonds: "\u2666\uFE0F",
|
|
8201
|
+
// ♦️
|
|
8202
|
+
clubs: "\u2663\uFE0F"
|
|
8203
|
+
// ♣️
|
|
8204
|
+
};
|
|
8205
|
+
function isRedSuit(suit) {
|
|
8206
|
+
return suit === "hearts" || suit === "diamonds";
|
|
8207
|
+
}
|
|
8208
|
+
var Rank = {
|
|
8209
|
+
Two: "2",
|
|
8210
|
+
Three: "3",
|
|
8211
|
+
Four: "4",
|
|
8212
|
+
Five: "5",
|
|
8213
|
+
Six: "6",
|
|
8214
|
+
Seven: "7",
|
|
8215
|
+
Eight: "8",
|
|
8216
|
+
Nine: "9",
|
|
8217
|
+
Ten: "10",
|
|
8218
|
+
Jack: "J",
|
|
8219
|
+
Queen: "Q",
|
|
8220
|
+
King: "K",
|
|
8221
|
+
Ace: "A"
|
|
8222
|
+
};
|
|
8223
|
+
function getRankValue(rank) {
|
|
8224
|
+
const values = {
|
|
8225
|
+
"2": 2,
|
|
8226
|
+
"3": 3,
|
|
8227
|
+
"4": 4,
|
|
8228
|
+
"5": 5,
|
|
8229
|
+
"6": 6,
|
|
8230
|
+
"7": 7,
|
|
8231
|
+
"8": 8,
|
|
8232
|
+
"9": 9,
|
|
8233
|
+
"10": 10,
|
|
8234
|
+
J: 11,
|
|
8235
|
+
Q: 12,
|
|
8236
|
+
K: 13,
|
|
8237
|
+
A: 14
|
|
8238
|
+
};
|
|
8239
|
+
return values[rank];
|
|
8240
|
+
}
|
|
8241
|
+
function formatCard(card) {
|
|
8242
|
+
return `${card.rank}${SUIT_SYMBOLS[card.suit]}`;
|
|
8243
|
+
}
|
|
8244
|
+
function formatCardEmoji(card) {
|
|
8245
|
+
return `${card.rank}${EMOJI_SYMBOLS[card.suit]}`;
|
|
8246
|
+
}
|
|
8247
|
+
|
|
8248
|
+
// src/widgets/poker/deck.ts
|
|
8249
|
+
var ALL_SUITS = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs];
|
|
8250
|
+
var ALL_RANKS = [
|
|
8251
|
+
Rank.Two,
|
|
8252
|
+
Rank.Three,
|
|
8253
|
+
Rank.Four,
|
|
8254
|
+
Rank.Five,
|
|
8255
|
+
Rank.Six,
|
|
8256
|
+
Rank.Seven,
|
|
8257
|
+
Rank.Eight,
|
|
8258
|
+
Rank.Nine,
|
|
8259
|
+
Rank.Ten,
|
|
8260
|
+
Rank.Jack,
|
|
8261
|
+
Rank.Queen,
|
|
8262
|
+
Rank.King,
|
|
8263
|
+
Rank.Ace
|
|
8264
|
+
];
|
|
8265
|
+
var Deck = class {
|
|
8266
|
+
cards = [];
|
|
8267
|
+
constructor() {
|
|
8268
|
+
this.initialize();
|
|
8269
|
+
this.shuffle();
|
|
7820
8270
|
}
|
|
7821
8271
|
/**
|
|
7822
|
-
*
|
|
7823
|
-
* @param data - Stdin data from Claude Code
|
|
8272
|
+
* Create a standard 52-card deck
|
|
7824
8273
|
*/
|
|
7825
|
-
|
|
7826
|
-
this.
|
|
8274
|
+
initialize() {
|
|
8275
|
+
this.cards = [];
|
|
8276
|
+
for (const suit of ALL_SUITS) {
|
|
8277
|
+
for (const rank of ALL_RANKS) {
|
|
8278
|
+
this.cards.push({ rank, suit });
|
|
8279
|
+
}
|
|
8280
|
+
}
|
|
7827
8281
|
}
|
|
7828
8282
|
/**
|
|
7829
|
-
*
|
|
7830
|
-
* @returns true if widget should render
|
|
8283
|
+
* Shuffle deck using Fisher-Yates algorithm with crypto.random
|
|
7831
8284
|
*/
|
|
7832
|
-
|
|
7833
|
-
|
|
8285
|
+
shuffle() {
|
|
8286
|
+
for (let i = this.cards.length - 1; i > 0; i--) {
|
|
8287
|
+
const j = (0, import_node_crypto.randomInt)(0, i + 1);
|
|
8288
|
+
[this.cards[i], this.cards[j]] = [this.cards[j], this.cards[i]];
|
|
8289
|
+
}
|
|
7834
8290
|
}
|
|
7835
8291
|
/**
|
|
7836
|
-
*
|
|
8292
|
+
* Deal one card from the top of the deck
|
|
8293
|
+
* @throws Error if deck is empty
|
|
7837
8294
|
*/
|
|
7838
|
-
|
|
8295
|
+
deal() {
|
|
8296
|
+
if (this.cards.length === 0) {
|
|
8297
|
+
throw new Error("Deck is empty");
|
|
8298
|
+
}
|
|
8299
|
+
return this.cards.pop();
|
|
7839
8300
|
}
|
|
7840
8301
|
/**
|
|
7841
|
-
*
|
|
7842
|
-
* @param context - Render context
|
|
7843
|
-
* @returns Rendered string, or null if no dev server detected
|
|
8302
|
+
* Get number of remaining cards in deck
|
|
7844
8303
|
*/
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
8304
|
+
remaining() {
|
|
8305
|
+
return this.cards.length;
|
|
8306
|
+
}
|
|
8307
|
+
};
|
|
8308
|
+
|
|
8309
|
+
// src/widgets/poker/hand-evaluator.ts
|
|
8310
|
+
var HAND_DISPLAY = {
|
|
8311
|
+
[10 /* RoyalFlush */]: { name: "Royal Flush", emoji: "\u{1F3C6}" },
|
|
8312
|
+
[9 /* StraightFlush */]: { name: "Straight Flush", emoji: "\u{1F525}" },
|
|
8313
|
+
[8 /* FourOfAKind */]: { name: "Four of a Kind", emoji: "\u{1F48E}" },
|
|
8314
|
+
[7 /* FullHouse */]: { name: "Full House", emoji: "\u{1F3E0}" },
|
|
8315
|
+
[6 /* Flush */]: { name: "Flush", emoji: "\u{1F4A7}" },
|
|
8316
|
+
[5 /* Straight */]: { name: "Straight", emoji: "\u{1F4C8}" },
|
|
8317
|
+
[4 /* ThreeOfAKind */]: { name: "Three of a Kind", emoji: "\u{1F3AF}" },
|
|
8318
|
+
[3 /* TwoPair */]: { name: "Two Pair", emoji: "\u270C\uFE0F" },
|
|
8319
|
+
[2 /* OnePair */]: { name: "One Pair", emoji: "\u{1F44D}" },
|
|
8320
|
+
[1 /* HighCard */]: { name: "High Card", emoji: "\u{1F0CF}" }
|
|
8321
|
+
};
|
|
8322
|
+
function countRanks(cards) {
|
|
8323
|
+
const counts = /* @__PURE__ */ new Map();
|
|
8324
|
+
for (const card of cards) {
|
|
8325
|
+
const value = getRankValue(card.rank);
|
|
8326
|
+
counts.set(value, (counts.get(value) || 0) + 1);
|
|
8327
|
+
}
|
|
8328
|
+
return counts;
|
|
8329
|
+
}
|
|
8330
|
+
function countSuits(cards) {
|
|
8331
|
+
const counts = /* @__PURE__ */ new Map();
|
|
8332
|
+
for (const card of cards) {
|
|
8333
|
+
counts.set(card.suit, (counts.get(card.suit) || 0) + 1);
|
|
8334
|
+
}
|
|
8335
|
+
return counts;
|
|
8336
|
+
}
|
|
8337
|
+
function findCardsOfRank(cards, targetRank) {
|
|
8338
|
+
const indices = [];
|
|
8339
|
+
for (let i = 0; i < cards.length; i++) {
|
|
8340
|
+
if (getRankValue(cards[i].rank) === targetRank) {
|
|
8341
|
+
indices.push(i);
|
|
7848
8342
|
}
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
8343
|
+
}
|
|
8344
|
+
return indices;
|
|
8345
|
+
}
|
|
8346
|
+
function findCardsOfSuit(cards, targetSuit) {
|
|
8347
|
+
const indices = [];
|
|
8348
|
+
for (let i = 0; i < cards.length; i++) {
|
|
8349
|
+
if (cards[i].suit === targetSuit) {
|
|
8350
|
+
indices.push(i);
|
|
7852
8351
|
}
|
|
7853
|
-
const renderData = { server };
|
|
7854
|
-
return this.styleFn(renderData, this.colors.devServer);
|
|
7855
8352
|
}
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
8353
|
+
return indices;
|
|
8354
|
+
}
|
|
8355
|
+
function findFlushSuit(cards) {
|
|
8356
|
+
const suitCounts = countSuits(cards);
|
|
8357
|
+
for (const [suit, count] of suitCounts.entries()) {
|
|
8358
|
+
if (count >= 5) return suit;
|
|
8359
|
+
}
|
|
8360
|
+
return null;
|
|
8361
|
+
}
|
|
8362
|
+
function getStraightIndices(cards, highCard) {
|
|
8363
|
+
const uniqueValues = /* @__PURE__ */ new Set();
|
|
8364
|
+
const cardIndicesByRank = /* @__PURE__ */ new Map();
|
|
8365
|
+
for (let i = 0; i < cards.length; i++) {
|
|
8366
|
+
const value = getRankValue(cards[i].rank);
|
|
8367
|
+
if (!cardIndicesByRank.has(value)) {
|
|
8368
|
+
cardIndicesByRank.set(value, []);
|
|
8369
|
+
uniqueValues.add(value);
|
|
8370
|
+
}
|
|
8371
|
+
cardIndicesByRank.get(value)?.push(i);
|
|
8372
|
+
}
|
|
8373
|
+
const sortedValues = Array.from(uniqueValues).sort((a, b) => b - a);
|
|
8374
|
+
if (sortedValues.includes(14)) {
|
|
8375
|
+
sortedValues.push(1);
|
|
8376
|
+
}
|
|
8377
|
+
for (let i = 0; i <= sortedValues.length - 5; i++) {
|
|
8378
|
+
const current = sortedValues[i];
|
|
8379
|
+
const next1 = sortedValues[i + 1];
|
|
8380
|
+
const next2 = sortedValues[i + 2];
|
|
8381
|
+
const next3 = sortedValues[i + 3];
|
|
8382
|
+
const next4 = sortedValues[i + 4];
|
|
8383
|
+
if (current - next1 === 1 && current - next2 === 2 && current - next3 === 3 && current - next4 === 4) {
|
|
8384
|
+
if (current === highCard) {
|
|
8385
|
+
const indices = [];
|
|
8386
|
+
indices.push(cardIndicesByRank.get(current)[0]);
|
|
8387
|
+
indices.push(cardIndicesByRank.get(next1)[0]);
|
|
8388
|
+
indices.push(cardIndicesByRank.get(next2)[0]);
|
|
8389
|
+
indices.push(cardIndicesByRank.get(next3)[0]);
|
|
8390
|
+
const rank4 = next4 === 1 ? 14 : next4;
|
|
8391
|
+
indices.push(cardIndicesByRank.get(rank4)[0]);
|
|
8392
|
+
return indices;
|
|
8393
|
+
}
|
|
8394
|
+
}
|
|
8395
|
+
}
|
|
8396
|
+
return [];
|
|
8397
|
+
}
|
|
8398
|
+
function getStraightFlushHighCard(cards, suit) {
|
|
8399
|
+
const suitCards = cards.filter((c) => c.suit === suit);
|
|
8400
|
+
return getStraightHighCard(suitCards);
|
|
8401
|
+
}
|
|
8402
|
+
function getStraightFlushIndices(cards, highCard, suit) {
|
|
8403
|
+
const _suitCards = cards.filter((c) => c.suit === suit);
|
|
8404
|
+
const suitCardIndices = [];
|
|
8405
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
8406
|
+
for (let i = 0; i < cards.length; i++) {
|
|
8407
|
+
if (cards[i].suit === suit) {
|
|
8408
|
+
indexMap.set(suitCardIndices.length, i);
|
|
8409
|
+
suitCardIndices.push(cards[i]);
|
|
8410
|
+
}
|
|
8411
|
+
}
|
|
8412
|
+
const indices = getStraightIndices(suitCardIndices, highCard);
|
|
8413
|
+
return indices.map((idx) => indexMap.get(idx));
|
|
8414
|
+
}
|
|
8415
|
+
function getFullHouseIndices(cards) {
|
|
8416
|
+
const rankCounts = countRanks(cards);
|
|
8417
|
+
let tripsRank = 0;
|
|
8418
|
+
for (const [rank, count] of rankCounts.entries()) {
|
|
8419
|
+
if (count === 3) {
|
|
8420
|
+
tripsRank = rank;
|
|
8421
|
+
break;
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
let pairRank = 0;
|
|
8425
|
+
for (const [rank, count] of rankCounts.entries()) {
|
|
8426
|
+
if (count >= 2 && rank !== tripsRank) {
|
|
8427
|
+
pairRank = rank;
|
|
8428
|
+
break;
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
if (pairRank === 0) {
|
|
8432
|
+
const tripsRanks = [];
|
|
8433
|
+
for (const [rank, count] of rankCounts.entries()) {
|
|
8434
|
+
if (count === 3) {
|
|
8435
|
+
tripsRanks.push(rank);
|
|
8436
|
+
}
|
|
8437
|
+
}
|
|
8438
|
+
if (tripsRanks.length >= 2) {
|
|
8439
|
+
tripsRanks.sort((a, b) => b - a);
|
|
8440
|
+
tripsRank = tripsRanks[0];
|
|
8441
|
+
pairRank = tripsRanks[1];
|
|
8442
|
+
}
|
|
8443
|
+
}
|
|
8444
|
+
const tripsIndices = findCardsOfRank(cards, tripsRank);
|
|
8445
|
+
const pairIndices = findCardsOfRank(cards, pairRank);
|
|
8446
|
+
return [...tripsIndices.slice(0, 3), ...pairIndices.slice(0, 2)];
|
|
8447
|
+
}
|
|
8448
|
+
function isFlush(cards) {
|
|
8449
|
+
const suitCounts = countSuits(cards);
|
|
8450
|
+
for (const count of suitCounts.values()) {
|
|
8451
|
+
if (count >= 5) return true;
|
|
8452
|
+
}
|
|
8453
|
+
return false;
|
|
8454
|
+
}
|
|
8455
|
+
function getStraightHighCard(cards) {
|
|
8456
|
+
const uniqueValues = /* @__PURE__ */ new Set();
|
|
8457
|
+
for (const card of cards) {
|
|
8458
|
+
uniqueValues.add(getRankValue(card.rank));
|
|
8459
|
+
}
|
|
8460
|
+
const sortedValues = Array.from(uniqueValues).sort((a, b) => b - a);
|
|
8461
|
+
if (sortedValues.includes(14)) {
|
|
8462
|
+
sortedValues.push(1);
|
|
8463
|
+
}
|
|
8464
|
+
for (let i = 0; i <= sortedValues.length - 5; i++) {
|
|
8465
|
+
const current = sortedValues[i];
|
|
8466
|
+
const next1 = sortedValues[i + 1];
|
|
8467
|
+
const next2 = sortedValues[i + 2];
|
|
8468
|
+
const next3 = sortedValues[i + 3];
|
|
8469
|
+
const next4 = sortedValues[i + 4];
|
|
8470
|
+
if (current - next1 === 1 && current - next2 === 2 && current - next3 === 3 && current - next4 === 4) {
|
|
8471
|
+
return current;
|
|
8472
|
+
}
|
|
8473
|
+
}
|
|
8474
|
+
return null;
|
|
8475
|
+
}
|
|
8476
|
+
function getMaxCount(cards) {
|
|
8477
|
+
const rankCounts = countRanks(cards);
|
|
8478
|
+
let maxCount = 0;
|
|
8479
|
+
for (const count of rankCounts.values()) {
|
|
8480
|
+
if (count > maxCount) {
|
|
8481
|
+
maxCount = count;
|
|
8482
|
+
}
|
|
8483
|
+
}
|
|
8484
|
+
return maxCount;
|
|
8485
|
+
}
|
|
8486
|
+
function getPairCount(cards) {
|
|
8487
|
+
const rankCounts = countRanks(cards);
|
|
8488
|
+
let pairCount = 0;
|
|
8489
|
+
for (const count of rankCounts.values()) {
|
|
8490
|
+
if (count === 2) {
|
|
8491
|
+
pairCount++;
|
|
8492
|
+
}
|
|
8493
|
+
}
|
|
8494
|
+
return pairCount;
|
|
8495
|
+
}
|
|
8496
|
+
function getMostCommonRank(cards) {
|
|
8497
|
+
const rankCounts = countRanks(cards);
|
|
8498
|
+
let bestRank = 0;
|
|
8499
|
+
let bestCount = 0;
|
|
8500
|
+
for (const [rank, count] of rankCounts.entries()) {
|
|
8501
|
+
if (count > bestCount) {
|
|
8502
|
+
bestCount = count;
|
|
8503
|
+
bestRank = rank;
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
return bestRank > 0 ? bestRank : null;
|
|
8507
|
+
}
|
|
8508
|
+
function getTwoPairRanks(cards) {
|
|
8509
|
+
const rankCounts = countRanks(cards);
|
|
8510
|
+
const pairRanks = [];
|
|
8511
|
+
for (const [rank, count] of rankCounts.entries()) {
|
|
8512
|
+
if (count >= 2) {
|
|
8513
|
+
pairRanks.push(rank);
|
|
8514
|
+
}
|
|
8515
|
+
}
|
|
8516
|
+
pairRanks.sort((a, b) => b - a);
|
|
8517
|
+
return pairRanks.slice(0, 2);
|
|
8518
|
+
}
|
|
8519
|
+
function getHighestCardIndex(cards) {
|
|
8520
|
+
let highestIdx = 0;
|
|
8521
|
+
let highestValue = 0;
|
|
8522
|
+
for (let i = 0; i < cards.length; i++) {
|
|
8523
|
+
const value = getRankValue(cards[i].rank);
|
|
8524
|
+
if (value > highestValue) {
|
|
8525
|
+
highestValue = value;
|
|
8526
|
+
highestIdx = i;
|
|
8527
|
+
}
|
|
8528
|
+
}
|
|
8529
|
+
return highestIdx;
|
|
8530
|
+
}
|
|
8531
|
+
function evaluateHand(hole, board) {
|
|
8532
|
+
const allCards = [...hole, ...board];
|
|
8533
|
+
const flush = isFlush(allCards);
|
|
8534
|
+
const straightHighCard = getStraightHighCard(allCards);
|
|
8535
|
+
const maxCount = getMaxCount(allCards);
|
|
8536
|
+
const pairCount = getPairCount(allCards);
|
|
8537
|
+
if (flush && straightHighCard === 14) {
|
|
8538
|
+
const flushSuit = findFlushSuit(allCards);
|
|
8539
|
+
const sfHighCard = getStraightFlushHighCard(allCards, flushSuit);
|
|
8540
|
+
if (sfHighCard === 14) {
|
|
8541
|
+
const participatingCards = getStraightFlushIndices(allCards, 14, flushSuit);
|
|
7867
8542
|
return {
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
isBuilding: portResult.isBuilding
|
|
8543
|
+
rank: 10 /* RoyalFlush */,
|
|
8544
|
+
...HAND_DISPLAY[10 /* RoyalFlush */],
|
|
8545
|
+
participatingCards
|
|
7872
8546
|
};
|
|
7873
8547
|
}
|
|
7874
|
-
return await this.processDetector.detect();
|
|
7875
8548
|
}
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
8549
|
+
if (flush) {
|
|
8550
|
+
const flushSuit = findFlushSuit(allCards);
|
|
8551
|
+
const sfHighCard = getStraightFlushHighCard(allCards, flushSuit);
|
|
8552
|
+
if (sfHighCard !== null) {
|
|
8553
|
+
const participatingCards = getStraightFlushIndices(allCards, sfHighCard, flushSuit);
|
|
8554
|
+
return {
|
|
8555
|
+
rank: 9 /* StraightFlush */,
|
|
8556
|
+
...HAND_DISPLAY[9 /* StraightFlush */],
|
|
8557
|
+
participatingCards
|
|
8558
|
+
};
|
|
8559
|
+
}
|
|
8560
|
+
}
|
|
8561
|
+
if (maxCount === 4) {
|
|
8562
|
+
const rank = getMostCommonRank(allCards);
|
|
8563
|
+
const participatingCards = findCardsOfRank(allCards, rank);
|
|
8564
|
+
return {
|
|
8565
|
+
rank: 8 /* FourOfAKind */,
|
|
8566
|
+
...HAND_DISPLAY[8 /* FourOfAKind */],
|
|
8567
|
+
participatingCards
|
|
8568
|
+
};
|
|
8569
|
+
}
|
|
8570
|
+
if (maxCount === 3 && pairCount >= 1) {
|
|
8571
|
+
const participatingCards = getFullHouseIndices(allCards);
|
|
8572
|
+
return { rank: 7 /* FullHouse */, ...HAND_DISPLAY[7 /* FullHouse */], participatingCards };
|
|
8573
|
+
}
|
|
8574
|
+
if (flush) {
|
|
8575
|
+
const flushSuit = findFlushSuit(allCards);
|
|
8576
|
+
const suitIndices = findCardsOfSuit(allCards, flushSuit);
|
|
8577
|
+
const participatingCards = suitIndices.slice(0, 5);
|
|
8578
|
+
return { rank: 6 /* Flush */, ...HAND_DISPLAY[6 /* Flush */], participatingCards };
|
|
8579
|
+
}
|
|
8580
|
+
if (straightHighCard !== null) {
|
|
8581
|
+
const participatingCards = getStraightIndices(allCards, straightHighCard);
|
|
8582
|
+
return { rank: 5 /* Straight */, ...HAND_DISPLAY[5 /* Straight */], participatingCards };
|
|
8583
|
+
}
|
|
8584
|
+
if (maxCount === 3) {
|
|
8585
|
+
const rank = getMostCommonRank(allCards);
|
|
8586
|
+
const participatingCards = findCardsOfRank(allCards, rank);
|
|
8587
|
+
return {
|
|
8588
|
+
rank: 4 /* ThreeOfAKind */,
|
|
8589
|
+
...HAND_DISPLAY[4 /* ThreeOfAKind */],
|
|
8590
|
+
participatingCards
|
|
8591
|
+
};
|
|
8592
|
+
}
|
|
8593
|
+
if (pairCount >= 2) {
|
|
8594
|
+
const [rank1, rank2] = getTwoPairRanks(allCards);
|
|
8595
|
+
const pair1Indices = findCardsOfRank(allCards, rank1);
|
|
8596
|
+
const pair2Indices = findCardsOfRank(allCards, rank2);
|
|
8597
|
+
const participatingCards = [...pair1Indices, ...pair2Indices];
|
|
8598
|
+
return { rank: 3 /* TwoPair */, ...HAND_DISPLAY[3 /* TwoPair */], participatingCards };
|
|
8599
|
+
}
|
|
8600
|
+
if (pairCount === 1) {
|
|
8601
|
+
const rank = getMostCommonRank(allCards);
|
|
8602
|
+
const participatingCards = findCardsOfRank(allCards, rank);
|
|
8603
|
+
return { rank: 2 /* OnePair */, ...HAND_DISPLAY[2 /* OnePair */], participatingCards };
|
|
8604
|
+
}
|
|
8605
|
+
const highestIdx = getHighestCardIndex(allCards);
|
|
8606
|
+
return {
|
|
8607
|
+
rank: 1 /* HighCard */,
|
|
8608
|
+
...HAND_DISPLAY[1 /* HighCard */],
|
|
8609
|
+
participatingCards: [highestIdx]
|
|
8610
|
+
};
|
|
8611
|
+
}
|
|
7883
8612
|
|
|
7884
|
-
// src/widgets/
|
|
8613
|
+
// src/widgets/poker/styles.ts
|
|
7885
8614
|
init_colors();
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
8615
|
+
init_formatters();
|
|
8616
|
+
var HAND_ABBREVIATIONS = {
|
|
8617
|
+
"Royal Flush": "RF",
|
|
8618
|
+
"Straight Flush": "SF",
|
|
8619
|
+
"Four of a Kind": "4K",
|
|
8620
|
+
"Full House": "FH",
|
|
8621
|
+
Flush: "FL",
|
|
8622
|
+
Straight: "ST",
|
|
8623
|
+
"Three of a Kind": "3K",
|
|
8624
|
+
"Two Pair": "2P",
|
|
8625
|
+
"One Pair": "1P",
|
|
8626
|
+
"High Card": "HC",
|
|
8627
|
+
Nothing: "\u2014"
|
|
8628
|
+
};
|
|
8629
|
+
function formatCardByParticipation(cardData, isParticipating) {
|
|
8630
|
+
const color = isRedSuit(cardData.card.suit) ? red : gray;
|
|
8631
|
+
const cardText = formatCard(cardData.card);
|
|
8632
|
+
if (isParticipating) {
|
|
8633
|
+
return `${color}${bold}(${cardText})${reset} `;
|
|
8634
|
+
} else {
|
|
8635
|
+
return `${color}${cardText}${reset} `;
|
|
8636
|
+
}
|
|
8637
|
+
}
|
|
8638
|
+
function formatCardCompact(cardData, isParticipating) {
|
|
8639
|
+
const color = isRedSuit(cardData.card.suit) ? red : gray;
|
|
8640
|
+
const cardText = formatCardTextCompact(cardData.card);
|
|
8641
|
+
if (isParticipating) {
|
|
8642
|
+
return `${color}${bold}(${cardText})${reset}`;
|
|
8643
|
+
} else {
|
|
8644
|
+
return `${color}${cardText}${reset}`;
|
|
8645
|
+
}
|
|
8646
|
+
}
|
|
8647
|
+
function formatCardTextCompact(card) {
|
|
8648
|
+
const rankSymbols = {
|
|
8649
|
+
"10": "T",
|
|
8650
|
+
"11": "J",
|
|
8651
|
+
"12": "Q",
|
|
8652
|
+
"13": "K",
|
|
8653
|
+
"14": "A"
|
|
8654
|
+
};
|
|
8655
|
+
const rank = String(card.rank);
|
|
8656
|
+
const rankSymbol = rankSymbols[rank] ?? rank;
|
|
8657
|
+
return `${rankSymbol}${card.suit}`;
|
|
8658
|
+
}
|
|
8659
|
+
function formatCardEmojiByParticipation(cardData, isParticipating) {
|
|
8660
|
+
const cardText = formatCardEmoji(cardData.card);
|
|
8661
|
+
if (isParticipating) {
|
|
8662
|
+
return `${bold}(${cardText})${reset} `;
|
|
8663
|
+
} else {
|
|
8664
|
+
return `${cardText} `;
|
|
8665
|
+
}
|
|
8666
|
+
}
|
|
8667
|
+
function formatHandResult(handResult, colors2) {
|
|
8668
|
+
if (!handResult) {
|
|
8669
|
+
return "\u2014";
|
|
8670
|
+
}
|
|
8671
|
+
const playerParticipates = handResult.participatingIndices.some((idx) => idx < 2);
|
|
8672
|
+
const resultText = !playerParticipates ? `Nothing \u{1F0CF}` : `${handResult.name}! ${handResult.emoji}`;
|
|
8673
|
+
if (!colors2) return resultText;
|
|
8674
|
+
return colorize2(resultText, colors2.result);
|
|
8675
|
+
}
|
|
8676
|
+
function getHandAbbreviation(handResult) {
|
|
8677
|
+
if (!handResult) {
|
|
8678
|
+
return "\u2014 (\u2014)";
|
|
8679
|
+
}
|
|
8680
|
+
const abbreviation = HAND_ABBREVIATIONS[handResult.name] ?? "\u2014";
|
|
8681
|
+
return `${abbreviation} (${handResult.name})`;
|
|
8682
|
+
}
|
|
8683
|
+
function balancedStyle2(data, colors2) {
|
|
8684
|
+
const { holeCards, boardCards, handResult } = data;
|
|
8685
|
+
const participatingSet = new Set(handResult?.participatingIndices || []);
|
|
8686
|
+
const handStr = holeCards.map((hc, idx) => formatCardByParticipation(hc, participatingSet.has(idx))).join("");
|
|
8687
|
+
const boardStr = boardCards.map((bc, idx) => formatCardByParticipation(bc, participatingSet.has(idx + 2))).join("");
|
|
8688
|
+
const labelColor = colors2?.participating ?? lightGray;
|
|
8689
|
+
const handLabel = colorize2("Hand:", labelColor);
|
|
8690
|
+
const boardLabel = colorize2("Board:", labelColor);
|
|
8691
|
+
return `${handLabel} ${handStr}| ${boardLabel} ${boardStr}\u2192 ${formatHandResult(handResult, colors2)}`;
|
|
8692
|
+
}
|
|
8693
|
+
var pokerStyles = {
|
|
8694
|
+
balanced: balancedStyle2,
|
|
8695
|
+
compact: balancedStyle2,
|
|
8696
|
+
playful: balancedStyle2,
|
|
8697
|
+
"compact-verbose": (data, colors2) => {
|
|
8698
|
+
const { holeCards, boardCards, handResult } = data;
|
|
8699
|
+
const participatingSet = new Set(handResult?.participatingIndices || []);
|
|
8700
|
+
const handStr = holeCards.map((hc, idx) => formatCardCompact(hc, participatingSet.has(idx))).join("");
|
|
8701
|
+
const boardStr = boardCards.map((bc, idx) => formatCardCompact(bc, participatingSet.has(idx + 2))).join("");
|
|
8702
|
+
const abbreviation = getHandAbbreviation(handResult);
|
|
8703
|
+
const result = `${handStr}| ${boardStr}\u2192 ${abbreviation}`;
|
|
8704
|
+
if (!colors2) return result;
|
|
8705
|
+
return colorize2(result, colors2.result);
|
|
7932
8706
|
},
|
|
7933
|
-
|
|
7934
|
-
const {
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
const
|
|
7940
|
-
const
|
|
7941
|
-
|
|
7942
|
-
return `\u25CF ${label} ${coloredCount}`;
|
|
8707
|
+
emoji: (data, colors2) => {
|
|
8708
|
+
const { holeCards, boardCards, handResult } = data;
|
|
8709
|
+
const participatingSet = new Set(handResult?.participatingIndices || []);
|
|
8710
|
+
const handStr = holeCards.map((hc, idx) => formatCardEmojiByParticipation(hc, participatingSet.has(idx))).join("");
|
|
8711
|
+
const boardStr = boardCards.map((bc, idx) => formatCardEmojiByParticipation(bc, participatingSet.has(idx + 2))).join("");
|
|
8712
|
+
const labelColor = colors2?.participating ?? lightGray;
|
|
8713
|
+
const handLabel = colorize2("Hand:", labelColor);
|
|
8714
|
+
const boardLabel = colorize2("Board:", labelColor);
|
|
8715
|
+
return `${handLabel} ${handStr}| ${boardLabel} ${boardStr}\u2192 ${formatHandResult(handResult, colors2)}`;
|
|
7943
8716
|
}
|
|
7944
8717
|
};
|
|
7945
8718
|
|
|
7946
|
-
// src/widgets/
|
|
7947
|
-
var
|
|
7948
|
-
|
|
7949
|
-
id = "docker";
|
|
8719
|
+
// src/widgets/poker-widget.ts
|
|
8720
|
+
var PokerWidget = class extends StdinDataWidget {
|
|
8721
|
+
id = "poker";
|
|
7950
8722
|
metadata = createWidgetMetadata(
|
|
7951
|
-
"
|
|
7952
|
-
"
|
|
8723
|
+
"Poker",
|
|
8724
|
+
"Displays random Texas Hold'em hands for entertainment",
|
|
7953
8725
|
"1.0.0",
|
|
7954
8726
|
"claude-scope",
|
|
7955
|
-
|
|
8727
|
+
4
|
|
8728
|
+
// Fifth line (0-indexed)
|
|
7956
8729
|
);
|
|
7957
|
-
|
|
8730
|
+
holeCards = [];
|
|
8731
|
+
boardCards = [];
|
|
8732
|
+
handResult = null;
|
|
8733
|
+
lastUpdateTimestamp = 0;
|
|
8734
|
+
THROTTLE_MS = 5e3;
|
|
8735
|
+
// 5 seconds
|
|
7958
8736
|
colors;
|
|
7959
8737
|
_lineOverride;
|
|
7960
|
-
styleFn =
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
CACHE_TTL = 5e3;
|
|
7964
|
-
constructor(colors2) {
|
|
7965
|
-
this.colors = colors2 ?? DEFAULT_THEME;
|
|
7966
|
-
}
|
|
7967
|
-
setStyle(style = "balanced") {
|
|
7968
|
-
const fn = dockerStyles[style];
|
|
8738
|
+
styleFn = pokerStyles.balanced;
|
|
8739
|
+
setStyle(style = DEFAULT_WIDGET_STYLE) {
|
|
8740
|
+
const fn = pokerStyles[style];
|
|
7969
8741
|
if (fn) {
|
|
7970
8742
|
this.styleFn = fn;
|
|
7971
8743
|
}
|
|
@@ -7976,56 +8748,84 @@ var DockerWidget = class {
|
|
|
7976
8748
|
getLine() {
|
|
7977
8749
|
return this._lineOverride ?? this.metadata.line ?? 0;
|
|
7978
8750
|
}
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
async update(_data) {
|
|
7983
|
-
}
|
|
7984
|
-
isEnabled() {
|
|
7985
|
-
return this.enabled;
|
|
7986
|
-
}
|
|
7987
|
-
async cleanup() {
|
|
8751
|
+
constructor(colors2) {
|
|
8752
|
+
super();
|
|
8753
|
+
this.colors = colors2 ?? DEFAULT_THEME;
|
|
7988
8754
|
}
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
8755
|
+
/**
|
|
8756
|
+
* Generate new poker hand on each update
|
|
8757
|
+
*/
|
|
8758
|
+
async update(data) {
|
|
8759
|
+
await super.update(data);
|
|
7993
8760
|
const now = Date.now();
|
|
7994
|
-
if (this.
|
|
7995
|
-
return
|
|
8761
|
+
if (this.lastUpdateTimestamp > 0 && now - this.lastUpdateTimestamp < this.THROTTLE_MS) {
|
|
8762
|
+
return;
|
|
7996
8763
|
}
|
|
7997
|
-
const
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8764
|
+
const deck = new Deck();
|
|
8765
|
+
const hole = [deck.deal(), deck.deal()];
|
|
8766
|
+
const board = [deck.deal(), deck.deal(), deck.deal(), deck.deal(), deck.deal()];
|
|
8767
|
+
const result = evaluateHand(hole, board);
|
|
8768
|
+
this.holeCards = hole.map((card) => ({
|
|
8769
|
+
card,
|
|
8770
|
+
formatted: this.formatCardColor(card)
|
|
8771
|
+
}));
|
|
8772
|
+
this.boardCards = board.map((card) => ({
|
|
8773
|
+
card,
|
|
8774
|
+
formatted: this.formatCardColor(card)
|
|
8775
|
+
}));
|
|
8776
|
+
const playerParticipates = result.participatingCards.some((idx) => idx < 2);
|
|
8777
|
+
if (!playerParticipates) {
|
|
8778
|
+
this.handResult = {
|
|
8779
|
+
text: `Nothing \u{1F0CF}`,
|
|
8780
|
+
participatingIndices: result.participatingCards
|
|
8781
|
+
};
|
|
8782
|
+
} else {
|
|
8783
|
+
this.handResult = {
|
|
8784
|
+
text: `${result.name}! ${result.emoji}`,
|
|
8785
|
+
participatingIndices: result.participatingCards
|
|
8786
|
+
};
|
|
8002
8787
|
}
|
|
8003
|
-
|
|
8788
|
+
this.lastUpdateTimestamp = now;
|
|
8004
8789
|
}
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8790
|
+
/**
|
|
8791
|
+
* Format card with appropriate color (red for ♥♦, gray for ♠♣)
|
|
8792
|
+
*/
|
|
8793
|
+
formatCardColor(card) {
|
|
8794
|
+
const _color = isRedSuit(card.suit) ? "red" : "gray";
|
|
8795
|
+
return formatCard(card);
|
|
8796
|
+
}
|
|
8797
|
+
renderWithData(_data, _context) {
|
|
8798
|
+
const holeCardsData = this.holeCards.map((hc, idx) => ({
|
|
8799
|
+
card: hc.card,
|
|
8800
|
+
isParticipating: (this.handResult?.participatingIndices || []).includes(idx)
|
|
8801
|
+
}));
|
|
8802
|
+
const boardCardsData = this.boardCards.map((bc, idx) => ({
|
|
8803
|
+
card: bc.card,
|
|
8804
|
+
isParticipating: (this.handResult?.participatingIndices || []).includes(idx + 2)
|
|
8805
|
+
}));
|
|
8806
|
+
const handResult = this.handResult ? {
|
|
8807
|
+
name: this.getHandName(this.handResult.text),
|
|
8808
|
+
emoji: this.getHandEmoji(this.handResult.text),
|
|
8809
|
+
participatingIndices: this.handResult.participatingIndices
|
|
8810
|
+
} : null;
|
|
8811
|
+
const renderData = {
|
|
8812
|
+
holeCards: holeCardsData,
|
|
8813
|
+
boardCards: boardCardsData,
|
|
8814
|
+
handResult
|
|
8815
|
+
};
|
|
8816
|
+
return this.styleFn(renderData, this.colors.poker);
|
|
8817
|
+
}
|
|
8818
|
+
getHandName(text) {
|
|
8819
|
+
const match = text.match(/^([^!]+)/);
|
|
8820
|
+
return match ? match[1].trim() : "Nothing";
|
|
8821
|
+
}
|
|
8822
|
+
getHandEmoji(text) {
|
|
8823
|
+
const match = text.match(/([🃏♠️♥️♦️♣️🎉✨🌟])/u);
|
|
8824
|
+
return match ? match[1] : "\u{1F0CF}";
|
|
8020
8825
|
}
|
|
8021
8826
|
};
|
|
8022
8827
|
|
|
8023
8828
|
// src/core/widget-factory.ts
|
|
8024
|
-
init_duration_widget();
|
|
8025
|
-
init_git_tag_widget();
|
|
8026
|
-
init_git_widget();
|
|
8027
|
-
init_lines_widget();
|
|
8028
|
-
init_model_widget();
|
|
8029
8829
|
var WidgetFactory = class {
|
|
8030
8830
|
transcriptProvider;
|
|
8031
8831
|
constructor() {
|
|
@@ -8062,6 +8862,10 @@ var WidgetFactory = class {
|
|
|
8062
8862
|
return new DevServerWidget(DEFAULT_THEME);
|
|
8063
8863
|
case "docker":
|
|
8064
8864
|
return new DockerWidget(DEFAULT_THEME);
|
|
8865
|
+
case "poker":
|
|
8866
|
+
return new PokerWidget(DEFAULT_THEME);
|
|
8867
|
+
case "empty-line":
|
|
8868
|
+
return new EmptyLineWidget();
|
|
8065
8869
|
default:
|
|
8066
8870
|
return null;
|
|
8067
8871
|
}
|
|
@@ -8082,7 +8886,9 @@ var WidgetFactory = class {
|
|
|
8082
8886
|
"cache-metrics",
|
|
8083
8887
|
"active-tools",
|
|
8084
8888
|
"dev-server",
|
|
8085
|
-
"docker"
|
|
8889
|
+
"docker",
|
|
8890
|
+
"poker",
|
|
8891
|
+
"empty-line"
|
|
8086
8892
|
];
|
|
8087
8893
|
}
|
|
8088
8894
|
};
|