gent-cli 6.0.1 → 7.0.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/QUICKSTART.md +116 -85
- package/README.md +60 -3
- package/package.json +5 -3
- package/src/commands/branch.js +3 -0
- package/src/commands/checkout.js +5 -0
- package/src/commands/commit.js +65 -2
- package/src/commands/explain.js +145 -0
- package/src/commands/log.js +51 -1
- package/src/commands/merge.js +4 -0
- package/src/commands/reset.js +10 -0
- package/src/commands/resolve.js +280 -0
- package/src/commands/summary.js +176 -0
- package/src/commands/undo.js +115 -0
- package/src/index.js +39 -3
- package/src/utils/ai-service.js +156 -0
- package/src/utils/diff-engine.js +68 -2
- package/src/utils/journal.js +215 -0
- package/src/utils/merge-engine.js +340 -140
package/QUICKSTART.md
CHANGED
|
@@ -1,198 +1,229 @@
|
|
|
1
|
-
# Quick Start Guide
|
|
1
|
+
# Gent CLI — Quick Start Guide
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Requirements
|
|
4
|
+
|
|
5
|
+
- Node.js **18 or newer**
|
|
6
|
+
- npm
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
4
9
|
|
|
5
10
|
```bash
|
|
6
|
-
# Navigate to the CLI directory
|
|
7
11
|
cd apps/Cli
|
|
8
|
-
|
|
9
|
-
# Install dependencies
|
|
10
12
|
npm install
|
|
11
|
-
|
|
12
|
-
# Test the CLI
|
|
13
13
|
node src/index.js --help
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Make `gent` available globally:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
# Link the CLI globally
|
|
20
19
|
npm link
|
|
21
|
-
|
|
22
|
-
# Now you can use 'gent' from anywhere
|
|
23
20
|
gent --help
|
|
24
21
|
```
|
|
25
22
|
|
|
23
|
+
---
|
|
24
|
+
|
|
26
25
|
## Your First Repository
|
|
27
26
|
|
|
28
27
|
### 1. Initialize
|
|
28
|
+
|
|
29
29
|
```bash
|
|
30
|
-
# Create a new directory
|
|
31
30
|
mkdir my-project
|
|
32
31
|
cd my-project
|
|
33
|
-
|
|
34
|
-
# Initialize gent repository
|
|
35
32
|
gent init
|
|
36
33
|
```
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
- Your name
|
|
40
|
-
- Your email
|
|
41
|
-
- Repository name
|
|
42
|
-
- Repository description
|
|
35
|
+
Skip the interactive prompts:
|
|
43
36
|
|
|
44
|
-
Or skip prompts with `-y`:
|
|
45
37
|
```bash
|
|
46
38
|
gent init -y
|
|
47
39
|
```
|
|
48
40
|
|
|
49
41
|
### 2. Add Files
|
|
42
|
+
|
|
50
43
|
```bash
|
|
51
|
-
# Create some files
|
|
52
44
|
echo "console.log('Hello');" > index.js
|
|
53
|
-
|
|
54
|
-
# Add to staging area
|
|
55
45
|
gent add index.js
|
|
56
|
-
|
|
57
|
-
# Or add all files
|
|
46
|
+
# or add everything
|
|
58
47
|
gent add .
|
|
59
48
|
```
|
|
60
49
|
|
|
61
50
|
### 3. Check Status
|
|
51
|
+
|
|
62
52
|
```bash
|
|
63
53
|
gent status
|
|
54
|
+
gent status -s # short format
|
|
64
55
|
```
|
|
65
56
|
|
|
66
|
-
### 4. Commit
|
|
57
|
+
### 4. Commit
|
|
58
|
+
|
|
67
59
|
```bash
|
|
68
|
-
# With message flag
|
|
69
60
|
gent commit -m "Initial commit"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Let AI suggest a message from your staged diff (requires `ANTHROPIC_API_KEY`):
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
gent commit
|
|
65
|
+
```bash
|
|
66
|
+
gent commit --ai
|
|
73
67
|
```
|
|
74
68
|
|
|
75
69
|
### 5. View History
|
|
70
|
+
|
|
76
71
|
```bash
|
|
77
|
-
# See all commits
|
|
78
72
|
gent log
|
|
79
|
-
|
|
80
|
-
# Compact view
|
|
81
73
|
gent log --oneline
|
|
82
|
-
|
|
83
|
-
# Limit commits shown
|
|
84
74
|
gent log -n 5
|
|
75
|
+
gent log --graph # ASCII commit graph with branches and merges
|
|
85
76
|
```
|
|
86
77
|
|
|
78
|
+
---
|
|
79
|
+
|
|
87
80
|
## Working with Branches
|
|
88
81
|
|
|
89
|
-
### Create a Branch
|
|
90
82
|
```bash
|
|
91
|
-
gent branch feature-name
|
|
83
|
+
gent branch feature-name # create
|
|
84
|
+
gent checkout feature-name # switch
|
|
85
|
+
gent checkout -b new-feature # create and switch
|
|
86
|
+
gent branch # list all
|
|
87
|
+
gent branch -d old-feature # delete (undoable)
|
|
92
88
|
```
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Merging
|
|
98
93
|
|
|
99
|
-
### Create and Switch
|
|
100
94
|
```bash
|
|
101
|
-
gent checkout
|
|
95
|
+
gent checkout main
|
|
96
|
+
gent merge feature-login
|
|
102
97
|
```
|
|
103
98
|
|
|
104
|
-
|
|
99
|
+
If the merge is clean it commits automatically. If there are conflicts:
|
|
100
|
+
|
|
105
101
|
```bash
|
|
106
|
-
gent
|
|
102
|
+
gent resolve # walk each conflict hunk interactively → Ours / Theirs / Both / Edit / Ask AI
|
|
103
|
+
gent push
|
|
107
104
|
```
|
|
108
105
|
|
|
109
|
-
|
|
106
|
+
Or resolve markers by hand then:
|
|
107
|
+
|
|
110
108
|
```bash
|
|
111
|
-
gent
|
|
109
|
+
gent add .
|
|
110
|
+
gent commit -m "Resolve merge"
|
|
112
111
|
```
|
|
113
112
|
|
|
113
|
+
---
|
|
114
|
+
|
|
114
115
|
## Common Workflows
|
|
115
116
|
|
|
116
|
-
### Feature
|
|
117
|
+
### Feature development
|
|
118
|
+
|
|
117
119
|
```bash
|
|
118
|
-
# Start a new feature
|
|
119
120
|
gent checkout -b feature-login
|
|
120
121
|
|
|
121
|
-
# Make changes
|
|
122
122
|
echo "// Login code" > login.js
|
|
123
123
|
gent add login.js
|
|
124
124
|
gent commit -m "Add login feature"
|
|
125
125
|
|
|
126
|
-
# View your work
|
|
127
|
-
gent log
|
|
128
|
-
|
|
129
|
-
# Switch back to main
|
|
130
126
|
gent checkout main
|
|
127
|
+
gent merge feature-login
|
|
128
|
+
gent log --graph
|
|
131
129
|
```
|
|
132
130
|
|
|
133
|
-
###
|
|
131
|
+
### Made a mistake? Undo it.
|
|
132
|
+
|
|
134
133
|
```bash
|
|
135
|
-
#
|
|
136
|
-
gent
|
|
137
|
-
gent
|
|
134
|
+
gent undo # reverse the last commit / merge / reset / checkout
|
|
135
|
+
gent undo --list # see what can be undone
|
|
136
|
+
gent redo # re-apply the last undone operation
|
|
138
137
|
```
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
Undo never deletes your working files. For hard-reset / fast-forward merges it
|
|
140
|
+
also restores file content from the object store.
|
|
141
|
+
|
|
142
|
+
### Understand what changed
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
gent
|
|
144
|
+
```bash
|
|
145
|
+
gent explain # explain the latest commit in plain language
|
|
146
|
+
gent explain <commit_hash> # explain a specific commit
|
|
147
|
+
gent explain --staged # explain what is currently staged
|
|
147
148
|
```
|
|
148
149
|
|
|
149
|
-
|
|
150
|
+
### Repository health
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
gent summary # branch counts, contributors, most-changed files, store size
|
|
154
|
+
gent summary --ai # + a short AI-written health narrative
|
|
155
|
+
```
|
|
150
156
|
|
|
151
|
-
|
|
152
|
-
2. **Commit Often** - Small commits are easier to track
|
|
153
|
-
3. **Descriptive Messages** - Write clear commit messages
|
|
154
|
-
4. **Branch for Features** - Keep main branch stable
|
|
155
|
-
5. **Check Status** - Always review before committing
|
|
157
|
+
---
|
|
156
158
|
|
|
157
|
-
##
|
|
159
|
+
## Optional AI Features
|
|
158
160
|
|
|
159
|
-
|
|
161
|
+
All AI features are off by default and have a non-AI fallback.
|
|
160
162
|
|
|
161
163
|
```bash
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
165
|
+
export GENT_AI_MODEL=claude-haiku-4-5 # optional; default is claude-opus-4-8
|
|
166
|
+
|
|
167
|
+
gent commit --ai # AI-suggested commit message
|
|
168
|
+
gent explain # plain-language diff summary
|
|
169
|
+
gent resolve # adds "Ask AI" option per conflict hunk
|
|
170
|
+
gent summary --ai # health narrative
|
|
164
171
|
```
|
|
165
172
|
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Tips & Tricks
|
|
176
|
+
|
|
177
|
+
1. **Undo freely** — `gent undo` reverses history-changing commands without deleting files.
|
|
178
|
+
2. **Use `gent resolve` for conflicts** — faster than editing conflict markers by hand.
|
|
179
|
+
3. **Run `gent summary`** after a sprint to see who changed what and how big the repo has grown.
|
|
180
|
+
4. **`gent log --graph`** gives you a visual picture of your branch and merge history.
|
|
181
|
+
5. **Commit often** — small commits are easier to track and undo individually.
|
|
182
|
+
6. **Use `.gentignore`** — exclude `node_modules/`, `.env`, build artifacts.
|
|
183
|
+
7. **Descriptive messages** — `gent commit --ai` can help when you are stuck.
|
|
184
|
+
8. **Branch for features** — keep `main` stable.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
166
188
|
## Troubleshooting
|
|
167
189
|
|
|
168
|
-
**Not a gent repository
|
|
190
|
+
**Not a gent repository?**
|
|
169
191
|
```bash
|
|
170
|
-
# Make sure you initialized
|
|
171
192
|
gent init
|
|
172
193
|
```
|
|
173
194
|
|
|
174
|
-
**
|
|
195
|
+
**Nothing to commit?**
|
|
175
196
|
```bash
|
|
176
|
-
# Add files first
|
|
177
197
|
gent add <files>
|
|
198
|
+
gent status
|
|
178
199
|
```
|
|
179
200
|
|
|
180
201
|
**Command not found?**
|
|
181
202
|
```bash
|
|
182
|
-
#
|
|
203
|
+
# Run without linking
|
|
183
204
|
node src/index.js <command>
|
|
184
|
-
|
|
185
205
|
# Or link globally
|
|
186
206
|
npm link
|
|
187
207
|
```
|
|
188
208
|
|
|
189
|
-
|
|
209
|
+
**Merge left conflict markers?**
|
|
210
|
+
```bash
|
|
211
|
+
gent resolve # interactive resolver
|
|
212
|
+
# or edit files, then:
|
|
213
|
+
gent add .
|
|
214
|
+
gent commit -m "Resolve conflicts"
|
|
215
|
+
```
|
|
190
216
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
217
|
+
**Undo went too far?**
|
|
218
|
+
```bash
|
|
219
|
+
gent redo
|
|
220
|
+
```
|
|
195
221
|
|
|
196
222
|
---
|
|
197
223
|
|
|
198
|
-
|
|
224
|
+
## Next Steps
|
|
225
|
+
|
|
226
|
+
- Full command reference: [docs/COMMANDS.md](docs/COMMANDS.md)
|
|
227
|
+
- How the algorithms work: [docs/ALGORITHMS.md](docs/ALGORITHMS.md)
|
|
228
|
+
- Architecture overview: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
229
|
+
- Full workflow with remote sync: [README.md](README.md)
|
package/README.md
CHANGED
|
@@ -12,10 +12,23 @@ The CLI is configured in `src/utils/constants.js` to use that deployed API. Do n
|
|
|
12
12
|
|
|
13
13
|
## Requirements
|
|
14
14
|
|
|
15
|
-
- Node.js
|
|
16
|
-
- Internet access to `https://gent-api.onrender.com`
|
|
15
|
+
- Node.js 18 or newer
|
|
16
|
+
- Internet access to `https://gent-api.onrender.com` (only for remote/auth commands; local commands work offline)
|
|
17
17
|
- A Gent account, created with `gent register`
|
|
18
18
|
|
|
19
|
+
## What makes Gent "smart"
|
|
20
|
+
|
|
21
|
+
Beyond a faithful git-like workflow, Gent adds:
|
|
22
|
+
|
|
23
|
+
- **diff3 three-way merge** with language-aware auto-resolution (JSON key merge, import unioning) that resolves more conflicts correctly and never merges unsafely.
|
|
24
|
+
- **`gent undo` / `gent redo`** — a one-command safety net over an operation journal (friendlier than `git reflog`).
|
|
25
|
+
- **`gent resolve`** — an interactive conflict resolver (ours / theirs / both / edit / AI).
|
|
26
|
+
- **`gent summary`** — a repository health dashboard, plus **`gent log --graph`**.
|
|
27
|
+
- **Optional AI** (`gent commit --ai`, `gent explain`, `gent summary --ai`, AI option in `gent resolve`) — off by default, enabled with `ANTHROPIC_API_KEY`.
|
|
28
|
+
|
|
29
|
+
See [docs/COMMANDS.md](docs/COMMANDS.md) for the full reference and
|
|
30
|
+
[docs/ALGORITHMS.md](docs/ALGORITHMS.md) for how the engines work.
|
|
31
|
+
|
|
19
32
|
## Install
|
|
20
33
|
|
|
21
34
|
From npm:
|
|
@@ -309,7 +322,14 @@ gent merge feature-login
|
|
|
309
322
|
gent push
|
|
310
323
|
```
|
|
311
324
|
|
|
312
|
-
If there are conflicts, resolve
|
|
325
|
+
If there are conflicts, resolve them interactively (recommended):
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
gent resolve # walk each conflict; it can finalize the merge commit for you
|
|
329
|
+
gent push
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Or resolve the markers by hand, then:
|
|
313
333
|
|
|
314
334
|
```bash
|
|
315
335
|
gent add .
|
|
@@ -450,6 +470,42 @@ gent checkout <branch>
|
|
|
450
470
|
gent checkout -b <branch>
|
|
451
471
|
gent merge <branch>
|
|
452
472
|
gent merge <branch> -m "Merge message"
|
|
473
|
+
gent resolve # interactively resolve merge conflicts
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Safety Net (undo / redo)
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
gent undo # reverse the last commit/merge/reset/checkout
|
|
480
|
+
gent undo --list # show the operation history
|
|
481
|
+
gent redo # re-apply the last undone operation
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Undo never deletes your working files; for content-discarding operations
|
|
485
|
+
(`reset --hard`, fast-forward merge, pull) it restores them from the object store.
|
|
486
|
+
|
|
487
|
+
### Insight
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
gent summary # repository health & statistics dashboard
|
|
491
|
+
gent summary --ai # + a short AI-written assessment (needs a key)
|
|
492
|
+
gent log --graph # ASCII commit graph with branches and merges
|
|
493
|
+
gent explain # explain the latest commit in plain language
|
|
494
|
+
gent explain <commit> # explain a specific commit
|
|
495
|
+
gent explain --staged # explain currently staged changes
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Optional AI features
|
|
499
|
+
|
|
500
|
+
AI is off by default and every feature has a non-AI fallback. Enable it with:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
504
|
+
export GENT_AI_MODEL=claude-haiku-4-5 # optional; default is claude-opus-4-8
|
|
505
|
+
|
|
506
|
+
gent commit --ai # suggest a commit message from the staged diff
|
|
507
|
+
gent explain # narrate a diff instead of just printing it
|
|
508
|
+
gent resolve # adds an "Ask AI" choice per conflict hunk
|
|
453
509
|
```
|
|
454
510
|
|
|
455
511
|
### Tags
|
|
@@ -515,6 +571,7 @@ Inside each repo:
|
|
|
515
571
|
├── config.json
|
|
516
572
|
├── commits.json
|
|
517
573
|
├── staging.json
|
|
574
|
+
├── journal.json # operation journal for undo/redo (created on first op)
|
|
518
575
|
├── HEAD
|
|
519
576
|
├── objects/
|
|
520
577
|
└── refs/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gent-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "A modern, Git-like version control CLI with built-in cloud authentication and global user identity management.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node src/index.js",
|
|
11
|
-
"test": "node --check src/index.js && node --
|
|
11
|
+
"test": "node --check src/index.js && node --test tests/diff.test.js tests/merge.test.js tests/hash.test.js tests/merge-base.test.js && node tests/offline-e2e.js",
|
|
12
|
+
"test:unit": "node --test tests/diff.test.js tests/merge.test.js tests/hash.test.js tests/merge-base.test.js",
|
|
13
|
+
"test:e2e": "node tests/offline-e2e.js",
|
|
12
14
|
"test:remote:e2e": "node tests/remote-e2e.js",
|
|
13
15
|
"demo": "bash demo.sh",
|
|
14
16
|
"link": "npm link",
|
|
@@ -47,7 +49,7 @@
|
|
|
47
49
|
"ora": "^5.4.1"
|
|
48
50
|
},
|
|
49
51
|
"engines": {
|
|
50
|
-
"node": ">=
|
|
52
|
+
"node": ">=18.0.0"
|
|
51
53
|
},
|
|
52
54
|
"files": [
|
|
53
55
|
"src/",
|
package/src/commands/branch.js
CHANGED
|
@@ -10,6 +10,7 @@ const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
|
|
|
10
10
|
const { COMMITS_FILE, CONFIG_FILE, API_ENDPOINTS, buildRepoUrl, parseRemoteUrl } = require('../utils/constants');
|
|
11
11
|
const apiClient = require('../utils/api-client');
|
|
12
12
|
const authStorage = require('../utils/auth-storage');
|
|
13
|
+
const journal = require('../utils/journal');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Manage branches
|
|
@@ -110,6 +111,8 @@ async function deleteBranch(name, repository, gentPath) {
|
|
|
110
111
|
process.exit(1);
|
|
111
112
|
}
|
|
112
113
|
|
|
114
|
+
await journal.recordOp(gentPath, 'branch-delete', `delete branch '${name}'`);
|
|
115
|
+
|
|
113
116
|
delete branches[name];
|
|
114
117
|
repository.branches = branches;
|
|
115
118
|
|
package/src/commands/checkout.js
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
const chalk = require('chalk');
|
|
8
8
|
const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
|
|
9
9
|
const { COMMITS_FILE } = require('../utils/constants');
|
|
10
|
+
const journal = require('../utils/journal');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Switch to a different branch
|
|
@@ -28,6 +29,8 @@ async function checkout(branch, options) {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
// Create and switch to new branch
|
|
32
|
+
await journal.recordOp(gentPath, 'checkout', `create branch '${branch}'`);
|
|
33
|
+
|
|
31
34
|
const currentCommit = branches[repository.currentBranch] || null;
|
|
32
35
|
branches[branch] = currentCommit;
|
|
33
36
|
repository.branches = branches;
|
|
@@ -52,6 +55,8 @@ async function checkout(branch, options) {
|
|
|
52
55
|
return;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
await journal.recordOp(gentPath, 'checkout', `switch to branch '${branch}'`);
|
|
59
|
+
|
|
55
60
|
repository.currentBranch = branch;
|
|
56
61
|
await writeJSON(path.join(gentPath, COMMITS_FILE), repository);
|
|
57
62
|
|
package/src/commands/commit.js
CHANGED
|
@@ -11,7 +11,10 @@ const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
|
|
|
11
11
|
const authStorage = require('../utils/auth-storage');
|
|
12
12
|
const { STAGING_FILE, COMMITS_FILE, CONFIG_FILE } = require('../utils/constants');
|
|
13
13
|
const { generateCommitHash } = require('../utils/helpers');
|
|
14
|
-
const { storeTree, snapshotFile } = require('../utils/hash-engine');
|
|
14
|
+
const { storeTree, snapshotFile, readBlobAsString } = require('../utils/hash-engine');
|
|
15
|
+
const { formatUnifiedDiff } = require('../utils/diff-engine');
|
|
16
|
+
const journal = require('../utils/journal');
|
|
17
|
+
const ai = require('../utils/ai-service');
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Create a new commit
|
|
@@ -36,6 +39,25 @@ async function commit(options) {
|
|
|
36
39
|
// Get commit message
|
|
37
40
|
let message = options.message;
|
|
38
41
|
|
|
42
|
+
// Optional: AI-suggested commit message (`gent commit --ai`)
|
|
43
|
+
if (!message && options.ai) {
|
|
44
|
+
if (!ai.isEnabled()) {
|
|
45
|
+
console.log(chalk.yellow(ai.disabledHint()));
|
|
46
|
+
} else {
|
|
47
|
+
const suggested = await suggestMessage(gentPath, stagedEntries);
|
|
48
|
+
if (suggested) {
|
|
49
|
+
const answer = await inquirer.prompt([{
|
|
50
|
+
type: 'input',
|
|
51
|
+
name: 'message',
|
|
52
|
+
message: 'Commit message (AI-suggested, edit as needed):',
|
|
53
|
+
default: suggested.split('\n')[0],
|
|
54
|
+
validate: (input) => input.length > 0 || 'Commit message cannot be empty'
|
|
55
|
+
}]);
|
|
56
|
+
message = answer.message;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
if (!message) {
|
|
40
62
|
const answer = await inquirer.prompt([
|
|
41
63
|
{
|
|
@@ -148,7 +170,9 @@ async function commit(options) {
|
|
|
148
170
|
}
|
|
149
171
|
};
|
|
150
172
|
|
|
151
|
-
// Save commit
|
|
173
|
+
// Save commit (journal pre-state first so "gent undo" can reverse it)
|
|
174
|
+
await journal.recordOp(gentPath, 'commit', `${message} [${repository.currentBranch}]`);
|
|
175
|
+
|
|
152
176
|
repository.commits = repository.commits || [];
|
|
153
177
|
repository.commits.push(commitObj);
|
|
154
178
|
repository.branches[repository.currentBranch] = commitObj.hash;
|
|
@@ -181,4 +205,43 @@ async function commit(options) {
|
|
|
181
205
|
}
|
|
182
206
|
}
|
|
183
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Build a compact staged-diff summary and ask the AI for a commit message.
|
|
210
|
+
* Returns null on any failure (caller falls back to a manual prompt).
|
|
211
|
+
* @param {String} gentPath
|
|
212
|
+
* @param {Array} stagedEntries
|
|
213
|
+
* @returns {Promise<String|null>}
|
|
214
|
+
*/
|
|
215
|
+
async function suggestMessage(gentPath, stagedEntries) {
|
|
216
|
+
try {
|
|
217
|
+
const repository = await readJSON(path.join(gentPath, COMMITS_FILE));
|
|
218
|
+
const headHash = repository.branches[repository.currentBranch];
|
|
219
|
+
const headCommit = headHash ? (repository.commits || []).find(c => c.hash === headHash) : null;
|
|
220
|
+
const headMap = new Map(
|
|
221
|
+
((headCommit && headCommit.tree) ? headCommit.tree : (headCommit ? headCommit.files : []) || [])
|
|
222
|
+
.map(f => [f.path || f.name, f.hash])
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const parts = [];
|
|
226
|
+
for (const e of stagedEntries) {
|
|
227
|
+
if (e.status === 'deleted') { parts.push(`deleted: ${e.path}`); continue; }
|
|
228
|
+
let oldText = '';
|
|
229
|
+
const prev = headMap.get(e.path);
|
|
230
|
+
try { if (prev) oldText = await readBlobAsString(gentPath, prev); } catch { /* binary */ }
|
|
231
|
+
let newText = '';
|
|
232
|
+
try { newText = await readBlobAsString(gentPath, e.hash); } catch { /* binary */ }
|
|
233
|
+
const d = formatUnifiedDiff(e.path, oldText, newText);
|
|
234
|
+
parts.push(d || `${e.status}: ${e.path}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const summary = parts.join('\n\n').slice(0, 12000);
|
|
238
|
+
const spinner = ora(`Asking ${ai.getModel()} for a commit message...`).start();
|
|
239
|
+
const msg = await ai.suggestCommitMessage(summary);
|
|
240
|
+
spinner.stop();
|
|
241
|
+
return msg || null;
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
184
247
|
module.exports = commit;
|