gent-cli 10.0.0 → 11.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/package.json +3 -3
- package/src/utils/constants.js +2 -0
- package/src/utils/fileSystem.js +74 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gent-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "A modern, Git-like version control CLI with cloud sync, AI-powered superpowers (ask/review/docs/changelog), and zero-friction setup (gent setup/doctor/config).",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node src/index.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",
|
|
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 tests/file-system.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 tests/file-system.test.js",
|
|
13
13
|
"test:e2e": "node tests/offline-e2e.js",
|
|
14
14
|
"test:remote:e2e": "node tests/remote-e2e.js",
|
|
15
15
|
"demo": "bash demo.sh",
|
package/src/utils/constants.js
CHANGED
package/src/utils/fileSystem.js
CHANGED
|
@@ -7,6 +7,8 @@ const fs = require('fs').promises;
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const { GENT_DIR, DEFAULT_IGNORE_PATTERNS, IGNORE_FILE } = require('./constants');
|
|
9
9
|
|
|
10
|
+
const GIT_IGNORE_FILE = '.gitignore';
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Check if a path exists
|
|
12
14
|
* @param {String} path - Path to check
|
|
@@ -115,21 +117,35 @@ function shouldIgnore(filePath, patterns) {
|
|
|
115
117
|
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
116
118
|
|
|
117
119
|
for (const pattern of patterns) {
|
|
120
|
+
const normalizedPattern = normalizeIgnorePattern(pattern);
|
|
121
|
+
if (!normalizedPattern) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
// Exact match
|
|
119
|
-
if (normalizedPath ===
|
|
126
|
+
if (normalizedPath === normalizedPattern || normalizedPath.startsWith(normalizedPattern + '/')) {
|
|
120
127
|
return true;
|
|
121
128
|
}
|
|
122
129
|
|
|
130
|
+
// Basename match
|
|
131
|
+
if (!normalizedPattern.includes('/') && !normalizedPattern.includes('*')) {
|
|
132
|
+
const parts = normalizedPath.split('/');
|
|
133
|
+
if (parts.includes(normalizedPattern)) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
123
138
|
// Wildcard match
|
|
124
|
-
if (
|
|
125
|
-
const
|
|
126
|
-
|
|
139
|
+
if (normalizedPattern.includes('*')) {
|
|
140
|
+
const wildcardRegex = normalizedPattern.split('*').map(escapeRegex).join('.*');
|
|
141
|
+
const regex = new RegExp('^' + wildcardRegex + '$');
|
|
142
|
+
if (regex.test(normalizedPath) || regex.test(path.posix.basename(normalizedPath))) {
|
|
127
143
|
return true;
|
|
128
144
|
}
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
// Extension match
|
|
132
|
-
if (
|
|
148
|
+
if (normalizedPattern.startsWith('*.') && normalizedPath.endsWith(normalizedPattern.substring(1))) {
|
|
133
149
|
return true;
|
|
134
150
|
}
|
|
135
151
|
}
|
|
@@ -137,6 +153,56 @@ function shouldIgnore(filePath, patterns) {
|
|
|
137
153
|
return false;
|
|
138
154
|
}
|
|
139
155
|
|
|
156
|
+
function normalizeIgnorePattern(pattern) {
|
|
157
|
+
return pattern
|
|
158
|
+
.replace(/\\/g, '/')
|
|
159
|
+
.replace(/^\.\//, '')
|
|
160
|
+
.replace(/^\/+/, '')
|
|
161
|
+
.replace(/\/+$/, '');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function escapeRegex(pattern) {
|
|
165
|
+
return pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function parseIgnoreContent(content, basePath = '') {
|
|
169
|
+
return content.split('\n')
|
|
170
|
+
.map(line => line.trim())
|
|
171
|
+
.filter(line => line && !line.startsWith('#') && !line.startsWith('!'))
|
|
172
|
+
.map(line => normalizeIgnorePattern(path.posix.join(basePath, line)))
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function collectGitIgnorePatterns(rootDir, patterns) {
|
|
177
|
+
async function scan(currentDir) {
|
|
178
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
179
|
+
const relativeDir = path.relative(rootDir, currentDir).replace(/\\/g, '/');
|
|
180
|
+
const gitIgnore = entries.find(entry => entry.isFile() && entry.name === GIT_IGNORE_FILE);
|
|
181
|
+
|
|
182
|
+
if (gitIgnore) {
|
|
183
|
+
const ignorePath = path.join(currentDir, GIT_IGNORE_FILE);
|
|
184
|
+
const content = await fs.readFile(ignorePath, 'utf-8');
|
|
185
|
+
patterns.push(...parseIgnoreContent(content, relativeDir));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
for (const entry of entries) {
|
|
189
|
+
if (!entry.isDirectory()) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
194
|
+
const relativePath = path.relative(rootDir, fullPath);
|
|
195
|
+
if (shouldIgnore(relativePath, patterns)) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
await scan(fullPath);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
await scan(rootDir);
|
|
204
|
+
}
|
|
205
|
+
|
|
140
206
|
/**
|
|
141
207
|
* Get ignore patterns from .gentignore file
|
|
142
208
|
* @param {String} dir - Directory to check
|
|
@@ -148,13 +214,11 @@ async function getIgnorePatterns(dir) {
|
|
|
148
214
|
|
|
149
215
|
if (await pathExists(ignorePath)) {
|
|
150
216
|
const content = await fs.readFile(ignorePath, 'utf-8');
|
|
151
|
-
|
|
152
|
-
.map(line => line.trim())
|
|
153
|
-
.filter(line => line && !line.startsWith('#'));
|
|
154
|
-
|
|
155
|
-
patterns.push(...lines);
|
|
217
|
+
patterns.push(...parseIgnoreContent(content));
|
|
156
218
|
}
|
|
157
219
|
|
|
220
|
+
await collectGitIgnorePatterns(dir, patterns);
|
|
221
|
+
|
|
158
222
|
return patterns;
|
|
159
223
|
}
|
|
160
224
|
|