git-cracked 1.2.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.
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/config.example.json +11 -0
- package/package.json +50 -0
- package/scripts/install-linux.js +57 -0
- package/scripts/install-mac.js +63 -0
- package/scripts/install-windows.js +38 -0
- package/src/ai.js +3 -0
- package/src/cli.js +37 -0
- package/src/committer.js +37 -0
- package/src/config.js +36 -0
- package/src/dashboard.js +485 -0
- package/src/index.js +64 -0
- package/src/logger.js +29 -0
- package/src/messages.js +197 -0
- package/src/mutator.js +373 -0
- package/src/paths.js +24 -0
- package/src/setup.js +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Trenton Scott
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# git-cracked
|
|
2
|
+
|
|
3
|
+
Keep your GitHub contribution graph green automatically. Commits realistic-looking code changes to a private repo on a schedule — completely free, no API key needed.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
### You need
|
|
10
|
+
|
|
11
|
+
- [Node.js v18+](https://nodejs.org)
|
|
12
|
+
- A GitHub account
|
|
13
|
+
- A private repo cloned to your machine (with some source code files in it)
|
|
14
|
+
|
|
15
|
+
### One command
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx git-cracked
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Your browser opens automatically. If this is your first time, you'll see a setup page — fill in the path to your private repo and click save. That's it.
|
|
22
|
+
|
|
23
|
+
### Or install from source
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/trentzx/git-cracked.git
|
|
27
|
+
cd git-cracked
|
|
28
|
+
npm install
|
|
29
|
+
npm start
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Auto-start on boot *(so it keeps running after restarts)*
|
|
33
|
+
|
|
34
|
+
From a source install:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Windows
|
|
38
|
+
npm run install-windows
|
|
39
|
+
|
|
40
|
+
# macOS
|
|
41
|
+
npm run install-mac
|
|
42
|
+
|
|
43
|
+
# Linux
|
|
44
|
+
npm run install-linux
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Dashboard
|
|
50
|
+
|
|
51
|
+
Once running, open **[http://localhost:4856](http://localhost:4856)** to see:
|
|
52
|
+
|
|
53
|
+
- Total commits (all time + today)
|
|
54
|
+
- Next scheduled commit times with countdown
|
|
55
|
+
- Full commit history — message, file changed, how long ago
|
|
56
|
+
- **Commit Now** button to test instantly
|
|
57
|
+
- Settings page to change your repo, schedule, or branch
|
|
58
|
+
|
|
59
|
+
The dashboard auto-refreshes every 30 seconds.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Changing the schedule
|
|
64
|
+
|
|
65
|
+
Go to [http://localhost:4856/settings](http://localhost:4856/settings) and pick from the dropdown:
|
|
66
|
+
|
|
67
|
+
| Option | Times |
|
|
68
|
+
|---|---|
|
|
69
|
+
| 3× per weekday *(default)* | 9am, 1pm, 4pm |
|
|
70
|
+
| 2× per weekday | 9am, 3pm |
|
|
71
|
+
| 4× per weekday | 9am, 12pm, 3pm, 6pm |
|
|
72
|
+
| 1× per weekday | 10am |
|
|
73
|
+
|
|
74
|
+
All times use your computer's local time zone, so it works the same anywhere in the world.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## How it works
|
|
79
|
+
|
|
80
|
+
1. At each scheduled time, a random source file in your repo is selected
|
|
81
|
+
2. A small, realistic change is applied — fixing whitespace, normalising quotes, adjusting a constant, sorting imports, etc.
|
|
82
|
+
3. A commit message is picked from a bank of 130+ realistic conventional commit messages that match the change type
|
|
83
|
+
4. The commit is pushed to your private repo automatically
|
|
84
|
+
|
|
85
|
+
**Supported file types:** `.js` `.ts` `.jsx` `.tsx` `.mjs` `.py` `.go` `.java` `.rb` `.cs` `.cpp` `.c` `.rs` `.php` `.swift` `.kt` `.scala` `.sh`
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Stopping / removing
|
|
90
|
+
|
|
91
|
+
**Kill the process** — just close the terminal, or stop the background service:
|
|
92
|
+
|
|
93
|
+
**Windows** — delete the startup file:
|
|
94
|
+
```
|
|
95
|
+
del "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\git-cracked.vbs"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**macOS:**
|
|
99
|
+
```bash
|
|
100
|
+
launchctl unload ~/Library/LaunchAgents/com.gitcracked.autocommit.plist
|
|
101
|
+
rm ~/Library/LaunchAgents/com.gitcracked.autocommit.plist
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Linux:**
|
|
105
|
+
```bash
|
|
106
|
+
systemctl --user disable --now git-cracked
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Troubleshooting
|
|
112
|
+
|
|
113
|
+
**"No suitable files found to mutate"**
|
|
114
|
+
Your private repo needs real source code files (`.js`, `.py`, `.ts`, etc.) that are at least 5 lines long and not minified.
|
|
115
|
+
|
|
116
|
+
**Commits don't show on my GitHub graph**
|
|
117
|
+
Make sure `git config user.email` in your private repo matches your GitHub account email:
|
|
118
|
+
```bash
|
|
119
|
+
cd path/to/your/private/repo
|
|
120
|
+
git config user.email "you@example.com"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Push fails**
|
|
124
|
+
You need GitHub credentials set up for HTTPS. Run `gh auth login` if you have the GitHub CLI, or set up SSH keys.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Security
|
|
129
|
+
|
|
130
|
+
- Your settings live in `~/.git-cracked/` on your machine and are never committed or uploaded
|
|
131
|
+
- No data is sent anywhere — commit messages are generated locally
|
|
132
|
+
- The tool only touches files inside the repo path you configure
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Project structure
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
git-cracked/
|
|
140
|
+
├── src/
|
|
141
|
+
│ ├── cli.js Entry point — starts app and opens browser
|
|
142
|
+
│ ├── index.js Scheduler
|
|
143
|
+
│ ├── dashboard.js Web dashboard + setup wizard (port 4856)
|
|
144
|
+
│ ├── committer.js Runs mutate → commit → push
|
|
145
|
+
│ ├── mutator.js Applies realistic code changes
|
|
146
|
+
│ ├── messages.js 130+ commit message bank
|
|
147
|
+
│ ├── logger.js Saves activity to activity.json
|
|
148
|
+
│ ├── config.js Loads and validates config.json
|
|
149
|
+
│ └── setup.js CLI setup wizard (alternative to web UI)
|
|
150
|
+
├── scripts/
|
|
151
|
+
│ ├── install-windows.js
|
|
152
|
+
│ ├── install-mac.js
|
|
153
|
+
│ └── install-linux.js
|
|
154
|
+
├── config.example.json
|
|
155
|
+
└── package.json
|
|
156
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "git-cracked",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Auto-commits realistic-looking code changes to keep your GitHub green — free, no API key required",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"git-cracked": "src/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/",
|
|
12
|
+
"scripts/",
|
|
13
|
+
"config.example.json",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "node src/cli.js",
|
|
19
|
+
"commit-now": "node src/index.js --now",
|
|
20
|
+
"setup": "node src/setup.js",
|
|
21
|
+
"install-windows": "node scripts/install-windows.js",
|
|
22
|
+
"install-mac": "node scripts/install-mac.js",
|
|
23
|
+
"install-linux": "node scripts/install-linux.js"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/trentzx/git-cracked.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/trentzx/git-cracked#readme",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/trentzx/git-cracked/issues"
|
|
32
|
+
},
|
|
33
|
+
"author": "Trenton Scott",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"node-cron": "^3.0.3",
|
|
36
|
+
"simple-git": "^3.27.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"github",
|
|
43
|
+
"contributions",
|
|
44
|
+
"commits",
|
|
45
|
+
"automation",
|
|
46
|
+
"contribution-graph",
|
|
47
|
+
"scheduler"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT"
|
|
50
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs git-cracked as a systemd user service on Linux.
|
|
3
|
+
* Run once with: node scripts/install-linux.js
|
|
4
|
+
* No sudo required — installs as a user service.
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname, join, resolve } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const projectRoot = resolve(__dirname, '..');
|
|
15
|
+
const entryPoint = join(projectRoot, 'src', 'index.js');
|
|
16
|
+
const nodePath = process.execPath;
|
|
17
|
+
const serviceDir = join(homedir(), '.config', 'systemd', 'user');
|
|
18
|
+
const servicePath = join(serviceDir, 'git-cracked.service');
|
|
19
|
+
|
|
20
|
+
if (!existsSync(join(projectRoot, 'config.json'))) {
|
|
21
|
+
console.error('config.json not found. Run "npm run setup" first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const unit = `[Unit]
|
|
26
|
+
Description=Git Cracked - automatic GitHub commit scheduler
|
|
27
|
+
After=network.target
|
|
28
|
+
|
|
29
|
+
[Service]
|
|
30
|
+
Type=simple
|
|
31
|
+
ExecStart=${nodePath} ${entryPoint}
|
|
32
|
+
WorkingDirectory=${projectRoot}
|
|
33
|
+
Restart=on-failure
|
|
34
|
+
RestartSec=30
|
|
35
|
+
StandardOutput=append:${projectRoot}/git-cracked.log
|
|
36
|
+
StandardError=append:${projectRoot}/git-cracked.log
|
|
37
|
+
|
|
38
|
+
[Install]
|
|
39
|
+
WantedBy=default.target
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
mkdirSync(serviceDir, { recursive: true });
|
|
43
|
+
writeFileSync(servicePath, unit);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
execSync('systemctl --user daemon-reload');
|
|
47
|
+
execSync('systemctl --user enable git-cracked.service');
|
|
48
|
+
execSync('systemctl --user start git-cracked.service');
|
|
49
|
+
console.log('systemd user service installed and started.');
|
|
50
|
+
console.log('Status: systemctl --user status git-cracked');
|
|
51
|
+
console.log(`Logs: ${projectRoot}/git-cracked.log`);
|
|
52
|
+
console.log('Remove: systemctl --user disable --now git-cracked');
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error('Failed to install service:', err.message);
|
|
55
|
+
console.error('Make sure systemd user services are supported on your distro.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs git-cracked as a macOS launchd agent.
|
|
3
|
+
* Run once with: node scripts/install-mac.js
|
|
4
|
+
* No sudo required — installs for the current user only.
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname, join, resolve } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const projectRoot = resolve(__dirname, '..');
|
|
15
|
+
const entryPoint = join(projectRoot, 'src', 'index.js');
|
|
16
|
+
const nodePath = process.execPath;
|
|
17
|
+
const label = 'com.gitcracked.autocommit';
|
|
18
|
+
const launchAgentsDir = join(homedir(), 'Library', 'LaunchAgents');
|
|
19
|
+
const plistPath = join(launchAgentsDir, `${label}.plist`);
|
|
20
|
+
|
|
21
|
+
if (!existsSync(join(projectRoot, 'config.json'))) {
|
|
22
|
+
console.error('config.json not found. Run "npm run setup" first.');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
27
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
28
|
+
<plist version="1.0">
|
|
29
|
+
<dict>
|
|
30
|
+
<key>Label</key>
|
|
31
|
+
<string>${label}</string>
|
|
32
|
+
<key>ProgramArguments</key>
|
|
33
|
+
<array>
|
|
34
|
+
<string>${nodePath}</string>
|
|
35
|
+
<string>${entryPoint}</string>
|
|
36
|
+
</array>
|
|
37
|
+
<key>RunAtLoad</key>
|
|
38
|
+
<true/>
|
|
39
|
+
<key>KeepAlive</key>
|
|
40
|
+
<true/>
|
|
41
|
+
<key>StandardOutPath</key>
|
|
42
|
+
<string>${projectRoot}/git-cracked.log</string>
|
|
43
|
+
<key>StandardErrorPath</key>
|
|
44
|
+
<string>${projectRoot}/git-cracked.log</string>
|
|
45
|
+
<key>WorkingDirectory</key>
|
|
46
|
+
<string>${projectRoot}</string>
|
|
47
|
+
</dict>
|
|
48
|
+
</plist>`;
|
|
49
|
+
|
|
50
|
+
mkdirSync(launchAgentsDir, { recursive: true });
|
|
51
|
+
writeFileSync(plistPath, plist);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Unload existing agent if running
|
|
55
|
+
execSync(`launchctl unload "${plistPath}" 2>/dev/null || true`);
|
|
56
|
+
execSync(`launchctl load "${plistPath}"`);
|
|
57
|
+
console.log('LaunchAgent installed and started.');
|
|
58
|
+
console.log(`Logs: ${projectRoot}/git-cracked.log`);
|
|
59
|
+
console.log(`To remove: launchctl unload "${plistPath}" && rm "${plistPath}"`);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error('Failed to load agent:', err.message);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs git-cracked to the Windows Startup folder.
|
|
3
|
+
* Runs automatically on login. No admin rights required.
|
|
4
|
+
* Run with: node scripts/install-windows.js
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { writeFileSync } from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname, join, resolve } from 'path';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const projectRoot = resolve(__dirname, '..');
|
|
15
|
+
const entryPoint = join(projectRoot, 'src', 'cli.js');
|
|
16
|
+
const nodePath = process.execPath;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
// Windows Startup folder — runs for current user, no admin needed
|
|
20
|
+
const startupDir = join(
|
|
21
|
+
homedir(),
|
|
22
|
+
'AppData', 'Roaming', 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup'
|
|
23
|
+
);
|
|
24
|
+
const vbsPath = join(startupDir, 'git-cracked.vbs');
|
|
25
|
+
const logPath = join(projectRoot, 'git-cracked.log');
|
|
26
|
+
|
|
27
|
+
// VBScript launches Node hidden (no console window flashing on login)
|
|
28
|
+
const vbs = `Set WshShell = CreateObject("WScript.Shell")
|
|
29
|
+
WshShell.Run """${nodePath}"" ""${entryPoint}""", 0, False`;
|
|
30
|
+
|
|
31
|
+
writeFileSync(vbsPath, vbs);
|
|
32
|
+
|
|
33
|
+
console.log('git-cracked installed to Startup folder.');
|
|
34
|
+
console.log(`Startup script: ${vbsPath}`);
|
|
35
|
+
console.log(`Logs: ${logPath}`);
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log('It will start automatically on next login.');
|
|
38
|
+
console.log(`To remove: del "${vbsPath}"`);
|
package/src/ai.js
ADDED
package/src/cli.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { CONFIG_PATH } from './paths.js';
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const hasConfig = existsSync(CONFIG_PATH);
|
|
10
|
+
const PORT = 4856;
|
|
11
|
+
|
|
12
|
+
// Start the main process
|
|
13
|
+
const child = spawn(process.execPath, [join(__dirname, 'index.js')], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
env: process.env,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
19
|
+
|
|
20
|
+
// Open browser after a short delay to let the server start
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
const url = `http://localhost:${PORT}${hasConfig ? '' : '/setup'}`;
|
|
23
|
+
openBrowser(url);
|
|
24
|
+
}, 1200);
|
|
25
|
+
|
|
26
|
+
function openBrowser(url) {
|
|
27
|
+
const platform = process.platform;
|
|
28
|
+
const cmd =
|
|
29
|
+
platform === 'win32' ? ['cmd', ['/c', 'start', url]] :
|
|
30
|
+
platform === 'darwin' ? ['open', [url]] :
|
|
31
|
+
['xdg-open', [url]];
|
|
32
|
+
try {
|
|
33
|
+
spawn(cmd[0], cmd[1], { stdio: 'ignore', detached: true }).unref();
|
|
34
|
+
} catch {
|
|
35
|
+
console.log(`Open your browser to: ${url}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/committer.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import simpleGit from 'simple-git';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { mutateRepo } from './mutator.js';
|
|
4
|
+
import { generateCommitMessage } from './ai.js';
|
|
5
|
+
import { logCommit } from './logger.js';
|
|
6
|
+
|
|
7
|
+
export async function runCommit(config) {
|
|
8
|
+
if (!existsSync(config.repoPath)) {
|
|
9
|
+
throw new Error(`Repo path does not exist: ${config.repoPath}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const git = simpleGit(config.repoPath);
|
|
13
|
+
|
|
14
|
+
const isRepo = await git.checkIsRepo().catch(() => false);
|
|
15
|
+
if (!isRepo) {
|
|
16
|
+
throw new Error(`Not a git repository: ${config.repoPath}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { changedFiles, description, relPath } = await mutateRepo(config.repoPath);
|
|
20
|
+
|
|
21
|
+
if (changedFiles.length === 0) {
|
|
22
|
+
console.log('No suitable files found to mutate — skipping commit.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const message = generateCommitMessage(description);
|
|
27
|
+
|
|
28
|
+
await git.add(changedFiles);
|
|
29
|
+
await git.commit(message);
|
|
30
|
+
|
|
31
|
+
if (config.pushAfterCommit) {
|
|
32
|
+
await git.push(config.remoteName, config.branch);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
logCommit({ message, file: relPath, repoPath: config.repoPath });
|
|
36
|
+
console.log(`Committed: ${message}`);
|
|
37
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { CONFIG_PATH } from './paths.js';
|
|
3
|
+
|
|
4
|
+
export function loadConfig() {
|
|
5
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
6
|
+
console.error('ERROR: No configuration found. Run "npm start" and complete setup in the browser.');
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let raw;
|
|
11
|
+
try {
|
|
12
|
+
raw = JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));
|
|
13
|
+
} catch {
|
|
14
|
+
console.error(`ERROR: ${CONFIG_PATH} is not valid JSON. Delete it and run setup again.`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const errors = [];
|
|
19
|
+
if (!raw.repoPath) errors.push('repoPath is required');
|
|
20
|
+
if (!Array.isArray(raw.schedule) || raw.schedule.length === 0) {
|
|
21
|
+
errors.push('schedule must be a non-empty array');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (errors.length) {
|
|
25
|
+
console.error('ERROR: Invalid config:\n' + errors.map(e => ' - ' + e).join('\n'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
repoPath: raw.repoPath,
|
|
31
|
+
branch: raw.branch ?? 'main',
|
|
32
|
+
remoteName: raw.remoteName ?? 'origin',
|
|
33
|
+
pushAfterCommit: raw.pushAfterCommit !== false,
|
|
34
|
+
schedule: raw.schedule,
|
|
35
|
+
};
|
|
36
|
+
}
|