gent-cli 6.0.0 → 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 CHANGED
@@ -1,198 +1,229 @@
1
- # Quick Start Guide - Gent CLI
1
+ # Gent CLI — Quick Start Guide
2
2
 
3
- ## Installation & Setup
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
- ## Make it Globally Available (Optional)
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
- You'll be prompted for:
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 Changes
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
- # Or interactive
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
- ### Switch to Branch
95
- ```bash
96
- gent checkout feature-name
97
- ```
90
+ ---
91
+
92
+ ## Merging
98
93
 
99
- ### Create and Switch
100
94
  ```bash
101
- gent checkout -b new-feature
95
+ gent checkout main
96
+ gent merge feature-login
102
97
  ```
103
98
 
104
- ### List Branches
99
+ If the merge is clean it commits automatically. If there are conflicts:
100
+
105
101
  ```bash
106
- gent branch
102
+ gent resolve # walk each conflict hunk interactively → Ours / Theirs / Both / Edit / Ask AI
103
+ gent push
107
104
  ```
108
105
 
109
- ### Delete Branch
106
+ Or resolve markers by hand then:
107
+
110
108
  ```bash
111
- gent branch -d old-feature
109
+ gent add .
110
+ gent commit -m "Resolve merge"
112
111
  ```
113
112
 
113
+ ---
114
+
114
115
  ## Common Workflows
115
116
 
116
- ### Feature Development
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
- ### Quick Commit All
131
+ ### Made a mistake? Undo it.
132
+
134
133
  ```bash
135
- # Stage and commit all changes
136
- gent add .
137
- gent commit -m "Update all files"
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
- ### Check What Changed
141
- ```bash
142
- # See status
143
- gent status
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
- # Short format
146
- gent status -s
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
- ## Tips & Tricks
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
- 1. **Use .gentignore** - Exclude files like `node_modules/`
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
- ## Running the Demo
159
+ ## Optional AI Features
158
160
 
159
- See the CLI in action:
161
+ All AI features are off by default and have a non-AI fallback.
160
162
 
161
163
  ```bash
162
- chmod +x demo.sh
163
- ./demo.sh
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 error?**
190
+ **Not a gent repository?**
169
191
  ```bash
170
- # Make sure you initialized
171
192
  gent init
172
193
  ```
173
194
 
174
- **No changes to commit?**
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
- # Use node directly
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
- ## Next Steps
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
- - Read the full [README.md](README.md)
192
- - Explore the [source code](src/)
193
- - Try the [demo script](demo.sh)
194
- - Build your own commands!
217
+ **Undo went too far?**
218
+ ```bash
219
+ gent redo
220
+ ```
195
221
 
196
222
  ---
197
223
 
198
- **Happy coding with Gent! 🚀**
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 14 or newer
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:
@@ -137,6 +150,8 @@ Use the `/api/repos/<owner_id>/<repo_name>` path from the previous command:
137
150
  gent remote add origin /api/repos/2/my-project
138
151
  ```
139
152
 
153
+ If the current folder is not initialized yet, `gent remote add` initializes `.gent` first, then adds the remote. You can still run `gent init` yourself before this step if you prefer the explicit flow.
154
+
140
155
  Check it:
141
156
 
142
157
  ```bash
@@ -307,7 +322,14 @@ gent merge feature-login
307
322
  gent push
308
323
  ```
309
324
 
310
- If there are conflicts, resolve the files, then:
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:
311
333
 
312
334
  ```bash
313
335
  gent add .
@@ -448,6 +470,42 @@ gent checkout <branch>
448
470
  gent checkout -b <branch>
449
471
  gent merge <branch>
450
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
451
509
  ```
452
510
 
453
511
  ### Tags
@@ -513,6 +571,7 @@ Inside each repo:
513
571
  ├── config.json
514
572
  ├── commits.json
515
573
  ├── staging.json
574
+ ├── journal.json # operation journal for undo/redo (created on first op)
516
575
  ├── HEAD
517
576
  ├── objects/
518
577
  └── refs/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gent-cli",
3
- "version": "6.0.0",
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 --check tests/remote-e2e.js",
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": ">=14.0.0"
52
+ "node": ">=18.0.0"
51
53
  },
52
54
  "files": [
53
55
  "src/",
@@ -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
 
@@ -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
 
@@ -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;