@vibe-agent-toolkit/utils 0.1.42 → 0.2.0-rc.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/README.md +19 -3
- package/dist/file-crawler.d.ts.map +1 -1
- package/dist/file-crawler.js +88 -2
- package/dist/file-crawler.js.map +1 -1
- package/dist/fs-utils.d.ts +389 -30
- package/dist/fs-utils.d.ts.map +1 -1
- package/dist/fs-utils.js +425 -56
- package/dist/fs-utils.js.map +1 -1
- package/dist/fs.d.ts +2 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +7 -1
- package/dist/fs.js.map +1 -1
- package/dist/git-root-cache.d.ts +44 -0
- package/dist/git-root-cache.d.ts.map +1 -0
- package/dist/git-root-cache.js +68 -0
- package/dist/git-root-cache.js.map +1 -0
- package/dist/git-utils.d.ts +11 -0
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +28 -8
- package/dist/git-utils.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/dist/numeric-args.d.ts +24 -0
- package/dist/numeric-args.d.ts.map +1 -0
- package/dist/numeric-args.js +37 -0
- package/dist/numeric-args.js.map +1 -0
- package/dist/path-core.d.ts +30 -0
- package/dist/path-core.d.ts.map +1 -1
- package/dist/path-core.js +32 -0
- package/dist/path-core.js.map +1 -1
- package/dist/path.d.ts +1 -1
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +1 -1
- package/dist/path.js.map +1 -1
- package/dist/project-utils.d.ts +7 -1
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js +9 -1
- package/dist/project-utils.js.map +1 -1
- package/dist/test-helpers.d.ts +16 -0
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +28 -1
- package/dist/test-helpers.js.map +1 -1
- package/eslint/README.md +1 -1
- package/eslint/rules/dead-import.cjs +61 -11
- package/eslint/rules/eslint-rule-factory.cjs +16 -1
- package/eslint/rules/no-manual-path-normalize.cjs +24 -3
- package/eslint/rules/path-function-rule-factory.cjs +99 -20
- package/eslint/rules/prefer-startswith-over-regex.cjs +24 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-root-cache.d.ts","sourceRoot":"","sources":["../src/git-root-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAmBH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGjG;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The module-level memo behind `gitFindRoot`, in its own leaf module.
|
|
3
|
+
*
|
|
4
|
+
* Two modules need it and they must not need each other:
|
|
5
|
+
*
|
|
6
|
+
* - `git-utils.ts` reads and writes it (it owns the walk).
|
|
7
|
+
* - `project-utils.ts` clears it from `resetProjectRootCaches()`, so callers
|
|
8
|
+
* have ONE reset to remember rather than one per walk-up cache.
|
|
9
|
+
*
|
|
10
|
+
* Having `project-utils.ts` import `git-utils.ts` for that would drag `which`
|
|
11
|
+
* and `node:child_process` into the `./project` entry, which exists precisely so
|
|
12
|
+
* root discovery costs no third-party packages to reach. This file imports
|
|
13
|
+
* nothing, so both sides can depend on it.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately not re-exported from `index.ts` or any subpath: the memo is an
|
|
16
|
+
* implementation detail of `gitFindRoot`, and a second public reset name is a
|
|
17
|
+
* reset callers forget to call.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Answers "which git root governs files at or below this directory?" for every
|
|
21
|
+
* directory a walk has climbed through.
|
|
22
|
+
*
|
|
23
|
+
* The answer is a property of the keyed directory alone — it does not depend on
|
|
24
|
+
* where the walk that discovered it started — so entries are safe to share
|
|
25
|
+
* across starting points. That sharing is the whole point: on a real `vat audit`
|
|
26
|
+
* run the `.git` probe fired 89 times over 21 distinct directories, because
|
|
27
|
+
* different files' walks re-climb the same ancestors.
|
|
28
|
+
*
|
|
29
|
+
* `null` is a stored value, not an absence: "known not to be in a repository"
|
|
30
|
+
* is the answer that costs a walk all the way to the filesystem root, so it has
|
|
31
|
+
* to be cacheable. Absence is `undefined`, which `Map.get` returns and this
|
|
32
|
+
* module never stores.
|
|
33
|
+
*/
|
|
34
|
+
const gitRootCache = new Map();
|
|
35
|
+
/**
|
|
36
|
+
* Look up a memoized git root.
|
|
37
|
+
*
|
|
38
|
+
* @param dir - Resolved directory to look up
|
|
39
|
+
* @returns The memoized answer (possibly `null`), or `undefined` if unknown
|
|
40
|
+
*/
|
|
41
|
+
export function lookupGitRoot(dir) {
|
|
42
|
+
return gitRootCache.get(dir);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Record `gitRoot` as the answer for every directory a walk climbed through.
|
|
46
|
+
*
|
|
47
|
+
* @param climbed - Directories visited by the walk, deepest first
|
|
48
|
+
* @param gitRoot - The answer they all share
|
|
49
|
+
* @returns `gitRoot`, so a walk can `return rememberGitRoot(...)`
|
|
50
|
+
*/
|
|
51
|
+
export function rememberGitRoot(climbed, gitRoot) {
|
|
52
|
+
for (const dir of climbed)
|
|
53
|
+
gitRootCache.set(dir, gitRoot);
|
|
54
|
+
return gitRoot;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Drop every memoized git root.
|
|
58
|
+
*
|
|
59
|
+
* Not called directly by application code — `resetProjectRootCaches()` calls it,
|
|
60
|
+
* so one reset invalidates both walk-up caches. Necessary because a `.git`
|
|
61
|
+
* directory can appear or vanish while the process lives (tests build fixtures
|
|
62
|
+
* mid-run; a long-lived host re-enters `vat audit` between edits), and a stale
|
|
63
|
+
* entry would outlive the change.
|
|
64
|
+
*/
|
|
65
|
+
export function resetGitRootCache() {
|
|
66
|
+
gitRootCache.clear();
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=git-root-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-root-cache.js","sourceRoot":"","sources":["../src/git-root-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,OAA0B,EAAE,OAAsB;IAChF,KAAK,MAAM,GAAG,IAAI,OAAO;QAAE,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB;IAC/B,YAAY,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC"}
|
package/dist/git-utils.d.ts
CHANGED
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Find the git repository root by walking up from the given directory.
|
|
7
7
|
*
|
|
8
|
+
* Memoized module-wide via `git-root-cache.ts`: the walk seeds an entry for
|
|
9
|
+
* every directory it climbs, not just for `startDir`, because the redundancy
|
|
10
|
+
* this removes is overlapping walks from *different* start directories rather
|
|
11
|
+
* than repeated calls with the same one. A `null` answer is memoized too — that
|
|
12
|
+
* is the case that costs a walk to the filesystem root.
|
|
13
|
+
*
|
|
14
|
+
* The memo therefore does NOT see a `.git` directory created or removed after
|
|
15
|
+
* the fact. Anything that mutates repositories in-process (tests; a host that
|
|
16
|
+
* re-enters a command) must call `resetProjectRootCaches()`, which clears this
|
|
17
|
+
* cache along with the project-root one.
|
|
18
|
+
*
|
|
8
19
|
* @param startDir - Directory to start searching from
|
|
9
20
|
* @returns Path to git root, or null if not in a git repository
|
|
10
21
|
*/
|
package/dist/git-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-utils.d.ts","sourceRoot":"","sources":["../src/git-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"git-utils.d.ts","sourceRoot":"","sources":["../src/git-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmB3D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,MAAM,EAAE,GAAG,IAAI,CA6ClB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAkEnF"}
|
package/dist/git-utils.js
CHANGED
|
@@ -6,25 +6,42 @@ import { spawnSync } from 'node:child_process';
|
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
7
|
import { dirname, parse } from 'node:path';
|
|
8
8
|
import which from 'which';
|
|
9
|
+
import { lookupGitRoot, rememberGitRoot } from './git-root-cache.js';
|
|
9
10
|
import { safePath } from './path-utils.js';
|
|
10
11
|
/**
|
|
11
12
|
* Find the git repository root by walking up from the given directory.
|
|
12
13
|
*
|
|
14
|
+
* Memoized module-wide via `git-root-cache.ts`: the walk seeds an entry for
|
|
15
|
+
* every directory it climbs, not just for `startDir`, because the redundancy
|
|
16
|
+
* this removes is overlapping walks from *different* start directories rather
|
|
17
|
+
* than repeated calls with the same one. A `null` answer is memoized too — that
|
|
18
|
+
* is the case that costs a walk to the filesystem root.
|
|
19
|
+
*
|
|
20
|
+
* The memo therefore does NOT see a `.git` directory created or removed after
|
|
21
|
+
* the fact. Anything that mutates repositories in-process (tests; a host that
|
|
22
|
+
* re-enters a command) must call `resetProjectRootCaches()`, which clears this
|
|
23
|
+
* cache along with the project-root one.
|
|
24
|
+
*
|
|
13
25
|
* @param startDir - Directory to start searching from
|
|
14
26
|
* @returns Path to git root, or null if not in a git repository
|
|
15
27
|
*/
|
|
16
28
|
export function gitFindRoot(startDir) {
|
|
17
29
|
let currentDir = safePath.resolve(startDir);
|
|
18
30
|
const root = parse(currentDir).root;
|
|
31
|
+
const climbed = [];
|
|
19
32
|
while (currentDir !== root) {
|
|
33
|
+
const memoized = lookupGitRoot(currentDir);
|
|
34
|
+
if (memoized !== undefined)
|
|
35
|
+
return rememberGitRoot(climbed, memoized);
|
|
36
|
+
climbed.push(currentDir);
|
|
20
37
|
const gitDir = safePath.join(currentDir, '.git');
|
|
21
38
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- walking up from validated startDir
|
|
22
39
|
if (existsSync(gitDir)) {
|
|
23
|
-
return currentDir;
|
|
40
|
+
return rememberGitRoot(climbed, currentDir);
|
|
24
41
|
}
|
|
25
42
|
currentDir = dirname(currentDir);
|
|
26
43
|
}
|
|
27
|
-
return null;
|
|
44
|
+
return rememberGitRoot(climbed, null);
|
|
28
45
|
}
|
|
29
46
|
/**
|
|
30
47
|
* List files tracked by git, optionally filtered by patterns.
|
|
@@ -48,7 +65,11 @@ export function gitLsFiles(options) {
|
|
|
48
65
|
try {
|
|
49
66
|
// Resolve git path using which for security (avoids PATH manipulation)
|
|
50
67
|
const gitPath = which.sync('git');
|
|
51
|
-
|
|
68
|
+
// -z emits NUL-separated, UNQUOTED paths regardless of byte content. Without
|
|
69
|
+
// it, git quotes any path containing non-ASCII bytes (wraps it in double
|
|
70
|
+
// quotes with octal escapes, e.g. `café.md` -> `"caf\303\251.md"`), which is
|
|
71
|
+
// unusable to any exact-string lookup against the real filename.
|
|
72
|
+
const args = ['ls-files', '-z'];
|
|
52
73
|
// Include untracked files that aren't gitignored
|
|
53
74
|
if (options.includeUntracked) {
|
|
54
75
|
args.push('--cached', '--others', '--exclude-standard');
|
|
@@ -70,11 +91,10 @@ export function gitLsFiles(options) {
|
|
|
70
91
|
if (result.status !== 0) {
|
|
71
92
|
return null;
|
|
72
93
|
}
|
|
73
|
-
// Parse output into array of file paths
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.filter((line) => line.length > 0);
|
|
94
|
+
// Parse output into array of file paths. NUL-separated (from -z above), so
|
|
95
|
+
// no path can ever need trimming or quote-unescaping — a trailing NUL just
|
|
96
|
+
// produces one empty string at the end, which the filter below drops.
|
|
97
|
+
return result.stdout.split('\0').filter((line) => line.length > 0);
|
|
78
98
|
}
|
|
79
99
|
catch {
|
|
80
100
|
// Git not available or other error
|
package/dist/git-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-utils.js","sourceRoot":"","sources":["../src/git-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C
|
|
1
|
+
{"version":3,"file":"git-utils.js","sourceRoot":"","sources":["../src/git-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ export * from './spawn-hardened.js';
|
|
|
10
10
|
export * from './path-utils.js';
|
|
11
11
|
export * from './stdio-blocking.js';
|
|
12
12
|
export * from './asset-reference.js';
|
|
13
|
-
export
|
|
13
|
+
export { classifyFilenameCaseFrom, copyDirectory, fillRealpaths, fillSiblingNames, FsLookupCache, realpathFrom, } from './fs-utils.js';
|
|
14
|
+
export type { FilenameCaseVerdict, FilenameMatch, PathProbe, PathProbeStats, RealpathTable, SiblingNamesTable, } from './fs-utils.js';
|
|
14
15
|
export * from './file-crawler.js';
|
|
15
16
|
export * from './gitignore-checker.js';
|
|
16
17
|
export * from './git-url.js';
|
|
@@ -30,4 +31,5 @@ export * from './skill-test/index.js';
|
|
|
30
31
|
export * from './glob/glob-pattern.js';
|
|
31
32
|
export * from './fs/file-hash.js';
|
|
32
33
|
export * from './yaml/surgical-yaml.js';
|
|
34
|
+
export { parseWholeNumberAtLeast } from './numeric-args.js';
|
|
33
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,oBAAoB,CAAC;AAGnC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,oBAAoB,CAAC;AAGnC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,sBAAsB,CAAC;AAqCrC,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,cAAc,EACd,aAAa,EACb,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,cAAc,CAAC;AAG7B,cAAc,gBAAgB,CAAC;AAI/B,cAAc,oBAAoB,CAAC;AAGnC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,eAAe,CAAC;AAG9B,cAAc,oBAAoB,CAAC;AAInC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,uBAAuB,EACvB,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAG7E,cAAc,uBAAuB,CAAC;AAGtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,yBAAyB,CAAC;AAExC,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16,8 +16,42 @@ export * from './path-utils.js';
|
|
|
16
16
|
export * from './stdio-blocking.js';
|
|
17
17
|
// Asset reference resolution (paths + npm bare specifiers)
|
|
18
18
|
export * from './asset-reference.js';
|
|
19
|
-
// Filesystem utilities
|
|
20
|
-
|
|
19
|
+
// Filesystem utilities.
|
|
20
|
+
//
|
|
21
|
+
// Named rather than `export *` on purpose: `classifyFilenameCase` (the pure
|
|
22
|
+
// judge over a hand-held row) and `siblingNamesFrom` (the table lookup that
|
|
23
|
+
// throws on a miss) are internal members of the fill+judge pairs below, and a
|
|
24
|
+
// star re-export would publish them on this barrel the moment they were written.
|
|
25
|
+
// (The `./fs` subpath was already an explicit list and was never at risk.) The
|
|
26
|
+
// public surface is a decision, not a side effect of module layout.
|
|
27
|
+
//
|
|
28
|
+
// TWO materialized columns are published, both shaped fill-first-then-judge:
|
|
29
|
+
//
|
|
30
|
+
// - sibling names — `fillSiblingNames` (every listing, once, up front) plus
|
|
31
|
+
// `classifyFilenameCaseFrom` (pure judgement over the filled table). Its row
|
|
32
|
+
// lookup `siblingNamesFrom` stays internal because a row there is not yet an
|
|
33
|
+
// answer: it still needs a judge, and that judge is what we export.
|
|
34
|
+
// - realpaths — `fillRealpaths` (every canonicalization, once, up front) plus
|
|
35
|
+
// `realpathFrom`. Here the row lookup IS the judge: the canonical path is the
|
|
36
|
+
// answer, so there is nothing left to keep internal.
|
|
37
|
+
//
|
|
38
|
+
// There is deliberately no one-call wrapper composing either pair: handed one, a
|
|
39
|
+
// caller with many paths loops over it, which reinstates the per-path `await` the
|
|
40
|
+
// pairs exist to remove.
|
|
41
|
+
//
|
|
42
|
+
// The `SiblingNames` row type is withheld for the same reason its judge is: it is
|
|
43
|
+
// only ever that judge's parameter, so publishing it would advertise a shape no
|
|
44
|
+
// consumer can hand anywhere. `SiblingNamesTable` and `RealpathTable` — what the
|
|
45
|
+
// fills return and the judges consume — are the ones a caller can name, as are
|
|
46
|
+
// `FilenameCaseVerdict`/`FilenameMatch`, which a consumer does not hand in but
|
|
47
|
+
// does receive and branch on.
|
|
48
|
+
//
|
|
49
|
+
// The cost of that decision, stated so it is not a surprise: a new *type* added
|
|
50
|
+
// to `fs-utils.ts` no longer reaches consumers automatically, and
|
|
51
|
+
// `barrel-exports.test.ts` pins runtime names only, so nothing will fail. The
|
|
52
|
+
// symptom is a type that cannot be imported, which surfaces the first time
|
|
53
|
+
// someone tries — not a silent break in existing code.
|
|
54
|
+
export { classifyFilenameCaseFrom, copyDirectory, fillRealpaths, fillSiblingNames, FsLookupCache, realpathFrom, } from './fs-utils.js';
|
|
21
55
|
// Directory crawling with glob patterns
|
|
22
56
|
export * from './file-crawler.js';
|
|
23
57
|
// Git ignore checking
|
|
@@ -52,4 +86,5 @@ export * from './glob/glob-pattern.js';
|
|
|
52
86
|
export * from './fs/file-hash.js';
|
|
53
87
|
// Byte-surgical YAML value updater (replace/insert without reflowing the doc)
|
|
54
88
|
export * from './yaml/surgical-yaml.js';
|
|
89
|
+
export { parseWholeNumberAtLeast } from './numeric-args.js';
|
|
55
90
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8DAA8D;AAC9D,cAAc,gBAAgB,CAAC;AAE/B,4FAA4F;AAC5F,cAAc,oBAAoB,CAAC;AAEnC,+EAA+E;AAC/E,cAAc,qBAAqB,CAAC;AAEpC,gCAAgC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,4EAA4E;AAC5E,cAAc,qBAAqB,CAAC;AAEpC,2DAA2D;AAC3D,cAAc,sBAAsB,CAAC;AAErC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8DAA8D;AAC9D,cAAc,gBAAgB,CAAC;AAE/B,4FAA4F;AAC5F,cAAc,oBAAoB,CAAC;AAEnC,+EAA+E;AAC/E,cAAc,qBAAqB,CAAC;AAEpC,gCAAgC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,4EAA4E;AAC5E,cAAc,qBAAqB,CAAC;AAEpC,2DAA2D;AAC3D,cAAc,sBAAsB,CAAC;AAErC,wBAAwB;AACxB,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,iFAAiF;AACjF,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,iFAAiF;AACjF,iFAAiF;AACjF,wEAAwE;AACxE,gFAAgF;AAChF,kFAAkF;AAClF,yDAAyD;AACzD,EAAE;AACF,iFAAiF;AACjF,kFAAkF;AAClF,yBAAyB;AACzB,EAAE;AACF,kFAAkF;AAClF,gFAAgF;AAChF,iFAAiF;AACjF,+EAA+E;AAC/E,+EAA+E;AAC/E,8BAA8B;AAC9B,EAAE;AACF,gFAAgF;AAChF,kEAAkE;AAClE,8EAA8E;AAC9E,2EAA2E;AAC3E,uDAAuD;AACvD,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AAUvB,wCAAwC;AACxC,cAAc,mBAAmB,CAAC;AAElC,sBAAsB;AACtB,cAAc,wBAAwB,CAAC;AAEvC,uEAAuE;AACvE,cAAc,cAAc,CAAC;AAE7B,8CAA8C;AAC9C,cAAc,gBAAgB,CAAC;AAE/B,2DAA2D;AAC3D,iEAAiE;AACjE,cAAc,oBAAoB,CAAC;AAEnC,yDAAyD;AACzD,cAAc,kBAAkB,CAAC;AAEjC,oDAAoD;AACpD,cAAc,mBAAmB,CAAC;AAElC,4CAA4C;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,2DAA2D;AAC3D,cAAc,eAAe,CAAC;AAE9B,oEAAoE;AACpE,cAAc,oBAAoB,CAAC;AAEnC,uDAAuD;AACvD,uEAAuE;AACvE,OAAO,EAKL,uBAAuB,GAExB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,iBAAiB,EAAoB,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,2EAA2E;AAC3E,cAAc,uBAAuB,CAAC;AAEtC,oEAAoE;AACpE,cAAc,wBAAwB,CAAC;AAEvC,gDAAgD;AAChD,cAAc,mBAAmB,CAAC;AAElC,8EAA8E;AAC9E,cAAc,yBAAyB,CAAC;AAExC,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation for numeric command-line arguments.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately free of any CLI-framework types: the rule is "is this a whole
|
|
5
|
+
* number at or above a floor", which has nothing to do with Commander. Callers
|
|
6
|
+
* that need a framework-specific error catch this one and re-raise, which is
|
|
7
|
+
* what lets a CLI print a usage message while the rule itself stays testable
|
|
8
|
+
* without a parser.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Parse a whole number that must be at or above a floor.
|
|
12
|
+
*
|
|
13
|
+
* The error names the flag as the user spelled it, because "expects a whole
|
|
14
|
+
* number" without saying *which* option is a message that sends someone back to
|
|
15
|
+
* `--help` to guess.
|
|
16
|
+
*
|
|
17
|
+
* @param value - Raw string as typed on the command line
|
|
18
|
+
* @param floor - Smallest value that makes sense for this option
|
|
19
|
+
* @param flag - Flag spelling, used in the error message
|
|
20
|
+
* @returns The parsed number
|
|
21
|
+
* @throws Error when the value is not a whole number at or above the floor
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseWholeNumberAtLeast(value: string, floor: number, flag: string): number;
|
|
24
|
+
//# sourceMappingURL=numeric-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"numeric-args.d.ts","sourceRoot":"","sources":["../src/numeric-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAiB1F"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation for numeric command-line arguments.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately free of any CLI-framework types: the rule is "is this a whole
|
|
5
|
+
* number at or above a floor", which has nothing to do with Commander. Callers
|
|
6
|
+
* that need a framework-specific error catch this one and re-raise, which is
|
|
7
|
+
* what lets a CLI print a usage message while the rule itself stays testable
|
|
8
|
+
* without a parser.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Parse a whole number that must be at or above a floor.
|
|
12
|
+
*
|
|
13
|
+
* The error names the flag as the user spelled it, because "expects a whole
|
|
14
|
+
* number" without saying *which* option is a message that sends someone back to
|
|
15
|
+
* `--help` to guess.
|
|
16
|
+
*
|
|
17
|
+
* @param value - Raw string as typed on the command line
|
|
18
|
+
* @param floor - Smallest value that makes sense for this option
|
|
19
|
+
* @param flag - Flag spelling, used in the error message
|
|
20
|
+
* @returns The parsed number
|
|
21
|
+
* @throws Error when the value is not a whole number at or above the floor
|
|
22
|
+
*/
|
|
23
|
+
export function parseWholeNumberAtLeast(value, floor, flag) {
|
|
24
|
+
const invalid = new Error(`${flag} expects a whole number of at least ${String(floor)}; got '${value}'.`);
|
|
25
|
+
// Number() coercion accepts far more than decimal digits — '' -> 0,
|
|
26
|
+
// '0x10' -> 16, '1e21' -> a value Number.isInteger still calls whole.
|
|
27
|
+
// Require plain ASCII digits before ever calling Number() on it.
|
|
28
|
+
if (!/^\d+$/.test(value)) {
|
|
29
|
+
throw invalid;
|
|
30
|
+
}
|
|
31
|
+
const parsed = Number(value);
|
|
32
|
+
if (!Number.isInteger(parsed) || parsed < floor) {
|
|
33
|
+
throw invalid;
|
|
34
|
+
}
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=numeric-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"numeric-args.js","sourceRoot":"","sources":["../src/numeric-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa,EAAE,KAAa,EAAE,IAAY;IAChF,MAAM,OAAO,GAAG,IAAI,KAAK,CACvB,GAAG,IAAI,uCAAuC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,CAC/E,CAAC;IAEF,oEAAoE;IACpE,sEAAsE;IACtE,iEAAiE;IACjE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,KAAK,EAAE,CAAC;QAChD,MAAM,OAAO,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/path-core.d.ts
CHANGED
|
@@ -132,6 +132,36 @@ export declare function getRelativePath(from: string, to: string): string;
|
|
|
132
132
|
* // Returns: '/project/docs/README.md' (unchanged)
|
|
133
133
|
*/
|
|
134
134
|
export declare function toForwardSlash(p: string): string;
|
|
135
|
+
/**
|
|
136
|
+
* Normalize text to Unicode NFC — the form in which two *visually identical*
|
|
137
|
+
* filenames compare equal.
|
|
138
|
+
*
|
|
139
|
+
* `é` has two encodings: precomposed NFC (`U+00E9`) and decomposed NFD
|
|
140
|
+
* (`e` + `U+0301`). They render identically and name the same file, yet they are
|
|
141
|
+
* different strings, so `===`, `toLowerCase()`, `Map.get()` and `Set.has()` all
|
|
142
|
+
* report them as different. `readdir` hands back whichever form is on disk —
|
|
143
|
+
* APFS preserves what was written, and decomposed names are common on macOS —
|
|
144
|
+
* while a markdown link typed in an editor almost always carries the composed
|
|
145
|
+
* form. The two sides of a filename comparison therefore disagree about a file
|
|
146
|
+
* that plainly exists.
|
|
147
|
+
*
|
|
148
|
+
* ⚠️ **This produces a COMPARISON KEY, never a path to open.** Do not normalize
|
|
149
|
+
* a path on its way to `fs.*`. macOS would not notice — it is
|
|
150
|
+
* normalization-*insensitive* at the syscall level, so `existsSync` answers the
|
|
151
|
+
* same for either form — but Linux is not: on ext4 the two forms are simply
|
|
152
|
+
* different byte sequences naming different files, so opening the normalized
|
|
153
|
+
* form of a decomposed filename fails outright. That asymmetry is exactly why
|
|
154
|
+
* this is not folded into {@link safePath.resolve}: its output is handed
|
|
155
|
+
* straight to the filesystem. Normalize where two strings are *compared*, and
|
|
156
|
+
* leave the string the filesystem receives alone.
|
|
157
|
+
*
|
|
158
|
+
* @param value - A filename, path segment, or whole path
|
|
159
|
+
* @returns The same text in NFC. Pure ASCII is returned unchanged.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* toNfc('cafe\u0301.md') === toNfc('caf\u00e9.md') // true — same file, two encodings
|
|
163
|
+
*/
|
|
164
|
+
export declare function toNfc(value: string): string;
|
|
135
165
|
/**
|
|
136
166
|
* Cross-platform safe path operations.
|
|
137
167
|
*
|
package/dist/path-core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-core.d.ts","sourceRoot":"","sources":["../src/path-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,QAAQ;IACnB,6DAA6D;8BAC9C,MAAM,EAAE,KAAG,MAAM;IAIhC,gEAAgE;iCAC9C,MAAM,EAAE,KAAG,MAAM;IAInC,iEAAiE;8BAClD,MAAM,MAAM,MAAM,KAAG,MAAM;IAI1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;mCACiB,MAAM,eAAe,MAAM,EAAE,KAAG,MAAM;CAuClD,CAAC"}
|
|
1
|
+
{"version":3,"file":"path-core.d.ts","sourceRoot":"","sources":["../src/path-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,QAAQ;IACnB,6DAA6D;8BAC9C,MAAM,EAAE,KAAG,MAAM;IAIhC,gEAAgE;iCAC9C,MAAM,EAAE,KAAG,MAAM;IAInC,iEAAiE;8BAClD,MAAM,MAAM,MAAM,KAAG,MAAM;IAI1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;mCACiB,MAAM,eAAe,MAAM,EAAE,KAAG,MAAM;CAuClD,CAAC"}
|
package/dist/path-core.js
CHANGED
|
@@ -153,6 +153,38 @@ export function getRelativePath(from, to) {
|
|
|
153
153
|
export function toForwardSlash(p) {
|
|
154
154
|
return p.replaceAll('\\', '/');
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Normalize text to Unicode NFC — the form in which two *visually identical*
|
|
158
|
+
* filenames compare equal.
|
|
159
|
+
*
|
|
160
|
+
* `é` has two encodings: precomposed NFC (`U+00E9`) and decomposed NFD
|
|
161
|
+
* (`e` + `U+0301`). They render identically and name the same file, yet they are
|
|
162
|
+
* different strings, so `===`, `toLowerCase()`, `Map.get()` and `Set.has()` all
|
|
163
|
+
* report them as different. `readdir` hands back whichever form is on disk —
|
|
164
|
+
* APFS preserves what was written, and decomposed names are common on macOS —
|
|
165
|
+
* while a markdown link typed in an editor almost always carries the composed
|
|
166
|
+
* form. The two sides of a filename comparison therefore disagree about a file
|
|
167
|
+
* that plainly exists.
|
|
168
|
+
*
|
|
169
|
+
* ⚠️ **This produces a COMPARISON KEY, never a path to open.** Do not normalize
|
|
170
|
+
* a path on its way to `fs.*`. macOS would not notice — it is
|
|
171
|
+
* normalization-*insensitive* at the syscall level, so `existsSync` answers the
|
|
172
|
+
* same for either form — but Linux is not: on ext4 the two forms are simply
|
|
173
|
+
* different byte sequences naming different files, so opening the normalized
|
|
174
|
+
* form of a decomposed filename fails outright. That asymmetry is exactly why
|
|
175
|
+
* this is not folded into {@link safePath.resolve}: its output is handed
|
|
176
|
+
* straight to the filesystem. Normalize where two strings are *compared*, and
|
|
177
|
+
* leave the string the filesystem receives alone.
|
|
178
|
+
*
|
|
179
|
+
* @param value - A filename, path segment, or whole path
|
|
180
|
+
* @returns The same text in NFC. Pure ASCII is returned unchanged.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* toNfc('cafe\u0301.md') === toNfc('caf\u00e9.md') // true — same file, two encodings
|
|
184
|
+
*/
|
|
185
|
+
export function toNfc(value) {
|
|
186
|
+
return value.normalize('NFC');
|
|
187
|
+
}
|
|
156
188
|
/**
|
|
157
189
|
* Cross-platform safe path operations.
|
|
158
190
|
*
|
package/dist/path-core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-core.js","sourceRoot":"","sources":["../src/path-core.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"path-core.js","sourceRoot":"","sources":["../src/path-core.ts"],"names":[],"mappings":"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"}
|
package/dist/path.d.ts
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
* If you need `normalizedTmpdir`, `mkdirSyncReal`, or `normalizePath`, those
|
|
9
9
|
* touch the filesystem — import them from `@vibe-agent-toolkit/utils/fs`.
|
|
10
10
|
*/
|
|
11
|
-
export { safePath, toForwardSlash, isAbsolutePath, isAbsoluteAnyPlatform, hasParentTraversalSegment, toAbsolutePath, getRelativePath, issueLocation, } from './path-core.js';
|
|
11
|
+
export { safePath, toForwardSlash, toNfc, isAbsolutePath, isAbsoluteAnyPlatform, hasParentTraversalSegment, toAbsolutePath, getRelativePath, issueLocation, } from './path-core.js';
|
|
12
12
|
//# sourceMappingURL=path.d.ts.map
|
package/dist/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,cAAc,EACd,KAAK,EACL,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist/path.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
* If you need `normalizedTmpdir`, `mkdirSyncReal`, or `normalizePath`, those
|
|
9
9
|
* touch the filesystem — import them from `@vibe-agent-toolkit/utils/fs`.
|
|
10
10
|
*/
|
|
11
|
-
export { safePath, toForwardSlash, isAbsolutePath, isAbsoluteAnyPlatform, hasParentTraversalSegment, toAbsolutePath, getRelativePath, issueLocation, } from './path-core.js';
|
|
11
|
+
export { safePath, toForwardSlash, toNfc, isAbsolutePath, isAbsoluteAnyPlatform, hasParentTraversalSegment, toAbsolutePath, getRelativePath, issueLocation, } from './path-core.js';
|
|
12
12
|
//# sourceMappingURL=path.js.map
|
package/dist/path.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,cAAc,EACd,KAAK,EACL,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist/project-utils.d.ts
CHANGED
|
@@ -28,10 +28,16 @@ export declare function findConfigFile(startDir: string): string | null;
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function findNodeWorkspaceRoot(startDir: string): string | null;
|
|
30
30
|
/**
|
|
31
|
-
* Reset {@link findProjectRoot}'s
|
|
31
|
+
* Reset the module-level walk-up caches: {@link findProjectRoot}'s, and the git
|
|
32
|
+
* root memo behind `gitFindRoot`.
|
|
32
33
|
*
|
|
33
34
|
* Call at the start of each independent CLI invocation so in-process callers
|
|
34
35
|
* (and integration tests sharing a vitest worker) don't observe stale results.
|
|
36
|
+
*
|
|
37
|
+
* Both caches are cleared by this one function on purpose. They memoize the same
|
|
38
|
+
* kind of fact — which ancestor governs a directory — and are invalidated by the
|
|
39
|
+
* same events, so a caller that had to remember two reset names would sooner or
|
|
40
|
+
* later remember only one.
|
|
35
41
|
*/
|
|
36
42
|
export declare function resetProjectRootCaches(): void;
|
|
37
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-utils.d.ts","sourceRoot":"","sources":["../src/project-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"project-utils.d.ts","sourceRoot":"","sources":["../src/project-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBrE;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAoED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/D"}
|
package/dist/project-utils.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync, readFileSync } from 'node:fs';
|
|
10
10
|
import { dirname, parse } from 'node:path';
|
|
11
|
+
import { resetGitRootCache } from './git-root-cache.js';
|
|
11
12
|
import { safePath } from './path-utils.js';
|
|
12
13
|
const CONFIG_FILENAME = 'vibe-agent-toolkit.config.yaml';
|
|
13
14
|
const PACKAGE_JSON_FILENAME = 'package.json';
|
|
@@ -81,13 +82,20 @@ export function findNodeWorkspaceRoot(startDir) {
|
|
|
81
82
|
*/
|
|
82
83
|
const walkUpCache = new Map();
|
|
83
84
|
/**
|
|
84
|
-
* Reset {@link findProjectRoot}'s
|
|
85
|
+
* Reset the module-level walk-up caches: {@link findProjectRoot}'s, and the git
|
|
86
|
+
* root memo behind `gitFindRoot`.
|
|
85
87
|
*
|
|
86
88
|
* Call at the start of each independent CLI invocation so in-process callers
|
|
87
89
|
* (and integration tests sharing a vitest worker) don't observe stale results.
|
|
90
|
+
*
|
|
91
|
+
* Both caches are cleared by this one function on purpose. They memoize the same
|
|
92
|
+
* kind of fact — which ancestor governs a directory — and are invalidated by the
|
|
93
|
+
* same events, so a caller that had to remember two reset names would sooner or
|
|
94
|
+
* later remember only one.
|
|
88
95
|
*/
|
|
89
96
|
export function resetProjectRootCaches() {
|
|
90
97
|
walkUpCache.clear();
|
|
98
|
+
resetGitRootCache();
|
|
91
99
|
}
|
|
92
100
|
/** Write `entry` into walkUpCache for every dir in `visited`. */
|
|
93
101
|
function propagateCache(visited, entry) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-utils.js","sourceRoot":"","sources":["../src/project-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,eAAe,GAAG,gCAAgC,CAAC;AACzD,MAAM,qBAAqB,GAAG,cAAc,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;IACjC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC1D,6FAA6F;QAC7F,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QAC9D,6FAA6F;QAC7F,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,6FAA6F;gBAC7F,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBACnE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,YAAY,IAAI,MAAM,EAAE,CAAC;oBAC5E,OAAO,OAAO,CAAC;gBACjB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,+CAA+C;YACjD,CAAC;QACH,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,GAA+C,IAAI,GAAG,EAAE,CAAC;AAE1E
|
|
1
|
+
{"version":3,"file":"project-utils.js","sourceRoot":"","sources":["../src/project-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/test-helpers.d.ts
CHANGED
|
@@ -99,4 +99,20 @@ export declare function setupSyncTempDirSuite(prefix: string): {
|
|
|
99
99
|
afterEach: () => void;
|
|
100
100
|
getTempDir: () => string;
|
|
101
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Probe whether this host can create symbolic links inside `dir`.
|
|
104
|
+
*
|
|
105
|
+
* On Windows, `symlink()` needs either Developer Mode or
|
|
106
|
+
* `SeCreateSymbolicLinkPrivilege`; CI agents frequently have neither. Fixtures
|
|
107
|
+
* that depend on symlinks must therefore ask rather than assume — and, having
|
|
108
|
+
* asked, must SAY they skipped. A symlink case that silently no-ops reads as a
|
|
109
|
+
* passing test for a property nobody exercised.
|
|
110
|
+
*
|
|
111
|
+
* The probe creates and removes one link, because the privilege cannot be
|
|
112
|
+
* inferred from `process.platform` alone.
|
|
113
|
+
*
|
|
114
|
+
* @param dir - An existing directory to probe in (the probe cleans up after itself)
|
|
115
|
+
* @returns True when a symlink was created successfully
|
|
116
|
+
*/
|
|
117
|
+
export declare function canCreateSymlinks(dir: string): boolean;
|
|
102
118
|
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,QAAQ,EAC3C,GAAG,OAAO,EAAE,MAAM,EAAE,GACnB,MAAM,CAuBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG;IACtD,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B,CAyBA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IACrD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B,CAwBA"}
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,QAAQ,EAC3C,GAAG,OAAO,EAAE,MAAM,EAAE,GACnB,MAAM,CAuBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG;IACtD,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B,CAyBA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IACrD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B,CAwBA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUtD"}
|
package/dist/test-helpers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, rmSync, symlinkSync } from 'node:fs';
|
|
3
3
|
import fs from 'node:fs/promises';
|
|
4
4
|
import { mkdirSyncReal, normalizedTmpdir, safePath } from './path-utils.js';
|
|
5
5
|
/**
|
|
@@ -152,4 +152,31 @@ export function setupSyncTempDirSuite(prefix) {
|
|
|
152
152
|
getTempDir: () => tempDir,
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Probe whether this host can create symbolic links inside `dir`.
|
|
157
|
+
*
|
|
158
|
+
* On Windows, `symlink()` needs either Developer Mode or
|
|
159
|
+
* `SeCreateSymbolicLinkPrivilege`; CI agents frequently have neither. Fixtures
|
|
160
|
+
* that depend on symlinks must therefore ask rather than assume — and, having
|
|
161
|
+
* asked, must SAY they skipped. A symlink case that silently no-ops reads as a
|
|
162
|
+
* passing test for a property nobody exercised.
|
|
163
|
+
*
|
|
164
|
+
* The probe creates and removes one link, because the privilege cannot be
|
|
165
|
+
* inferred from `process.platform` alone.
|
|
166
|
+
*
|
|
167
|
+
* @param dir - An existing directory to probe in (the probe cleans up after itself)
|
|
168
|
+
* @returns True when a symlink was created successfully
|
|
169
|
+
*/
|
|
170
|
+
export function canCreateSymlinks(dir) {
|
|
171
|
+
const probe = safePath.join(dir, `.vat-symlink-probe-${randomBytes(4).toString('hex')}`);
|
|
172
|
+
try {
|
|
173
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- caller-supplied dir plus a random basename generated here
|
|
174
|
+
symlinkSync('.', probe);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
rmSync(probe, { force: true });
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
155
182
|
//# sourceMappingURL=test-helpers.js.map
|