cowork-cli 2.0.0 → 2.0.1
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 +1 -1
- package/src/utils/fsUtils.js +39 -16
package/package.json
CHANGED
package/src/utils/fsUtils.js
CHANGED
|
@@ -207,31 +207,51 @@ export function clearIgnoreCache() {
|
|
|
207
207
|
* and the **last matching pattern wins**. Negation patterns (`!`) can
|
|
208
208
|
* therefore un-ignore a previously ignored name.
|
|
209
209
|
*
|
|
210
|
-
* @param {string} name
|
|
211
|
-
* @param {Object[]} ignoreList
|
|
210
|
+
* @param {string} name Item basename.
|
|
211
|
+
* @param {Object[]} ignoreList Structured pattern objects.
|
|
212
212
|
* @param {Object} [options]
|
|
213
|
-
* @param {boolean} [options.isDirectory]
|
|
213
|
+
* @param {boolean} [options.isDirectory] Whether the item is a directory.
|
|
214
214
|
* When omitted, directory-only patterns match regardless
|
|
215
215
|
* (backward-compatible with existing callers).
|
|
216
|
+
* @param {string} [options.relativePath] Path relative to the project root
|
|
217
|
+
* (e.g. `"src/internal/foo.js"`). When provided, patterns
|
|
218
|
+
* that contain a `/` are tested against this value instead
|
|
219
|
+
* of being skipped. When omitted the old skip behaviour is
|
|
220
|
+
* preserved for backward compatibility.
|
|
216
221
|
* @returns {boolean} `true` if the item should be skipped.
|
|
217
222
|
*/
|
|
218
223
|
export function shouldIgnore(name, ignoreList, options = {}) {
|
|
219
|
-
const { isDirectory } = options;
|
|
224
|
+
const { isDirectory, relativePath } = options;
|
|
220
225
|
let ignored = false;
|
|
221
226
|
|
|
222
227
|
for (const entry of ignoreList) {
|
|
223
|
-
// Path-containing patterns (e.g. `docs/internal`) require full
|
|
224
|
-
// relative-path matching which callers don't supply — skip them.
|
|
225
|
-
if (entry.hasSlash) continue;
|
|
226
|
-
|
|
227
228
|
// Directory-only patterns (`build/`) don't apply to files.
|
|
228
229
|
// When `isDirectory` is undefined the caller didn't say, so we match
|
|
229
230
|
// to preserve backward compat with callers that only pass basenames.
|
|
230
231
|
if (entry.dirOnly && isDirectory === false) continue;
|
|
231
232
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
let matches = false;
|
|
234
|
+
|
|
235
|
+
if (entry.hasSlash) {
|
|
236
|
+
// Path-scoped pattern — needs a full relative path to evaluate.
|
|
237
|
+
// Without one we conservatively skip it (backward-compatible).
|
|
238
|
+
if (!relativePath) continue;
|
|
239
|
+
|
|
240
|
+
if (entry.hasGlob && entry.regex) {
|
|
241
|
+
matches = entry.regex.test(relativePath);
|
|
242
|
+
} else {
|
|
243
|
+
// Exact segment match: the pattern must equal the relative path
|
|
244
|
+
// OR appear as a leading path prefix followed by a separator.
|
|
245
|
+
matches =
|
|
246
|
+
relativePath === entry.pattern ||
|
|
247
|
+
relativePath.startsWith(entry.pattern + '/');
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
// Basename-only pattern — match against the entry name.
|
|
251
|
+
matches = entry.hasGlob && entry.regex
|
|
252
|
+
? entry.regex.test(name)
|
|
253
|
+
: name === entry.pattern;
|
|
254
|
+
}
|
|
235
255
|
|
|
236
256
|
if (matches) {
|
|
237
257
|
ignored = !entry.negated;
|
|
@@ -263,7 +283,7 @@ export function safePath(inputPath) {
|
|
|
263
283
|
*
|
|
264
284
|
* Rejects:
|
|
265
285
|
* 1. Symbolic links (could escape the project sandbox).
|
|
266
|
-
* 2. Names matched by the ignore list.
|
|
286
|
+
* 2. Names matched by the ignore list (basename AND path-scoped patterns).
|
|
267
287
|
* 3. Paths that resolve outside `process.cwd()`.
|
|
268
288
|
*
|
|
269
289
|
* @param {import('fs').Dirent} dirent Directory entry from `readdir`.
|
|
@@ -274,12 +294,15 @@ export function safePath(inputPath) {
|
|
|
274
294
|
export function isSafeEntry(dirent, parentPath, ignoreList) {
|
|
275
295
|
if (dirent.isSymbolicLink()) return false;
|
|
276
296
|
|
|
277
|
-
const isDir = dirent.isDirectory();
|
|
278
|
-
if (shouldIgnore(dirent.name, ignoreList, { isDirectory: isDir })) return false;
|
|
279
|
-
|
|
280
|
-
const resolved = path.resolve(parentPath, dirent.name);
|
|
281
297
|
const root = process.cwd();
|
|
298
|
+
const resolved = path.resolve(parentPath, dirent.name);
|
|
282
299
|
if (resolved !== root && !resolved.startsWith(root + path.sep)) return false;
|
|
283
300
|
|
|
301
|
+
const isDir = dirent.isDirectory();
|
|
302
|
+
// Compute the relative path so shouldIgnore() can evaluate path-scoped
|
|
303
|
+
// patterns like `tests/fixtures/` in addition to bare-name patterns.
|
|
304
|
+
const relativePath = path.relative(root, resolved);
|
|
305
|
+
if (shouldIgnore(dirent.name, ignoreList, { isDirectory: isDir, relativePath })) return false;
|
|
306
|
+
|
|
284
307
|
return true;
|
|
285
308
|
}
|