claude-scope 0.3.2 → 0.4.1

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.
@@ -440,6 +440,7 @@ function colorize(text, color) {
440
440
  }
441
441
 
442
442
  // src/ui/utils/colors.ts
443
+ var red = "\x1B[31m";
443
444
  var gray = "\x1B[90m";
444
445
 
445
446
  // src/ui/theme/default-theme.ts
@@ -823,6 +824,486 @@ var ConfigCountWidget = class {
823
824
  }
824
825
  };
825
826
 
827
+ // src/widgets/poker/deck.ts
828
+ var import_node_crypto = require("node:crypto");
829
+
830
+ // src/widgets/poker/types.ts
831
+ var Suit = {
832
+ Spades: "spades",
833
+ Hearts: "hearts",
834
+ Diamonds: "diamonds",
835
+ Clubs: "clubs"
836
+ };
837
+ var SUIT_SYMBOLS = {
838
+ spades: "\u2660",
839
+ hearts: "\u2665",
840
+ diamonds: "\u2666",
841
+ clubs: "\u2663"
842
+ };
843
+ function isRedSuit(suit) {
844
+ return suit === "hearts" || suit === "diamonds";
845
+ }
846
+ var Rank = {
847
+ Two: "2",
848
+ Three: "3",
849
+ Four: "4",
850
+ Five: "5",
851
+ Six: "6",
852
+ Seven: "7",
853
+ Eight: "8",
854
+ Nine: "9",
855
+ Ten: "10",
856
+ Jack: "J",
857
+ Queen: "Q",
858
+ King: "K",
859
+ Ace: "A"
860
+ };
861
+ function getRankValue(rank) {
862
+ const values = {
863
+ "2": 2,
864
+ "3": 3,
865
+ "4": 4,
866
+ "5": 5,
867
+ "6": 6,
868
+ "7": 7,
869
+ "8": 8,
870
+ "9": 9,
871
+ "10": 10,
872
+ "J": 11,
873
+ "Q": 12,
874
+ "K": 13,
875
+ "A": 14
876
+ };
877
+ return values[rank];
878
+ }
879
+ function formatCard(card) {
880
+ return `${card.rank}${SUIT_SYMBOLS[card.suit]}`;
881
+ }
882
+
883
+ // src/widgets/poker/deck.ts
884
+ var ALL_SUITS = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs];
885
+ var ALL_RANKS = [
886
+ Rank.Two,
887
+ Rank.Three,
888
+ Rank.Four,
889
+ Rank.Five,
890
+ Rank.Six,
891
+ Rank.Seven,
892
+ Rank.Eight,
893
+ Rank.Nine,
894
+ Rank.Ten,
895
+ Rank.Jack,
896
+ Rank.Queen,
897
+ Rank.King,
898
+ Rank.Ace
899
+ ];
900
+ var Deck = class {
901
+ cards = [];
902
+ constructor() {
903
+ this.initialize();
904
+ this.shuffle();
905
+ }
906
+ /**
907
+ * Create a standard 52-card deck
908
+ */
909
+ initialize() {
910
+ this.cards = [];
911
+ for (const suit of ALL_SUITS) {
912
+ for (const rank of ALL_RANKS) {
913
+ this.cards.push({ rank, suit });
914
+ }
915
+ }
916
+ }
917
+ /**
918
+ * Shuffle deck using Fisher-Yates algorithm with crypto.random
919
+ */
920
+ shuffle() {
921
+ for (let i = this.cards.length - 1; i > 0; i--) {
922
+ const j = (0, import_node_crypto.randomInt)(0, i + 1);
923
+ [this.cards[i], this.cards[j]] = [this.cards[j], this.cards[i]];
924
+ }
925
+ }
926
+ /**
927
+ * Deal one card from the top of the deck
928
+ * @throws Error if deck is empty
929
+ */
930
+ deal() {
931
+ if (this.cards.length === 0) {
932
+ throw new Error("Deck is empty");
933
+ }
934
+ return this.cards.pop();
935
+ }
936
+ /**
937
+ * Get number of remaining cards in deck
938
+ */
939
+ remaining() {
940
+ return this.cards.length;
941
+ }
942
+ };
943
+
944
+ // src/widgets/poker/hand-evaluator.ts
945
+ var HAND_DISPLAY = {
946
+ [10 /* RoyalFlush */]: { name: "Royal Flush", emoji: "\u{1F3C6}" },
947
+ [9 /* StraightFlush */]: { name: "Straight Flush", emoji: "\u{1F525}" },
948
+ [8 /* FourOfAKind */]: { name: "Four of a Kind", emoji: "\u{1F48E}" },
949
+ [7 /* FullHouse */]: { name: "Full House", emoji: "\u{1F3E0}" },
950
+ [6 /* Flush */]: { name: "Flush", emoji: "\u{1F4A7}" },
951
+ [5 /* Straight */]: { name: "Straight", emoji: "\u{1F4C8}" },
952
+ [4 /* ThreeOfAKind */]: { name: "Three of a Kind", emoji: "\u{1F3AF}" },
953
+ [3 /* TwoPair */]: { name: "Two Pair", emoji: "\u270C\uFE0F" },
954
+ [2 /* OnePair */]: { name: "One Pair", emoji: "\u{1F44D}" },
955
+ [1 /* HighCard */]: { name: "High Card", emoji: "\u{1F0CF}" }
956
+ };
957
+ function countRanks(cards) {
958
+ const counts = /* @__PURE__ */ new Map();
959
+ for (const card of cards) {
960
+ const value = getRankValue(card.rank);
961
+ counts.set(value, (counts.get(value) || 0) + 1);
962
+ }
963
+ return counts;
964
+ }
965
+ function countSuits(cards) {
966
+ const counts = /* @__PURE__ */ new Map();
967
+ for (const card of cards) {
968
+ counts.set(card.suit, (counts.get(card.suit) || 0) + 1);
969
+ }
970
+ return counts;
971
+ }
972
+ function findCardsOfRank(cards, targetRank) {
973
+ const indices = [];
974
+ for (let i = 0; i < cards.length; i++) {
975
+ if (getRankValue(cards[i].rank) === targetRank) {
976
+ indices.push(i);
977
+ }
978
+ }
979
+ return indices;
980
+ }
981
+ function findCardsOfSuit(cards, targetSuit) {
982
+ const indices = [];
983
+ for (let i = 0; i < cards.length; i++) {
984
+ if (cards[i].suit === targetSuit) {
985
+ indices.push(i);
986
+ }
987
+ }
988
+ return indices;
989
+ }
990
+ function findFlushSuit(cards) {
991
+ const suitCounts = countSuits(cards);
992
+ for (const [suit, count] of suitCounts.entries()) {
993
+ if (count >= 5) return suit;
994
+ }
995
+ return null;
996
+ }
997
+ function getStraightIndices(cards, highCard) {
998
+ const uniqueValues = /* @__PURE__ */ new Set();
999
+ const cardIndicesByRank = /* @__PURE__ */ new Map();
1000
+ for (let i = 0; i < cards.length; i++) {
1001
+ const value = getRankValue(cards[i].rank);
1002
+ if (!cardIndicesByRank.has(value)) {
1003
+ cardIndicesByRank.set(value, []);
1004
+ uniqueValues.add(value);
1005
+ }
1006
+ cardIndicesByRank.get(value).push(i);
1007
+ }
1008
+ const sortedValues = Array.from(uniqueValues).sort((a, b) => b - a);
1009
+ if (sortedValues.includes(14)) {
1010
+ sortedValues.push(1);
1011
+ }
1012
+ for (let i = 0; i <= sortedValues.length - 5; i++) {
1013
+ const current = sortedValues[i];
1014
+ const next1 = sortedValues[i + 1];
1015
+ const next2 = sortedValues[i + 2];
1016
+ const next3 = sortedValues[i + 3];
1017
+ const next4 = sortedValues[i + 4];
1018
+ if (current - next1 === 1 && current - next2 === 2 && current - next3 === 3 && current - next4 === 4) {
1019
+ if (current === highCard) {
1020
+ const indices = [];
1021
+ indices.push(cardIndicesByRank.get(current)[0]);
1022
+ indices.push(cardIndicesByRank.get(next1)[0]);
1023
+ indices.push(cardIndicesByRank.get(next2)[0]);
1024
+ indices.push(cardIndicesByRank.get(next3)[0]);
1025
+ indices.push(cardIndicesByRank.get(next4)[0]);
1026
+ return indices;
1027
+ }
1028
+ }
1029
+ }
1030
+ return [];
1031
+ }
1032
+ function getStraightFlushHighCard(cards, suit) {
1033
+ const suitCards = cards.filter((c) => c.suit === suit);
1034
+ return getStraightHighCard(suitCards);
1035
+ }
1036
+ function getStraightFlushIndices(cards, highCard, suit) {
1037
+ const suitCards = cards.filter((c) => c.suit === suit);
1038
+ const suitCardIndices = [];
1039
+ const indexMap = /* @__PURE__ */ new Map();
1040
+ for (let i = 0; i < cards.length; i++) {
1041
+ if (cards[i].suit === suit) {
1042
+ indexMap.set(suitCardIndices.length, i);
1043
+ suitCardIndices.push(cards[i]);
1044
+ }
1045
+ }
1046
+ const indices = getStraightIndices(suitCardIndices, highCard);
1047
+ return indices.map((idx) => indexMap.get(idx));
1048
+ }
1049
+ function getFullHouseIndices(cards) {
1050
+ const rankCounts = countRanks(cards);
1051
+ let tripsRank = 0;
1052
+ for (const [rank, count] of rankCounts.entries()) {
1053
+ if (count === 3) {
1054
+ tripsRank = rank;
1055
+ break;
1056
+ }
1057
+ }
1058
+ let pairRank = 0;
1059
+ for (const [rank, count] of rankCounts.entries()) {
1060
+ if (count >= 2 && rank !== tripsRank) {
1061
+ pairRank = rank;
1062
+ break;
1063
+ }
1064
+ }
1065
+ if (pairRank === 0) {
1066
+ const tripsRanks = [];
1067
+ for (const [rank, count] of rankCounts.entries()) {
1068
+ if (count === 3) {
1069
+ tripsRanks.push(rank);
1070
+ }
1071
+ }
1072
+ if (tripsRanks.length >= 2) {
1073
+ tripsRanks.sort((a, b) => b - a);
1074
+ tripsRank = tripsRanks[0];
1075
+ pairRank = tripsRanks[1];
1076
+ }
1077
+ }
1078
+ const tripsIndices = findCardsOfRank(cards, tripsRank);
1079
+ const pairIndices = findCardsOfRank(cards, pairRank);
1080
+ return [...tripsIndices.slice(0, 3), ...pairIndices.slice(0, 2)];
1081
+ }
1082
+ function isFlush(cards) {
1083
+ const suitCounts = countSuits(cards);
1084
+ for (const count of suitCounts.values()) {
1085
+ if (count >= 5) return true;
1086
+ }
1087
+ return false;
1088
+ }
1089
+ function getStraightHighCard(cards) {
1090
+ const uniqueValues = /* @__PURE__ */ new Set();
1091
+ for (const card of cards) {
1092
+ uniqueValues.add(getRankValue(card.rank));
1093
+ }
1094
+ const sortedValues = Array.from(uniqueValues).sort((a, b) => b - a);
1095
+ if (sortedValues.includes(14)) {
1096
+ sortedValues.push(1);
1097
+ }
1098
+ for (let i = 0; i <= sortedValues.length - 5; i++) {
1099
+ const current = sortedValues[i];
1100
+ const next1 = sortedValues[i + 1];
1101
+ const next2 = sortedValues[i + 2];
1102
+ const next3 = sortedValues[i + 3];
1103
+ const next4 = sortedValues[i + 4];
1104
+ if (current - next1 === 1 && current - next2 === 2 && current - next3 === 3 && current - next4 === 4) {
1105
+ return current;
1106
+ }
1107
+ }
1108
+ return null;
1109
+ }
1110
+ function getMaxCount(cards) {
1111
+ const rankCounts = countRanks(cards);
1112
+ let maxCount = 0;
1113
+ for (const count of rankCounts.values()) {
1114
+ if (count > maxCount) {
1115
+ maxCount = count;
1116
+ }
1117
+ }
1118
+ return maxCount;
1119
+ }
1120
+ function getPairCount(cards) {
1121
+ const rankCounts = countRanks(cards);
1122
+ let pairCount = 0;
1123
+ for (const count of rankCounts.values()) {
1124
+ if (count === 2) {
1125
+ pairCount++;
1126
+ }
1127
+ }
1128
+ return pairCount;
1129
+ }
1130
+ function getMostCommonRank(cards) {
1131
+ const rankCounts = countRanks(cards);
1132
+ let bestRank = 0;
1133
+ let bestCount = 0;
1134
+ for (const [rank, count] of rankCounts.entries()) {
1135
+ if (count > bestCount) {
1136
+ bestCount = count;
1137
+ bestRank = rank;
1138
+ }
1139
+ }
1140
+ return bestRank > 0 ? bestRank : null;
1141
+ }
1142
+ function getTwoPairRanks(cards) {
1143
+ const rankCounts = countRanks(cards);
1144
+ const pairRanks = [];
1145
+ for (const [rank, count] of rankCounts.entries()) {
1146
+ if (count >= 2) {
1147
+ pairRanks.push(rank);
1148
+ }
1149
+ }
1150
+ pairRanks.sort((a, b) => b - a);
1151
+ return pairRanks.slice(0, 2);
1152
+ }
1153
+ function getHighestCardIndex(cards) {
1154
+ let highestIdx = 0;
1155
+ let highestValue = 0;
1156
+ for (let i = 0; i < cards.length; i++) {
1157
+ const value = getRankValue(cards[i].rank);
1158
+ if (value > highestValue) {
1159
+ highestValue = value;
1160
+ highestIdx = i;
1161
+ }
1162
+ }
1163
+ return highestIdx;
1164
+ }
1165
+ function evaluateHand(hole, board) {
1166
+ const allCards = [...hole, ...board];
1167
+ const flush = isFlush(allCards);
1168
+ const straightHighCard = getStraightHighCard(allCards);
1169
+ const maxCount = getMaxCount(allCards);
1170
+ const pairCount = getPairCount(allCards);
1171
+ if (flush && straightHighCard === 14) {
1172
+ const flushSuit = findFlushSuit(allCards);
1173
+ const sfHighCard = getStraightFlushHighCard(allCards, flushSuit);
1174
+ if (sfHighCard === 14) {
1175
+ const participatingCards = getStraightFlushIndices(allCards, 14, flushSuit);
1176
+ return { rank: 10 /* RoyalFlush */, ...HAND_DISPLAY[10 /* RoyalFlush */], participatingCards };
1177
+ }
1178
+ }
1179
+ if (flush) {
1180
+ const flushSuit = findFlushSuit(allCards);
1181
+ const sfHighCard = getStraightFlushHighCard(allCards, flushSuit);
1182
+ if (sfHighCard !== null) {
1183
+ const participatingCards = getStraightFlushIndices(allCards, sfHighCard, flushSuit);
1184
+ return { rank: 9 /* StraightFlush */, ...HAND_DISPLAY[9 /* StraightFlush */], participatingCards };
1185
+ }
1186
+ }
1187
+ if (maxCount === 4) {
1188
+ const rank = getMostCommonRank(allCards);
1189
+ const participatingCards = findCardsOfRank(allCards, rank);
1190
+ return { rank: 8 /* FourOfAKind */, ...HAND_DISPLAY[8 /* FourOfAKind */], participatingCards };
1191
+ }
1192
+ if (maxCount === 3 && pairCount >= 1) {
1193
+ const participatingCards = getFullHouseIndices(allCards);
1194
+ return { rank: 7 /* FullHouse */, ...HAND_DISPLAY[7 /* FullHouse */], participatingCards };
1195
+ }
1196
+ if (flush) {
1197
+ const flushSuit = findFlushSuit(allCards);
1198
+ const suitIndices = findCardsOfSuit(allCards, flushSuit);
1199
+ const participatingCards = suitIndices.slice(0, 5);
1200
+ return { rank: 6 /* Flush */, ...HAND_DISPLAY[6 /* Flush */], participatingCards };
1201
+ }
1202
+ if (straightHighCard !== null) {
1203
+ const participatingCards = getStraightIndices(allCards, straightHighCard);
1204
+ return { rank: 5 /* Straight */, ...HAND_DISPLAY[5 /* Straight */], participatingCards };
1205
+ }
1206
+ if (maxCount === 3) {
1207
+ const rank = getMostCommonRank(allCards);
1208
+ const participatingCards = findCardsOfRank(allCards, rank);
1209
+ return { rank: 4 /* ThreeOfAKind */, ...HAND_DISPLAY[4 /* ThreeOfAKind */], participatingCards };
1210
+ }
1211
+ if (pairCount >= 2) {
1212
+ const [rank1, rank2] = getTwoPairRanks(allCards);
1213
+ const pair1Indices = findCardsOfRank(allCards, rank1);
1214
+ const pair2Indices = findCardsOfRank(allCards, rank2);
1215
+ const participatingCards = [...pair1Indices, ...pair2Indices];
1216
+ return { rank: 3 /* TwoPair */, ...HAND_DISPLAY[3 /* TwoPair */], participatingCards };
1217
+ }
1218
+ if (pairCount === 1) {
1219
+ const rank = getMostCommonRank(allCards);
1220
+ const participatingCards = findCardsOfRank(allCards, rank);
1221
+ return { rank: 2 /* OnePair */, ...HAND_DISPLAY[2 /* OnePair */], participatingCards };
1222
+ }
1223
+ const highestIdx = getHighestCardIndex(allCards);
1224
+ return { rank: 1 /* HighCard */, ...HAND_DISPLAY[1 /* HighCard */], participatingCards: [highestIdx] };
1225
+ }
1226
+
1227
+ // src/widgets/poker-widget.ts
1228
+ var PokerWidget = class extends StdinDataWidget {
1229
+ id = "poker";
1230
+ metadata = createWidgetMetadata(
1231
+ "Poker",
1232
+ "Displays random Texas Hold'em hands for entertainment",
1233
+ "1.0.0",
1234
+ "claude-scope",
1235
+ 2
1236
+ // Third line (0-indexed)
1237
+ );
1238
+ holeCards = [];
1239
+ boardCards = [];
1240
+ handResult = null;
1241
+ constructor() {
1242
+ super();
1243
+ }
1244
+ /**
1245
+ * Generate new poker hand on each update
1246
+ */
1247
+ async update(data) {
1248
+ await super.update(data);
1249
+ const deck = new Deck();
1250
+ const hole = [deck.deal(), deck.deal()];
1251
+ const board = [deck.deal(), deck.deal(), deck.deal(), deck.deal(), deck.deal()];
1252
+ const result = evaluateHand(hole, board);
1253
+ this.holeCards = hole.map((card) => ({
1254
+ card,
1255
+ formatted: this.formatCardColor(card)
1256
+ }));
1257
+ this.boardCards = board.map((card) => ({
1258
+ card,
1259
+ formatted: this.formatCardColor(card)
1260
+ }));
1261
+ const playerParticipates = result.participatingCards.some((idx) => idx < 2);
1262
+ if (!playerParticipates) {
1263
+ this.handResult = {
1264
+ text: `Nothing \u{1F0CF}`,
1265
+ participatingIndices: result.participatingCards
1266
+ };
1267
+ } else {
1268
+ this.handResult = {
1269
+ text: `${result.name}! ${result.emoji}`,
1270
+ participatingIndices: result.participatingCards
1271
+ };
1272
+ }
1273
+ }
1274
+ /**
1275
+ * Format card with appropriate color (red for ♥♦, gray for ♠♣)
1276
+ */
1277
+ formatCardColor(card) {
1278
+ const color = isRedSuit(card.suit) ? red : gray;
1279
+ return colorize(`[${formatCard(card)}]`, color);
1280
+ }
1281
+ /**
1282
+ * Format card based on participation in best hand
1283
+ * Participating cards: [K♠] (with brackets)
1284
+ * Non-participating cards: K♠ (spaces instead of brackets)
1285
+ */
1286
+ formatCardByParticipation(cardData, isParticipating) {
1287
+ if (isParticipating) {
1288
+ return cardData.formatted;
1289
+ } else {
1290
+ const inner = cardData.formatted.match(/\[(.+)\]/)?.[1] || cardData.formatted;
1291
+ const colorMatch = cardData.formatted.match(/^(\x1b\[\d+m)/);
1292
+ const color = colorMatch ? colorMatch[1] : "";
1293
+ const reset = cardData.formatted.match(/\x1b\[0m$/) ? "\x1B[0m" : "";
1294
+ return ` ${color}${inner}${reset} `;
1295
+ }
1296
+ }
1297
+ renderWithData(_data, _context) {
1298
+ const participatingSet = new Set(this.handResult?.participatingIndices || []);
1299
+ const handStr = this.holeCards.map((hc, idx) => this.formatCardByParticipation(hc, participatingSet.has(idx))).join("");
1300
+ const boardStr = this.boardCards.map((bc, idx) => this.formatCardByParticipation(bc, participatingSet.has(idx + 2))).join("");
1301
+ const handLabel = colorize("Hand:", gray);
1302
+ const boardLabel = colorize("Board:", gray);
1303
+ return `${handLabel} ${handStr} | ${boardLabel} ${boardStr} \u2192 ${this.handResult?.text}`;
1304
+ }
1305
+ };
1306
+
826
1307
  // src/validation/result.ts
827
1308
  function success(data) {
828
1309
  return { success: true, data };
@@ -1026,6 +1507,7 @@ async function main() {
1026
1507
  await registry.register(new GitWidget());
1027
1508
  await registry.register(new GitChangesWidget());
1028
1509
  await registry.register(new ConfigCountWidget());
1510
+ await registry.register(new PokerWidget());
1029
1511
  const renderer = new Renderer({
1030
1512
  separator: " \u2502 ",
1031
1513
  onError: (error, widget) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-scope",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "Claude Code plugin for session status and analytics",
5
5
  "license": "MIT",
6
6
  "type": "module",