git-slot-machine 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/animation/slotMachine.js +47 -44
  2. package/dist/index.js +4 -1
  3. package/dist/templates/post-commit.d.ts +1 -1
  4. package/dist/templates/post-commit.js +3 -11
  5. package/package.json +6 -1
  6. package/.claude/release.md +0 -74
  7. package/CHANGELOG.md +0 -241
  8. package/dist/animation/slotMachine.d.ts.map +0 -1
  9. package/dist/animation/slotMachine.js.map +0 -1
  10. package/dist/api.d.ts.map +0 -1
  11. package/dist/api.js.map +0 -1
  12. package/dist/balance.d.ts.map +0 -1
  13. package/dist/balance.js.map +0 -1
  14. package/dist/commands/auth.d.ts.map +0 -1
  15. package/dist/commands/auth.js.map +0 -1
  16. package/dist/commands/balance.d.ts.map +0 -1
  17. package/dist/commands/balance.js.map +0 -1
  18. package/dist/commands/config.d.ts.map +0 -1
  19. package/dist/commands/config.js.map +0 -1
  20. package/dist/commands/init.d.ts.map +0 -1
  21. package/dist/commands/init.js.map +0 -1
  22. package/dist/commands/play.d.ts.map +0 -1
  23. package/dist/commands/play.js.map +0 -1
  24. package/dist/commands/spin.d.ts.map +0 -1
  25. package/dist/commands/spin.js.map +0 -1
  26. package/dist/commands/sync.d.ts.map +0 -1
  27. package/dist/commands/sync.js.map +0 -1
  28. package/dist/commands/test.d.ts.map +0 -1
  29. package/dist/commands/test.js.map +0 -1
  30. package/dist/config.d.ts.map +0 -1
  31. package/dist/config.js.map +0 -1
  32. package/dist/index.d.ts.map +0 -1
  33. package/dist/index.js.map +0 -1
  34. package/dist/patterns.d.ts.map +0 -1
  35. package/dist/patterns.js.map +0 -1
  36. package/dist/secrets.d.ts.map +0 -1
  37. package/dist/secrets.js.map +0 -1
  38. package/dist/templates/post-commit.d.ts.map +0 -1
  39. package/dist/templates/post-commit.js.map +0 -1
  40. package/dist/utils/amendDetector.d.ts.map +0 -1
  41. package/dist/utils/amendDetector.js.map +0 -1
  42. package/dist/utils/fetch-polyfill.d.ts.map +0 -1
  43. package/dist/utils/fetch-polyfill.js.map +0 -1
  44. package/dist/utils/git.d.ts.map +0 -1
  45. package/dist/utils/git.js.map +0 -1
  46. package/jest.config.js +0 -12
  47. package/src/animation/slotMachine.ts +0 -159
  48. package/src/api.ts +0 -207
  49. package/src/balance.ts +0 -118
  50. package/src/commands/auth.ts +0 -92
  51. package/src/commands/balance.ts +0 -28
  52. package/src/commands/config.ts +0 -59
  53. package/src/commands/init.ts +0 -259
  54. package/src/commands/play.ts +0 -196
  55. package/src/commands/spin.ts +0 -17
  56. package/src/commands/sync.ts +0 -49
  57. package/src/commands/test.ts +0 -19
  58. package/src/config.ts +0 -189
  59. package/src/index.ts +0 -132
  60. package/src/patterns.test.ts +0 -44
  61. package/src/patterns.ts +0 -313
  62. package/src/secrets.ts +0 -44
  63. package/src/templates/post-commit.ts +0 -23
  64. package/src/utils/amendDetector.ts +0 -74
  65. package/src/utils/fetch-polyfill.ts +0 -13
  66. package/src/utils/git.ts +0 -88
  67. package/test.txt +0 -2
  68. package/tsconfig.json +0 -21
