@vibe-x/agent-better-checkpoint 0.1.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 +124 -0
- package/bin/cli.mjs +380 -0
- package/package.json +34 -0
- package/platform/unix/check_uncommitted.sh +256 -0
- package/platform/unix/checkpoint.sh +124 -0
- package/platform/win/check_uncommitted.ps1 +209 -0
- package/platform/win/checkpoint.ps1 +123 -0
- package/skill/SKILL.md +170 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alien ZHOU
|
|
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,124 @@
|
|
|
1
|
+
# Agent Better Checkpoint
|
|
2
|
+
|
|
3
|
+
**One-line install, zero config.** Turns AI agent edits into transparent, queryable Git commits.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @vibe-x/agent-better-checkpoint
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
That's it. Your AI coding assistant (Cursor, Claude Code) will now auto-commit every meaningful edit with semantic messages and structured metadata — no more opaque checkpoints.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The Problem
|
|
14
|
+
|
|
15
|
+
AI coding assistants create "checkpoints" as you work, but these are black-box snapshots:
|
|
16
|
+
- **Unreadable** — no meaningful commit messages
|
|
17
|
+
- **Unnavigable** — can't browse or diff individual changes
|
|
18
|
+
- **Unqueryable** — no way to filter, search, or trace back
|
|
19
|
+
|
|
20
|
+
## The Solution
|
|
21
|
+
|
|
22
|
+
Agent Better Checkpoint replaces them with real Git commits:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
checkpoint(api): add user registration endpoint
|
|
26
|
+
|
|
27
|
+
Implement POST /api/users with email/password validation.
|
|
28
|
+
Includes bcrypt hashing and duplicate email check.
|
|
29
|
+
|
|
30
|
+
Agent: cursor
|
|
31
|
+
Checkpoint-Type: auto
|
|
32
|
+
User-Prompt: 帮我实现用户注册接口,需要邮...要密码加密
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Each commit follows [Conventional Commits](https://www.conventionalcommits.org/) and carries structured metadata via [Git Trailers](https://git-scm.com/docs/git-interpret-trailers) — queryable with standard Git tools:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git log --grep="^checkpoint(" # all checkpoints
|
|
39
|
+
git log --format="%(trailers:key=Agent,valueonly)" # by agent
|
|
40
|
+
git log --grep="User-Prompt:.*registration" # by prompt keyword
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
Three components, fully automatic after install:
|
|
48
|
+
|
|
49
|
+
| Component | What it does |
|
|
50
|
+
|-----------|-------------|
|
|
51
|
+
| **SKILL.md** | Instructs the AI to commit after each meaningful edit, with proper format |
|
|
52
|
+
| **Commit Script** | Appends Git Trailers (agent, type, user prompt) and runs `git commit` |
|
|
53
|
+
| **Stop Hook** | Safety net — reminds the AI to commit if anything is left uncommitted |
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
User gives task → AI edits code → AI calls checkpoint script → Git commit with trailers
|
|
57
|
+
↗
|
|
58
|
+
Conversation ends → Stop hook checks for uncommitted changes
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
### Prerequisites
|
|
66
|
+
|
|
67
|
+
- Git ≥ 2.0
|
|
68
|
+
- Node.js ≥ 18 (only needed for installation)
|
|
69
|
+
- [Cursor](https://cursor.com) or [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
70
|
+
|
|
71
|
+
### Quick Install
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx @vibe-x/agent-better-checkpoint
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Auto-detects your OS and AI platform. Or specify explicitly:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx @vibe-x/agent-better-checkpoint --platform cursor
|
|
81
|
+
npx @vibe-x/agent-better-checkpoint --platform claude
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Via [skills.sh](https://skills.sh)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx skills add alienzhou/agent-better-checkpoint
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The AI agent will auto-bootstrap the runtime scripts on first use.
|
|
91
|
+
|
|
92
|
+
### What Gets Installed
|
|
93
|
+
|
|
94
|
+
| Location | Content |
|
|
95
|
+
|----------|---------|
|
|
96
|
+
| `~/.agent-better-checkpoint/scripts/` | Commit script (`checkpoint.sh` / `.ps1`) |
|
|
97
|
+
| `~/.agent-better-checkpoint/hooks/stop/` | Stop hook (`check_uncommitted.sh` / `.ps1`) |
|
|
98
|
+
| Platform skill directory | `SKILL.md` — AI agent instructions |
|
|
99
|
+
| Platform hook config | Stop hook registration |
|
|
100
|
+
|
|
101
|
+
### Uninstall
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx @vibe-x/agent-better-checkpoint --uninstall
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Platform Support
|
|
110
|
+
|
|
111
|
+
| Platform | OS | Status |
|
|
112
|
+
|----------|----|--------|
|
|
113
|
+
| Cursor | macOS, Linux, Windows | ✅ |
|
|
114
|
+
| Claude Code | macOS, Linux, Windows | ✅ |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Contributing
|
|
119
|
+
|
|
120
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and publishing instructions.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
[MIT](LICENSE)
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* agent-better-checkpoint 安装器 (Node.js)
|
|
5
|
+
*
|
|
6
|
+
* 通过 npx 一键安装 checkpoint 脚本、stop hook 和 SKILL.md 到用户环境。
|
|
7
|
+
* 按平台(macOS/Linux vs Windows)选择性部署对应脚本。
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx @vibe-x/agent-better-checkpoint
|
|
11
|
+
* npx @vibe-x/agent-better-checkpoint --platform cursor
|
|
12
|
+
* npx @vibe-x/agent-better-checkpoint --uninstall
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, chmodSync, rmSync, statSync } from 'node:fs';
|
|
16
|
+
import { join, dirname, resolve } from 'node:path';
|
|
17
|
+
import { homedir, platform } from 'node:os';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
|
|
20
|
+
// ============================================================
|
|
21
|
+
// 路径常量
|
|
22
|
+
// ============================================================
|
|
23
|
+
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
const __dirname = dirname(__filename);
|
|
26
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
27
|
+
|
|
28
|
+
const INSTALL_BASE = join(homedir(), '.agent-better-checkpoint');
|
|
29
|
+
const SKILL_NAME = 'agent-better-checkpoint';
|
|
30
|
+
|
|
31
|
+
// 包内源文件路径
|
|
32
|
+
const PLATFORM_DIR = join(PKG_ROOT, 'platform');
|
|
33
|
+
const SKILL_SRC = join(PKG_ROOT, 'skill', 'SKILL.md');
|
|
34
|
+
|
|
35
|
+
// ============================================================
|
|
36
|
+
// 参数解析
|
|
37
|
+
// ============================================================
|
|
38
|
+
|
|
39
|
+
function parseArgs(argv) {
|
|
40
|
+
const args = { platform: null, uninstall: false };
|
|
41
|
+
for (let i = 2; i < argv.length; i++) {
|
|
42
|
+
switch (argv[i]) {
|
|
43
|
+
case '--platform':
|
|
44
|
+
args.platform = argv[++i];
|
|
45
|
+
if (!['cursor', 'claude'].includes(args.platform)) {
|
|
46
|
+
console.error(`Error: unsupported platform "${args.platform}". Use "cursor" or "claude".`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case '--uninstall':
|
|
51
|
+
args.uninstall = true;
|
|
52
|
+
break;
|
|
53
|
+
case '--help':
|
|
54
|
+
case '-h':
|
|
55
|
+
printHelp();
|
|
56
|
+
process.exit(0);
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
console.error(`Unknown option: ${argv[i]}`);
|
|
60
|
+
printHelp();
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return args;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function printHelp() {
|
|
68
|
+
console.log(`
|
|
69
|
+
agent-better-checkpoint — Semantic Git Checkpoint Installer
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
npx @vibe-x/agent-better-checkpoint [options]
|
|
73
|
+
|
|
74
|
+
Options:
|
|
75
|
+
--platform <cursor|claude> Target AI platform (auto-detected if omitted)
|
|
76
|
+
--uninstall Remove installed files and hook registrations
|
|
77
|
+
-h, --help Show this help message
|
|
78
|
+
`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ============================================================
|
|
82
|
+
// 平台检测
|
|
83
|
+
// ============================================================
|
|
84
|
+
|
|
85
|
+
function detectAIPlatform() {
|
|
86
|
+
const home = homedir();
|
|
87
|
+
// 优先 Claude(如果两者都存在,用户可以用 --platform 覆盖)
|
|
88
|
+
if (existsSync(join(home, '.claude'))) return 'claude';
|
|
89
|
+
if (existsSync(join(home, '.cursor'))) return 'cursor';
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getOSType() {
|
|
94
|
+
const p = platform();
|
|
95
|
+
if (p === 'win32') return 'win';
|
|
96
|
+
return 'unix'; // darwin, linux, freebsd, etc.
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ============================================================
|
|
100
|
+
// 文件操作辅助
|
|
101
|
+
// ============================================================
|
|
102
|
+
|
|
103
|
+
function ensureDir(dir) {
|
|
104
|
+
if (!existsSync(dir)) {
|
|
105
|
+
mkdirSync(dir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function copyFileSafe(src, dest) {
|
|
110
|
+
ensureDir(dirname(dest));
|
|
111
|
+
copyFileSync(src, dest);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function setExecutable(filepath) {
|
|
115
|
+
try {
|
|
116
|
+
const st = statSync(filepath);
|
|
117
|
+
chmodSync(filepath, st.mode | 0o111);
|
|
118
|
+
} catch {
|
|
119
|
+
// Windows 下 chmod 可能无效,忽略
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function readJsonFile(filepath) {
|
|
124
|
+
try {
|
|
125
|
+
return JSON.parse(readFileSync(filepath, 'utf-8'));
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function writeJsonFile(filepath, data) {
|
|
132
|
+
ensureDir(dirname(filepath));
|
|
133
|
+
writeFileSync(filepath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ============================================================
|
|
137
|
+
// 安装逻辑
|
|
138
|
+
// ============================================================
|
|
139
|
+
|
|
140
|
+
function installScripts(osType) {
|
|
141
|
+
const scriptsDir = join(INSTALL_BASE, 'scripts');
|
|
142
|
+
const hooksDir = join(INSTALL_BASE, 'hooks', 'stop');
|
|
143
|
+
|
|
144
|
+
ensureDir(scriptsDir);
|
|
145
|
+
ensureDir(hooksDir);
|
|
146
|
+
|
|
147
|
+
if (osType === 'unix') {
|
|
148
|
+
const checkpointSrc = join(PLATFORM_DIR, 'unix', 'checkpoint.sh');
|
|
149
|
+
const hookSrc = join(PLATFORM_DIR, 'unix', 'check_uncommitted.sh');
|
|
150
|
+
const checkpointDest = join(scriptsDir, 'checkpoint.sh');
|
|
151
|
+
const hookDest = join(hooksDir, 'check_uncommitted.sh');
|
|
152
|
+
|
|
153
|
+
copyFileSafe(checkpointSrc, checkpointDest);
|
|
154
|
+
copyFileSafe(hookSrc, hookDest);
|
|
155
|
+
setExecutable(checkpointDest);
|
|
156
|
+
setExecutable(hookDest);
|
|
157
|
+
|
|
158
|
+
console.log(` Scripts → ${scriptsDir}/checkpoint.sh`);
|
|
159
|
+
console.log(` Hooks → ${hooksDir}/check_uncommitted.sh`);
|
|
160
|
+
} else {
|
|
161
|
+
const checkpointSrc = join(PLATFORM_DIR, 'win', 'checkpoint.ps1');
|
|
162
|
+
const hookSrc = join(PLATFORM_DIR, 'win', 'check_uncommitted.ps1');
|
|
163
|
+
const checkpointDest = join(scriptsDir, 'checkpoint.ps1');
|
|
164
|
+
const hookDest = join(hooksDir, 'check_uncommitted.ps1');
|
|
165
|
+
|
|
166
|
+
copyFileSafe(checkpointSrc, checkpointDest);
|
|
167
|
+
copyFileSafe(hookSrc, hookDest);
|
|
168
|
+
|
|
169
|
+
console.log(` Scripts → ${scriptsDir}\\checkpoint.ps1`);
|
|
170
|
+
console.log(` Hooks → ${hooksDir}\\check_uncommitted.ps1`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function installSkill(aiPlatform) {
|
|
175
|
+
let skillDir;
|
|
176
|
+
let skillDest;
|
|
177
|
+
|
|
178
|
+
if (aiPlatform === 'cursor') {
|
|
179
|
+
// 检查 skills.sh 安装路径
|
|
180
|
+
const skillsShPath = join(homedir(), '.cursor', 'skills', SKILL_NAME, 'SKILL.md');
|
|
181
|
+
if (existsSync(skillsShPath)) {
|
|
182
|
+
console.log(` Skill → already installed at ${skillsShPath} (skipped)`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
skillDir = join(homedir(), '.cursor', 'skills', SKILL_NAME);
|
|
187
|
+
skillDest = join(skillDir, 'SKILL.md');
|
|
188
|
+
} else if (aiPlatform === 'claude') {
|
|
189
|
+
// Claude Code: 作为 slash command 安装
|
|
190
|
+
const commandsDir = join(homedir(), '.claude', 'commands');
|
|
191
|
+
skillDest = join(commandsDir, `${SKILL_NAME}.md`);
|
|
192
|
+
|
|
193
|
+
if (existsSync(skillDest)) {
|
|
194
|
+
console.log(` Skill → already installed at ${skillDest} (skipped)`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
skillDir = commandsDir;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
copyFileSafe(SKILL_SRC, skillDest);
|
|
202
|
+
console.log(` Skill → ${skillDest}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function registerCursorHook(osType) {
|
|
206
|
+
const hooksPath = join(homedir(), '.cursor', 'hooks.json');
|
|
207
|
+
let config = readJsonFile(hooksPath) || { version: 1, hooks: {} };
|
|
208
|
+
|
|
209
|
+
if (!config.hooks) config.hooks = {};
|
|
210
|
+
if (!config.hooks.stop) config.hooks.stop = [];
|
|
211
|
+
|
|
212
|
+
// 构建 hook 命令
|
|
213
|
+
let hookCmd;
|
|
214
|
+
if (osType === 'unix') {
|
|
215
|
+
hookCmd = `bash ${INSTALL_BASE}/hooks/stop/check_uncommitted.sh`;
|
|
216
|
+
} else {
|
|
217
|
+
hookCmd = `powershell -File "${INSTALL_BASE}\\hooks\\stop\\check_uncommitted.ps1"`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 检查是否已注册
|
|
221
|
+
const alreadyRegistered = config.hooks.stop.some(
|
|
222
|
+
h => typeof h === 'object' && h.command && h.command.includes(SKILL_NAME.replace(/-/g, ''))
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// 用更精确的检测:检查命令中是否包含 agent-better-checkpoint
|
|
226
|
+
const registered = config.hooks.stop.some(
|
|
227
|
+
h => typeof h === 'object' && h.command && h.command.includes('agent-better-checkpoint')
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (!registered) {
|
|
231
|
+
config.hooks.stop.push({ command: hookCmd });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
writeJsonFile(hooksPath, config);
|
|
235
|
+
console.log(` Config → ${hooksPath}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function registerClaudeHook(osType) {
|
|
239
|
+
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
240
|
+
let settings = readJsonFile(settingsPath) || {};
|
|
241
|
+
|
|
242
|
+
if (!settings.hooks) settings.hooks = {};
|
|
243
|
+
if (!settings.hooks.Stop) settings.hooks.Stop = [];
|
|
244
|
+
|
|
245
|
+
let hookCmd;
|
|
246
|
+
if (osType === 'unix') {
|
|
247
|
+
hookCmd = `bash ${INSTALL_BASE}/hooks/stop/check_uncommitted.sh`;
|
|
248
|
+
} else {
|
|
249
|
+
hookCmd = `powershell -File "${INSTALL_BASE}\\hooks\\stop\\check_uncommitted.ps1"`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const registered = settings.hooks.Stop.some(
|
|
253
|
+
h => typeof h === 'object' &&
|
|
254
|
+
JSON.stringify(h).includes('agent-better-checkpoint')
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (!registered) {
|
|
258
|
+
settings.hooks.Stop.push({
|
|
259
|
+
matcher: '',
|
|
260
|
+
hooks: [{ type: 'command', command: hookCmd }]
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
writeJsonFile(settingsPath, settings);
|
|
265
|
+
console.log(` Config → ${settingsPath}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ============================================================
|
|
269
|
+
// 卸载逻辑
|
|
270
|
+
// ============================================================
|
|
271
|
+
|
|
272
|
+
function uninstallScripts() {
|
|
273
|
+
if (existsSync(INSTALL_BASE)) {
|
|
274
|
+
rmSync(INSTALL_BASE, { recursive: true, force: true });
|
|
275
|
+
console.log(` Removed ${INSTALL_BASE}`);
|
|
276
|
+
} else {
|
|
277
|
+
console.log(` ${INSTALL_BASE} not found, nothing to remove`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function uninstallCursorSkill() {
|
|
282
|
+
const skillDir = join(homedir(), '.cursor', 'skills', SKILL_NAME);
|
|
283
|
+
if (existsSync(skillDir)) {
|
|
284
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
285
|
+
console.log(` Removed skill: ${skillDir}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function uninstallClaudeSkill() {
|
|
290
|
+
const cmdFile = join(homedir(), '.claude', 'commands', `${SKILL_NAME}.md`);
|
|
291
|
+
if (existsSync(cmdFile)) {
|
|
292
|
+
rmSync(cmdFile, { force: true });
|
|
293
|
+
console.log(` Removed command: ${cmdFile}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function unregisterCursorHook() {
|
|
298
|
+
const hooksPath = join(homedir(), '.cursor', 'hooks.json');
|
|
299
|
+
if (!existsSync(hooksPath)) return;
|
|
300
|
+
|
|
301
|
+
const config = readJsonFile(hooksPath);
|
|
302
|
+
if (!config || !config.hooks || !config.hooks.stop) return;
|
|
303
|
+
|
|
304
|
+
config.hooks.stop = config.hooks.stop.filter(
|
|
305
|
+
h => !(typeof h === 'object' && h.command && h.command.includes('agent-better-checkpoint'))
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
writeJsonFile(hooksPath, config);
|
|
309
|
+
console.log(` Cleaned config: ${hooksPath}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function unregisterClaudeHook() {
|
|
313
|
+
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
314
|
+
if (!existsSync(settingsPath)) return;
|
|
315
|
+
|
|
316
|
+
const settings = readJsonFile(settingsPath);
|
|
317
|
+
if (!settings || !settings.hooks || !settings.hooks.Stop) return;
|
|
318
|
+
|
|
319
|
+
settings.hooks.Stop = settings.hooks.Stop.filter(
|
|
320
|
+
h => !JSON.stringify(h).includes('agent-better-checkpoint')
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
writeJsonFile(settingsPath, settings);
|
|
324
|
+
console.log(` Cleaned config: ${settingsPath}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ============================================================
|
|
328
|
+
// 主入口
|
|
329
|
+
// ============================================================
|
|
330
|
+
|
|
331
|
+
function main() {
|
|
332
|
+
const args = parseArgs(process.argv);
|
|
333
|
+
const osType = getOSType();
|
|
334
|
+
const aiPlatform = args.platform || detectAIPlatform();
|
|
335
|
+
|
|
336
|
+
if (!aiPlatform) {
|
|
337
|
+
console.error(
|
|
338
|
+
'Error: could not detect AI platform.\n' +
|
|
339
|
+
'Please specify: npx @vibe-x/agent-better-checkpoint --platform cursor|claude'
|
|
340
|
+
);
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (args.uninstall) {
|
|
345
|
+
// 卸载流程
|
|
346
|
+
console.log(`\n[${aiPlatform === 'cursor' ? 'Cursor' : 'Claude Code'}] Uninstalling...`);
|
|
347
|
+
|
|
348
|
+
if (aiPlatform === 'cursor') {
|
|
349
|
+
uninstallCursorSkill();
|
|
350
|
+
unregisterCursorHook();
|
|
351
|
+
} else {
|
|
352
|
+
uninstallClaudeSkill();
|
|
353
|
+
unregisterClaudeHook();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
uninstallScripts();
|
|
357
|
+
console.log(`\n✅ Uninstallation complete!`);
|
|
358
|
+
} else {
|
|
359
|
+
// 安装流程
|
|
360
|
+
console.log(`\n[${aiPlatform === 'cursor' ? 'Cursor' : 'Claude Code'}] Installing... (OS: ${osType})`);
|
|
361
|
+
|
|
362
|
+
installScripts(osType);
|
|
363
|
+
installSkill(aiPlatform);
|
|
364
|
+
|
|
365
|
+
if (aiPlatform === 'cursor') {
|
|
366
|
+
registerCursorHook(osType);
|
|
367
|
+
} else {
|
|
368
|
+
registerClaudeHook(osType);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
console.log(`\n✅ Installation complete!`);
|
|
372
|
+
console.log(`\nInstalled components:`);
|
|
373
|
+
console.log(` 📜 Checkpoint script → ~/.agent-better-checkpoint/scripts/`);
|
|
374
|
+
console.log(` 🔒 Stop hook → ~/.agent-better-checkpoint/hooks/stop/`);
|
|
375
|
+
console.log(` 📖 SKILL.md → ${aiPlatform === 'cursor' ? '~/.cursor/skills/' : '~/.claude/commands/'}${SKILL_NAME}/`);
|
|
376
|
+
console.log(`\nThe AI agent will now auto-commit with semantic messages. Happy coding! 🎉`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibe-x/agent-better-checkpoint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Semantic Git checkpoint commits for AI coding sessions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-better-checkpoint": "./bin/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"platform/",
|
|
12
|
+
"skill/",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"agent",
|
|
18
|
+
"git",
|
|
19
|
+
"checkpoint",
|
|
20
|
+
"cursor",
|
|
21
|
+
"claude",
|
|
22
|
+
"conventional-commits",
|
|
23
|
+
"skills-sh"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "alienzhou",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/alienzhou/agent-better-checkpoint.git"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
}
|
|
34
|
+
}
|