@vibe-x/agent-better-checkpoint 0.1.1 → 0.3.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/README.md +42 -3
- package/bin/cli.mjs +126 -45
- package/package.json +1 -1
- package/platform/config.template.yml +16 -0
- package/platform/unix/check_uncommitted.sh +263 -52
- package/platform/unix/checkpoint.sh +13 -13
- package/platform/win/check_uncommitted.ps1 +278 -57
- package/platform/win/checkpoint.ps1 +13 -13
- package/skill/SKILL.md +23 -13
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Agent Better Checkpoint
|
|
1
|
+
# Agent Better Checkpoint (ABC)
|
|
2
2
|
|
|
3
3
|
**One-line install, zero config.** Turns AI agent edits into transparent, queryable Git commits.
|
|
4
4
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
npx @vibe-x/agent-better-checkpoint
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
+

|
|
10
|
+
|
|
9
11
|
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
12
|
|
|
11
13
|
---
|
|
@@ -40,6 +42,19 @@ git log --format="%(trailers:key=Agent,valueonly)" # by agent
|
|
|
40
42
|
git log --grep="User-Prompt:.*registration" # by prompt keyword
|
|
41
43
|
```
|
|
42
44
|
|
|
45
|
+
### Works with Your Favorite Git Tools
|
|
46
|
+
|
|
47
|
+
Since every checkpoint is a standard Git commit, the entire Git ecosystem is at your disposal — what was once a hidden, platform-specific checkpoint becomes a first-class citizen you can browse, search, diff, and rebase.
|
|
48
|
+
|
|
49
|
+
| Tool | Type | What You Get |
|
|
50
|
+
|------|------|-------------|
|
|
51
|
+
| [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) | VS Code / Cursor Extension | Inline blame, file history, visual commit graph, interactive rebase — see *who* (you or the AI) changed *what* and *when*, right in the editor |
|
|
52
|
+
| [lazygit](https://github.com/jesseduffield/lazygit) | Terminal UI | Fast keyboard-driven staging, diff browsing, cherry-pick, and rebase across checkpoint commits |
|
|
53
|
+
| [tig](https://github.com/jonas/tig) | Terminal UI | Lightweight ncurses Git log viewer, great for quickly scanning checkpoint history |
|
|
54
|
+
| [GitHub / GitLab Web UI](https://github.com) | Web | Browse, compare, and share checkpoint history online after pushing |
|
|
55
|
+
|
|
56
|
+
For example, with **GitLens in Cursor** you can hover any line to see which checkpoint introduced it and the original user prompt, view all checkpoints for a file in a timeline, or search commits by `checkpoint(` prefix and `User-Prompt` trailer content.
|
|
57
|
+
|
|
43
58
|
---
|
|
44
59
|
|
|
45
60
|
## How It Works
|
|
@@ -81,6 +96,28 @@ npx @vibe-x/agent-better-checkpoint --platform cursor
|
|
|
81
96
|
npx @vibe-x/agent-better-checkpoint --platform claude
|
|
82
97
|
```
|
|
83
98
|
|
|
99
|
+
### Project-local Install
|
|
100
|
+
|
|
101
|
+
Install scripts into your project for self-contained setup (commit with repo):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
cd /path/to/your/project
|
|
105
|
+
npx @vibe-x/agent-better-checkpoint --target .
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Or specify a target directory:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx @vibe-x/agent-better-checkpoint --target /path/to/your/project
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Uninstall project-local only:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx @vibe-x/agent-better-checkpoint --uninstall --target .
|
|
118
|
+
npx @vibe-x/agent-better-checkpoint --uninstall --target /path/to/project
|
|
119
|
+
```
|
|
120
|
+
|
|
84
121
|
### Via [skills.sh](https://skills.sh)
|
|
85
122
|
|
|
86
123
|
```bash
|
|
@@ -93,11 +130,13 @@ The AI agent will auto-bootstrap the runtime scripts on first use.
|
|
|
93
130
|
|
|
94
131
|
| Location | Content |
|
|
95
132
|
|----------|---------|
|
|
96
|
-
| `~/.agent-better-checkpoint/scripts/` | Commit script (`checkpoint.sh` / `.ps1`) |
|
|
97
|
-
| `~/.agent-better-checkpoint/hooks/stop/` | Stop hook (`check_uncommitted.sh` / `.ps1`) |
|
|
133
|
+
| `~/.vibe-x/agent-better-checkpoint/scripts/` | Commit script (`checkpoint.sh` / `.ps1`) |
|
|
134
|
+
| `~/.vibe-x/agent-better-checkpoint/hooks/stop/` | Stop hook (`check_uncommitted.sh` / `.ps1`) |
|
|
98
135
|
| Platform skill directory | `SKILL.md` — AI agent instructions |
|
|
99
136
|
| Platform hook config | Stop hook registration |
|
|
100
137
|
|
|
138
|
+
> **Project-local mode**: Projects can also commit `.vibe-x/agent-better-checkpoint/` (config + scripts) for self-contained setup. When present, the global hook delegates to the project-local scripts automatically.
|
|
139
|
+
|
|
101
140
|
### Uninstall
|
|
102
141
|
|
|
103
142
|
```bash
|
package/bin/cli.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* agent-better-checkpoint
|
|
4
|
+
* agent-better-checkpoint installer (Node.js)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* One-click install via npx: checkpoint scripts, stop hook, and SKILL.md to user env.
|
|
7
|
+
* Deploys platform-specific scripts (macOS/Linux vs Windows).
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
10
|
* npx @vibe-x/agent-better-checkpoint
|
|
@@ -18,26 +18,27 @@ import { homedir, platform } from 'node:os';
|
|
|
18
18
|
import { fileURLToPath } from 'node:url';
|
|
19
19
|
|
|
20
20
|
// ============================================================
|
|
21
|
-
//
|
|
21
|
+
// Path constants
|
|
22
22
|
// ============================================================
|
|
23
23
|
|
|
24
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
25
|
const __dirname = dirname(__filename);
|
|
26
26
|
const PKG_ROOT = resolve(__dirname, '..');
|
|
27
27
|
|
|
28
|
-
const INSTALL_BASE = join(homedir(), '.agent-better-checkpoint');
|
|
28
|
+
const INSTALL_BASE = join(homedir(), '.vibe-x', 'agent-better-checkpoint');
|
|
29
29
|
const SKILL_NAME = 'agent-better-checkpoint';
|
|
30
30
|
|
|
31
|
-
//
|
|
31
|
+
// In-package source paths
|
|
32
32
|
const PLATFORM_DIR = join(PKG_ROOT, 'platform');
|
|
33
33
|
const SKILL_SRC = join(PKG_ROOT, 'skill', 'SKILL.md');
|
|
34
|
+
const CONFIG_TEMPLATE = join(PLATFORM_DIR, 'config.template.yml');
|
|
34
35
|
|
|
35
36
|
// ============================================================
|
|
36
|
-
//
|
|
37
|
+
// Argument parsing
|
|
37
38
|
// ============================================================
|
|
38
39
|
|
|
39
40
|
function parseArgs(argv) {
|
|
40
|
-
const args = { platform: null, uninstall: false };
|
|
41
|
+
const args = { platform: null, uninstall: false, target: null };
|
|
41
42
|
for (let i = 2; i < argv.length; i++) {
|
|
42
43
|
switch (argv[i]) {
|
|
43
44
|
case '--platform':
|
|
@@ -47,6 +48,13 @@ function parseArgs(argv) {
|
|
|
47
48
|
process.exit(1);
|
|
48
49
|
}
|
|
49
50
|
break;
|
|
51
|
+
case '--target':
|
|
52
|
+
args.target = argv[++i];
|
|
53
|
+
if (!args.target) {
|
|
54
|
+
console.error('Error: --target requires a path argument');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
50
58
|
case '--uninstall':
|
|
51
59
|
args.uninstall = true;
|
|
52
60
|
break;
|
|
@@ -73,18 +81,19 @@ Usage:
|
|
|
73
81
|
|
|
74
82
|
Options:
|
|
75
83
|
--platform <cursor|claude> Target AI platform (auto-detected if omitted)
|
|
84
|
+
--target <path> Install to specified project directory (. for cwd)
|
|
76
85
|
--uninstall Remove installed files and hook registrations
|
|
77
86
|
-h, --help Show this help message
|
|
78
87
|
`);
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
// ============================================================
|
|
82
|
-
//
|
|
91
|
+
// Platform detection
|
|
83
92
|
// ============================================================
|
|
84
93
|
|
|
85
94
|
function detectAIPlatform() {
|
|
86
95
|
const home = homedir();
|
|
87
|
-
//
|
|
96
|
+
// Prefer Claude (if both exist, user can override with --platform)
|
|
88
97
|
if (existsSync(join(home, '.claude'))) return 'claude';
|
|
89
98
|
if (existsSync(join(home, '.cursor'))) return 'cursor';
|
|
90
99
|
return null;
|
|
@@ -97,7 +106,7 @@ function getOSType() {
|
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
// ============================================================
|
|
100
|
-
//
|
|
109
|
+
// File operation helpers
|
|
101
110
|
// ============================================================
|
|
102
111
|
|
|
103
112
|
function ensureDir(dir) {
|
|
@@ -116,7 +125,7 @@ function setExecutable(filepath) {
|
|
|
116
125
|
const st = statSync(filepath);
|
|
117
126
|
chmodSync(filepath, st.mode | 0o111);
|
|
118
127
|
} catch {
|
|
119
|
-
//
|
|
128
|
+
// chmod may be ineffective on Windows, ignore
|
|
120
129
|
}
|
|
121
130
|
}
|
|
122
131
|
|
|
@@ -134,7 +143,7 @@ function writeJsonFile(filepath, data) {
|
|
|
134
143
|
}
|
|
135
144
|
|
|
136
145
|
// ============================================================
|
|
137
|
-
//
|
|
146
|
+
// Install logic
|
|
138
147
|
// ============================================================
|
|
139
148
|
|
|
140
149
|
function installScripts(osType) {
|
|
@@ -176,7 +185,7 @@ function installSkill(aiPlatform) {
|
|
|
176
185
|
let skillDest;
|
|
177
186
|
|
|
178
187
|
if (aiPlatform === 'cursor') {
|
|
179
|
-
//
|
|
188
|
+
// Check skills.sh install path
|
|
180
189
|
const skillsShPath = join(homedir(), '.cursor', 'skills', SKILL_NAME, 'SKILL.md');
|
|
181
190
|
if (existsSync(skillsShPath)) {
|
|
182
191
|
console.log(` Skill → already installed at ${skillsShPath} (skipped)`);
|
|
@@ -186,7 +195,7 @@ function installSkill(aiPlatform) {
|
|
|
186
195
|
skillDir = join(homedir(), '.cursor', 'skills', SKILL_NAME);
|
|
187
196
|
skillDest = join(skillDir, 'SKILL.md');
|
|
188
197
|
} else if (aiPlatform === 'claude') {
|
|
189
|
-
// Claude Code:
|
|
198
|
+
// Claude Code: install to standard skills directory
|
|
190
199
|
const skillsRootDir = join(homedir(), '.claude', 'skills');
|
|
191
200
|
skillDir = join(skillsRootDir, SKILL_NAME);
|
|
192
201
|
skillDest = join(skillDir, 'SKILL.md');
|
|
@@ -208,7 +217,7 @@ function registerCursorHook(osType) {
|
|
|
208
217
|
if (!config.hooks) config.hooks = {};
|
|
209
218
|
if (!config.hooks.stop) config.hooks.stop = [];
|
|
210
219
|
|
|
211
|
-
//
|
|
220
|
+
// Build hook command
|
|
212
221
|
let hookCmd;
|
|
213
222
|
if (osType === 'unix') {
|
|
214
223
|
hookCmd = `bash ${INSTALL_BASE}/hooks/stop/check_uncommitted.sh`;
|
|
@@ -216,12 +225,12 @@ function registerCursorHook(osType) {
|
|
|
216
225
|
hookCmd = `powershell -File "${INSTALL_BASE}\\hooks\\stop\\check_uncommitted.ps1"`;
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
//
|
|
228
|
+
// Check if already registered
|
|
220
229
|
const alreadyRegistered = config.hooks.stop.some(
|
|
221
230
|
h => typeof h === 'object' && h.command && h.command.includes(SKILL_NAME.replace(/-/g, ''))
|
|
222
231
|
);
|
|
223
232
|
|
|
224
|
-
//
|
|
233
|
+
// More precise check: command includes agent-better-checkpoint
|
|
225
234
|
const registered = config.hooks.stop.some(
|
|
226
235
|
h => typeof h === 'object' && h.command && h.command.includes('agent-better-checkpoint')
|
|
227
236
|
);
|
|
@@ -234,6 +243,37 @@ function registerCursorHook(osType) {
|
|
|
234
243
|
console.log(` Config → ${hooksPath}`);
|
|
235
244
|
}
|
|
236
245
|
|
|
246
|
+
function installProjectLocal(targetDir, osType) {
|
|
247
|
+
const projectBase = join(resolve(targetDir), '.vibe-x', 'agent-better-checkpoint');
|
|
248
|
+
ensureDir(projectBase);
|
|
249
|
+
|
|
250
|
+
if (osType === 'unix') {
|
|
251
|
+
copyFileSafe(join(PLATFORM_DIR, 'unix', 'checkpoint.sh'), join(projectBase, 'checkpoint.sh'));
|
|
252
|
+
copyFileSafe(join(PLATFORM_DIR, 'unix', 'check_uncommitted.sh'), join(projectBase, 'check_uncommitted.sh'));
|
|
253
|
+
setExecutable(join(projectBase, 'checkpoint.sh'));
|
|
254
|
+
setExecutable(join(projectBase, 'check_uncommitted.sh'));
|
|
255
|
+
}
|
|
256
|
+
copyFileSafe(join(PLATFORM_DIR, 'win', 'checkpoint.ps1'), join(projectBase, 'checkpoint.ps1'));
|
|
257
|
+
copyFileSafe(join(PLATFORM_DIR, 'win', 'check_uncommitted.ps1'), join(projectBase, 'check_uncommitted.ps1'));
|
|
258
|
+
|
|
259
|
+
const configDest = join(projectBase, 'config.yml');
|
|
260
|
+
if (!existsSync(configDest) && existsSync(CONFIG_TEMPLATE)) {
|
|
261
|
+
copyFileSafe(CONFIG_TEMPLATE, configDest);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log(` Project → ${projectBase}/`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function uninstallProjectLocal(targetDir) {
|
|
268
|
+
const projectBase = join(resolve(targetDir), '.vibe-x', 'agent-better-checkpoint');
|
|
269
|
+
if (existsSync(projectBase)) {
|
|
270
|
+
rmSync(projectBase, { recursive: true, force: true });
|
|
271
|
+
console.log(` Removed project-local: ${projectBase}`);
|
|
272
|
+
} else {
|
|
273
|
+
console.log(` ${projectBase} not found, nothing to remove`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
237
277
|
function registerClaudeHook(osType) {
|
|
238
278
|
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
239
279
|
let settings = readJsonFile(settingsPath) || {};
|
|
@@ -265,9 +305,15 @@ function registerClaudeHook(osType) {
|
|
|
265
305
|
}
|
|
266
306
|
|
|
267
307
|
// ============================================================
|
|
268
|
-
//
|
|
308
|
+
// Uninstall logic
|
|
269
309
|
// ============================================================
|
|
270
310
|
|
|
311
|
+
function hasInstallation(platform) {
|
|
312
|
+
const home = homedir();
|
|
313
|
+
const skillDir = join(home, platform === 'cursor' ? '.cursor' : '.claude', 'skills', SKILL_NAME);
|
|
314
|
+
return existsSync(skillDir);
|
|
315
|
+
}
|
|
316
|
+
|
|
271
317
|
function uninstallScripts() {
|
|
272
318
|
if (existsSync(INSTALL_BASE)) {
|
|
273
319
|
rmSync(INSTALL_BASE, { recursive: true, force: true });
|
|
@@ -324,15 +370,16 @@ function unregisterClaudeHook() {
|
|
|
324
370
|
}
|
|
325
371
|
|
|
326
372
|
// ============================================================
|
|
327
|
-
//
|
|
373
|
+
// Main entry
|
|
328
374
|
// ============================================================
|
|
329
375
|
|
|
330
376
|
function main() {
|
|
331
377
|
const args = parseArgs(process.argv);
|
|
332
378
|
const osType = getOSType();
|
|
333
379
|
const aiPlatform = args.platform || detectAIPlatform();
|
|
380
|
+
const projectTargetDir = args.target ? resolve(args.target) : null;
|
|
334
381
|
|
|
335
|
-
if (!aiPlatform) {
|
|
382
|
+
if (!aiPlatform && !projectTargetDir && !args.uninstall) {
|
|
336
383
|
console.error(
|
|
337
384
|
'Error: could not detect AI platform.\n' +
|
|
338
385
|
'Please specify: npx @vibe-x/agent-better-checkpoint --platform cursor|claude'
|
|
@@ -341,38 +388,72 @@ function main() {
|
|
|
341
388
|
}
|
|
342
389
|
|
|
343
390
|
if (args.uninstall) {
|
|
344
|
-
|
|
345
|
-
|
|
391
|
+
if (projectTargetDir) {
|
|
392
|
+
console.log('\n[Project-local] Uninstalling...');
|
|
393
|
+
uninstallProjectLocal(projectTargetDir);
|
|
394
|
+
}
|
|
346
395
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
396
|
+
// 指定 --platform 时只清该平台;未指定时清理所有已安装的平台
|
|
397
|
+
const platforms = args.platform
|
|
398
|
+
? [args.platform]
|
|
399
|
+
: ['cursor', 'claude'].filter(p => hasInstallation(p));
|
|
400
|
+
|
|
401
|
+
if (!projectTargetDir || args.platform) {
|
|
402
|
+
for (const p of platforms) {
|
|
403
|
+
console.log(`\n[${p === 'cursor' ? 'Cursor' : 'Claude Code'}] Uninstalling...`);
|
|
404
|
+
if (p === 'cursor') {
|
|
405
|
+
uninstallCursorSkill();
|
|
406
|
+
unregisterCursorHook();
|
|
407
|
+
} else {
|
|
408
|
+
uninstallClaudeSkill();
|
|
409
|
+
unregisterClaudeHook();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (platforms.length > 0) {
|
|
413
|
+
uninstallScripts();
|
|
414
|
+
}
|
|
353
415
|
}
|
|
354
416
|
|
|
355
|
-
|
|
356
|
-
|
|
417
|
+
if (platforms.length === 0 && !projectTargetDir) {
|
|
418
|
+
console.log('\nNo installation found for any platform.');
|
|
419
|
+
}
|
|
420
|
+
console.log('\n✅ Uninstallation complete!');
|
|
357
421
|
} else {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
422
|
+
if (projectTargetDir) {
|
|
423
|
+
if (!aiPlatform) {
|
|
424
|
+
console.error('Error: --target requires AI platform for global hook. Specify --platform cursor|claude');
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
console.log(`\n[${aiPlatform === 'cursor' ? 'Cursor' : 'Claude Code'}] Installing... (OS: ${osType})`);
|
|
428
|
+
installScripts(osType);
|
|
429
|
+
installSkill(aiPlatform);
|
|
430
|
+
if (aiPlatform === 'cursor') {
|
|
431
|
+
registerCursorHook(osType);
|
|
432
|
+
} else {
|
|
433
|
+
registerClaudeHook(osType);
|
|
434
|
+
}
|
|
435
|
+
installProjectLocal(projectTargetDir, osType);
|
|
366
436
|
} else {
|
|
367
|
-
|
|
437
|
+
console.log(`\n[${aiPlatform === 'cursor' ? 'Cursor' : 'Claude Code'}] Installing... (OS: ${osType})`);
|
|
438
|
+
installScripts(osType);
|
|
439
|
+
installSkill(aiPlatform);
|
|
440
|
+
if (aiPlatform === 'cursor') {
|
|
441
|
+
registerCursorHook(osType);
|
|
442
|
+
} else {
|
|
443
|
+
registerClaudeHook(osType);
|
|
444
|
+
}
|
|
368
445
|
}
|
|
369
446
|
|
|
370
|
-
console.log(
|
|
371
|
-
console.log(
|
|
372
|
-
console.log(` 📜 Checkpoint script → ~/.agent-better-checkpoint/scripts/`);
|
|
373
|
-
console.log(` 🔒 Stop hook → ~/.agent-better-checkpoint/hooks/stop/`);
|
|
447
|
+
console.log('\n✅ Installation complete!');
|
|
448
|
+
console.log('\nInstalled components:');
|
|
449
|
+
console.log(` 📜 Checkpoint script → ~/.vibe-x/agent-better-checkpoint/scripts/`);
|
|
450
|
+
console.log(` 🔒 Stop hook → ~/.vibe-x/agent-better-checkpoint/hooks/stop/`);
|
|
374
451
|
console.log(` 📖 SKILL.md → ${aiPlatform === 'cursor' ? '~/.cursor/skills/' : '~/.claude/skills/'}${SKILL_NAME}/`);
|
|
375
|
-
|
|
452
|
+
if (projectTargetDir) {
|
|
453
|
+
const projectBase = join(resolve(projectTargetDir), '.vibe-x', 'agent-better-checkpoint');
|
|
454
|
+
console.log(` 📁 Project-local → ${projectBase}/`);
|
|
455
|
+
}
|
|
456
|
+
console.log('\nThe AI agent will now auto-commit with semantic messages. Happy coding! 🎉');
|
|
376
457
|
}
|
|
377
458
|
}
|
|
378
459
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Checkpoint commit trigger conditions
|
|
2
|
+
#
|
|
3
|
+
# Controls when stop hook (check_uncommitted) triggers commit reminder.
|
|
4
|
+
# Affects only stop hook detection, not checkpoint.sh commit behavior.
|
|
5
|
+
|
|
6
|
+
# Trigger reminder if ANY condition met (OR)
|
|
7
|
+
# Empty/commented = condition disabled
|
|
8
|
+
trigger_if_any:
|
|
9
|
+
# min_changed_files: 3 # At least N active files changed
|
|
10
|
+
min_changed_lines: 5 # At least N lines changed
|
|
11
|
+
|
|
12
|
+
# Passive file patterns — matched files do not trigger reminder alone
|
|
13
|
+
passive_patterns:
|
|
14
|
+
- ".discuss/**"
|
|
15
|
+
- ".vibe-x/**"
|
|
16
|
+
- ".DS_Store"
|