@@ -1,49 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getBalance as getApiBalance } from '../api.js';
3
- import { getBalance as getLocalBalance } from '../balance.js';
4
-
5
- export async function syncCommand(): Promise<void> {
6
- try {
7
- console.log(chalk.dim('Syncing with API...'));
8
-
9
- const apiBalance = await getApiBalance();
10
-
11
- if (!apiBalance) {
12
- console.log(chalk.yellow('Unable to sync with API.'));
13
- console.log(chalk.dim('Make sure you are authenticated and online.'));
14
- return;
15
- }
16
-
17
- const localBalance = getLocalBalance();
18
-
19
- console.log();
20
- console.log(chalk.bold('Local Balance:'));
21
- console.log(` Balance: ${chalk.green(localBalance)} points`);
22
- console.log();
23
- console.log(chalk.bold('API Balance:'));
24
- console.log(` Balance: ${chalk.green(apiBalance.balance)} points`);
25
- console.log(` Total Commits: ${chalk.cyan(apiBalance.total_commits)}`);
26
- console.log(` Total Winnings: ${chalk.cyan(apiBalance.total_winnings)}`);
27
-
28
- // Show biggest win with pattern and hash
29
- if (apiBalance.biggest_win > 0) {
30
- const winText = `${chalk.cyan(apiBalance.biggest_win)} points`;
31
- const patternText = apiBalance.biggest_win_pattern ? ` (${chalk.yellow(apiBalance.biggest_win_pattern)})` : '';
32
- const hashText = apiBalance.biggest_win_hash ? chalk.dim(` - ${apiBalance.biggest_win_hash}`) : '';
33
- console.log(` Biggest Win: ${winText}${patternText}${hashText}`);
34
- } else {
35
- console.log(` Biggest Win: ${chalk.cyan(apiBalance.biggest_win)}`);
36
- }
37
- console.log();
38
-
39
- if (localBalance !== apiBalance.balance) {
40
- console.log(chalk.yellow('Warning: Local and API balances differ.'));
41
- console.log(chalk.dim('This is normal if you play offline or in multiple repos.'));
42
- } else {
43
- console.log(chalk.green('Balances are in sync!'));
44
- }
45
- } catch (error) {
46
- console.error(chalk.red(`Error: ${(error as Error).message}`));
47
- process.exit(1);
48
- }
49
- }
@@ -1,19 +0,0 @@
1
- import { playCommand } from './play.js';
2
-
3
- interface TestOptions {
4
- small?: boolean;
5
- }
6
-
7
- function generateRandomHash(): string {
8
- const hexChars = '0123456789abcdef';
9
- let hash = '';
10
- for (let i = 0; i < 7; i++) {
11
- hash += hexChars[Math.floor(Math.random() * hexChars.length)];
12
- }
13
- return hash;
14
- }
15
-
16
- export async function testCommand(options: TestOptions): Promise<void> {
17
- const randomHash = generateRandomHash();
18
- await playCommand(randomHash, options);
19
- }
package/src/config.ts DELETED
@@ -1,189 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
- import { execSync } from 'child_process';
5
-
6
- interface Config {
7
- githubUsername?: string;
8
- playAsUsername?: string; // Per-repo override: play as this username instead
9
- apiUrl?: string;
10
- apiToken?: string;
11
- syncEnabled?: boolean;
12
- privateRepo?: boolean;
13
- }
14
-
15
- // Get repo-specific config path
16
- function getRepoConfigPath(): string {
17
- return path.join(process.cwd(), '.git', 'slot-machine-config.json');
18
- }
19
-
20
- // Get global config path
21
- function getGlobalConfigPath(): string {
22
- const homeDir = os.homedir();
23
- const configDir = path.join(homeDir, '.git-slot-machine');
24
-
25
- // Ensure config directory exists
26
- if (!fs.existsSync(configDir)) {
27
- fs.mkdirSync(configDir, { recursive: true });
28
- }
29
-
30
- return path.join(configDir, 'config.json');
31
- }
32
-
33
- // Get merged config (repo-specific overrides global)
34
- export function getConfig(): Config {
35
- const globalConfig = getGlobalConfig();
36
- const repoConfig = getRepoConfig();
37
-
38
- return { ...globalConfig, ...repoConfig };
39
- }
40
-
41
- // Get only repo-specific config
42
- export function getRepoConfig(): Config {
43
- const configPath = getRepoConfigPath();
44
-
45
- if (!fs.existsSync(configPath)) {
46
- return {};
47
- }
48
-
49
- try {
50
- const content = fs.readFileSync(configPath, 'utf-8');
51
- return JSON.parse(content);
52
- } catch {
53
- return {};
54
- }
55
- }
56
-
57
- // Get only global config
58
- export function getGlobalConfig(): Config {
59
- const configPath = getGlobalConfigPath();
60
-
61
- if (!fs.existsSync(configPath)) {
62
- return {};
63
- }
64
-
65
- try {
66
- const content = fs.readFileSync(configPath, 'utf-8');
67
- return JSON.parse(content);
68
- } catch {
69
- return {};
70
- }
71
- }
72
-
73
- // Save repo-specific config
74
- export function saveRepoConfig(config: Config): void {
75
- const configPath = getRepoConfigPath();
76
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
77
- }
78
-
79
- // Save global config
80
- export function saveGlobalConfig(config: Config): void {
81
- const configPath = getGlobalConfigPath();
82
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
83
- }
84
-
85
- export function getGitHubUsername(): string | null {
86
- const config = getConfig();
87
- // Check for per-repo override first, then fall back to global username
88
- return config.playAsUsername || config.githubUsername || null;
89
- }
90
-
91
- export function setGitHubUsername(username: string): void {
92
- const config = getGlobalConfig();
93
- config.githubUsername = username;
94
- saveGlobalConfig(config);
95
- }
96
-
97
- export function getApiUrl(): string {
98
- const config = getConfig();
99
- return config.apiUrl || process.env.GIT_SLOT_MACHINE_API_URL || 'https://gitslotmachine.com/api';
100
- }
101
-
102
- export function setApiUrl(url: string): void {
103
- const config = getGlobalConfig();
104
- config.apiUrl = url;
105
- saveGlobalConfig(config);
106
- }
107
-
108
- export function getApiToken(): string | null {
109
- const config = getConfig();
110
- return config.apiToken || null;
111
- }
112
-
113
- export function setApiToken(token: string): void {
114
- const config = getGlobalConfig();
115
- config.apiToken = token;
116
- saveGlobalConfig(config);
117
- }
118
-
119
- export function clearApiToken(): void {
120
- const config = getGlobalConfig();
121
- delete config.apiToken;
122
- saveGlobalConfig(config);
123
- }
124
-
125
- export function isSyncEnabled(): boolean {
126
- const config = getConfig();
127
- return config.syncEnabled !== false; // Default to true
128
- }
129
-
130
- export function setSyncEnabled(enabled: boolean): void {
131
- const config = getGlobalConfig();
132
- config.syncEnabled = enabled;
133
- saveGlobalConfig(config);
134
- }
135
-
136
- export function isPrivateRepo(): boolean {
137
- const config = getRepoConfig();
138
- return config.privateRepo === true;
139
- }
140
-
141
- export function setPrivateRepo(isPrivate: boolean): void {
142
- const config = getRepoConfig();
143
- config.privateRepo = isPrivate;
144
- saveRepoConfig(config);
145
- }
146
-
147
- export function setPlayAsUsername(username: string): void {
148
- const config = getRepoConfig();
149
- config.playAsUsername = username;
150
- saveRepoConfig(config);
151
- }
152
-
153
- export function getPlayAsUsername(): string | null {
154
- const config = getRepoConfig();
155
- return config.playAsUsername || null;
156
- }
157
-
158
- export function getRepoInfo(): { owner: string; name: string; url: string } | null {
159
- try {
160
- const remoteUrl = execSync('git config --get remote.origin.url', { encoding: 'utf-8' }).trim();
161
-
162
- // Parse GitHub URL (supports both HTTPS and SSH)
163
- const match = remoteUrl.match(/github\.com[:/](.+?)\/(.+?)(\.git)?$/);
164
-
165
- if (match) {
166
- const owner = match[1];
167
- const name = match[2];
168
-
169
- // If privacy mode is enabled, return obfuscated info
170
- if (isPrivateRepo()) {
171
- return {
172
- owner: 'private',
173
- name: 'private',
174
- url: 'private',
175
- };
176
- }
177
-
178
- return {
179
- owner,
180
- name,
181
- url: `https://github.com/${owner}/${name}`,
182
- };
183
- }
184
-
185
- return null;
186
- } catch {
187
- return null;
188
- }
189
- }
package/src/index.ts DELETED
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
- import chalk from 'chalk';
5
- import { playCommand } from './commands/play.js';
6
- import { spinCommand } from './commands/spin.js';
7
- import { initCommand } from './commands/init.js';
8
- import { balanceCommand } from './commands/balance.js';
9
- import { testCommand } from './commands/test.js';
10
- import { authLoginCommand, authLogoutCommand, authStatusCommand } from './commands/auth.js';
11
- import { syncCommand } from './commands/sync.js';
12
- import { configGetCommand, configSetCommand } from './commands/config.js';
13
-
14
- const program = new Command();
15
-
16
- program
17
- .name('git-slot-machine')
18
- .description('Git commit hash slot machine')
19
- .version('2.2.0', '-v, --version', 'Output the current version');
20
-
21
- program
22
- .command('play')
23
- .description('Play the slot machine with a git hash')
24
- .argument('<hash>', '7-character git commit hash')
25
- .option('-s, --small', 'Single line output')
26
- .action(async (hash: string, options: any) => {
27
- await playCommand(hash, options);
28
- });
29
-
30
- program
31
- .command('spin')
32
- .description('Play with the current git commit hash')
33
- .option('-s, --small', 'Single line output')
34
- .action(async (options: any) => {
35
- await spinCommand(options);
36
- });
37
-
38
- program
39
- .command('init')
40
- .description('Install post-commit hook in current repository')
41
- .action(async () => {
42
- await initCommand();
43
- });
44
-
45
- program
46
- .command('balance')
47
- .description('Show current repository balance and stats')
48
- .action(balanceCommand);
49
-
50
- program
51
- .command('test')
52
- .description('Play with a random 7-character hash')
53
- .option('-s, --small', 'Single line output')
54
- .action(async (options: any) => {
55
- await testCommand(options);
56
- });
57
-
58
- // Auth commands (top-level)
59
- program
60
- .command('login')
61
- .description('Login with GitHub username to join the leaderboard')
62
- .argument('<github-username>', 'Your GitHub username')
63
- .action(async (githubUsername: string) => {
64
- await authLoginCommand(githubUsername);
65
- });
66
-
67
- program
68
- .command('logout')
69
- .description('Logout and clear authentication')
70
- .action(async () => {
71
- await authLogoutCommand();
72
- });
73
-
74
- program
75
- .command('status')
76
- .description('Show authentication and sync status')
77
- .action(async () => {
78
- await authStatusCommand();
79
- });
80
-
81
- // Sync commands
82
- program
83
- .command('sync')
84
- .description('Sync balance with API')
85
- .action(async () => {
86
- await syncCommand();
87
- });
88
-
89
- program
90
- .command('sync:enable')
91
- .description('Enable automatic API sync')
92
- .action(async () => {
93
- await configSetCommand('sync-enabled', 'true');
94
- });
95
-
96
- program
97
- .command('sync:disable')
98
- .description('Disable automatic API sync')
99
- .action(async () => {
100
- await configSetCommand('sync-enabled', 'false');
101
- });
102
-
103
- // Username commands
104
- program
105
- .command('username:set')
106
- .description('Set GitHub username')
107
- .argument('<username>', 'Your GitHub username')
108
- .action(async (username: string) => {
109
- const { setGitHubUsername } = await import('./config.js');
110
- setGitHubUsername(username);
111
- console.log(chalk.green(`GitHub username set to: ${username}`));
112
- });
113
-
114
- // Config commands (advanced - hidden from main help)
115
- program
116
- .command('config:get', { hidden: true })
117
- .description('Get configuration value (advanced)')
118
- .argument('<key>', 'Configuration key (api-url, sync-enabled, all)')
119
- .action(async (key: string) => {
120
- await configGetCommand(key);
121
- });
122
-
123
- program
124
- .command('config:set', { hidden: true })
125
- .description('Set configuration value (advanced)')
126
- .argument('<key>', 'Configuration key (api-url, sync-enabled)')
127
- .argument('<value>', 'Configuration value')
128
- .action(async (key: string, value: string) => {
129
- await configSetCommand(key, value);
130
- });
131
-
132
- program.parse();
@@ -1,44 +0,0 @@
1
- import { detectPattern, PatternType } from './patterns.js';
2
-
3
- describe('Pattern Detection', () => {
4
- it('detects all same character', () => {
5
- const result = detectPattern('aaaaaaa');
6
- expect(result.type).toBe(PatternType.ALL_SAME);
7
- expect(result.name).toBe('JACKPOT');
8
- });
9
-
10
- it('detects 4 of a kind', () => {
11
- const result = detectPattern('aaaa123');
12
- expect(result.type).toBe(PatternType.FOUR_OF_KIND);
13
- expect(result.payout).toBeGreaterThan(0);
14
- });
15
-
16
- it('detects fullest house (4-3)', () => {
17
- const result = detectPattern('aaaabbb');
18
- expect(result.type).toBe(PatternType.FULLEST_HOUSE);
19
- });
20
-
21
- it('detects three pair', () => {
22
- const result = detectPattern('aabbcc1');
23
- expect(result.type).toBe(PatternType.THREE_PAIR);
24
- });
25
-
26
- it('detects one pair', () => {
27
- const result = detectPattern('aa12345');
28
- expect(result.type).toBe(PatternType.ONE_PAIR);
29
- });
30
-
31
- it('detects no win', () => {
32
- const result = detectPattern('1234567');
33
- expect(result.type).toBe(PatternType.NO_WIN);
34
- expect(result.payout).toBe(0);
35
- });
36
-
37
- it('validates hash length', () => {
38
- expect(() => detectPattern('abc')).toThrow('Hash must be 7 characters');
39
- });
40
-
41
- it('validates hex characters', () => {
42
- expect(() => detectPattern('gggggg1')).toThrow('Hash must contain only hex characters');
43
- });
44
- });