@vibe-agent-toolkit/utils 0.1.42 → 0.2.0-rc.10
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 +81 -19
- package/dist/asset-reference.js +3 -11
- package/dist/asset-reference.js.map +1 -1
- package/dist/compare-code-units.d.ts +28 -0
- package/dist/compare-code-units.d.ts.map +1 -0
- package/dist/compare-code-units.js +33 -0
- package/dist/compare-code-units.js.map +1 -0
- package/dist/crawl-timing.d.ts +657 -0
- package/dist/crawl-timing.d.ts.map +1 -0
- package/dist/crawl-timing.js +765 -0
- package/dist/crawl-timing.js.map +1 -0
- package/dist/crawl.d.ts +2 -4
- package/dist/crawl.d.ts.map +1 -1
- package/dist/crawl.js +2 -4
- package/dist/crawl.js.map +1 -1
- package/dist/dirent-kind.d.ts +83 -0
- package/dist/dirent-kind.d.ts.map +1 -0
- package/dist/dirent-kind.js +129 -0
- package/dist/dirent-kind.js.map +1 -0
- package/dist/entrypoint.d.ts +54 -0
- package/dist/entrypoint.d.ts.map +1 -0
- package/dist/entrypoint.js +71 -0
- package/dist/entrypoint.js.map +1 -0
- package/dist/env-flag.d.ts +51 -0
- package/dist/env-flag.d.ts.map +1 -0
- package/dist/env-flag.js +62 -0
- package/dist/env-flag.js.map +1 -0
- package/dist/errors/errno.d.ts +51 -0
- package/dist/errors/errno.d.ts.map +1 -0
- package/dist/errors/errno.js +112 -0
- package/dist/errors/errno.js.map +1 -0
- package/dist/errors/vat-error.d.ts +60 -0
- package/dist/errors/vat-error.d.ts.map +1 -0
- package/dist/errors/vat-error.js +86 -0
- package/dist/errors/vat-error.js.map +1 -0
- package/dist/file-crawler.d.ts +60 -0
- package/dist/file-crawler.d.ts.map +1 -1
- package/dist/file-crawler.js +214 -24
- package/dist/file-crawler.js.map +1 -1
- package/dist/fs/file-hash.d.ts.map +1 -1
- package/dist/fs/file-hash.js +0 -1
- package/dist/fs/file-hash.js.map +1 -1
- package/dist/fs-utils.d.ts +628 -38
- package/dist/fs-utils.d.ts.map +1 -1
- package/dist/fs-utils.js +770 -71
- package/dist/fs-utils.js.map +1 -1
- package/dist/fs.d.ts +5 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +9 -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-run.d.ts +167 -0
- package/dist/git-run.d.ts.map +1 -0
- package/dist/git-run.js +154 -0
- package/dist/git-run.js.map +1 -0
- package/dist/git-snapshot.d.ts +199 -0
- package/dist/git-snapshot.d.ts.map +1 -0
- package/dist/git-snapshot.js +250 -0
- package/dist/git-snapshot.js.map +1 -0
- package/dist/git-tracker.d.ts +166 -3
- package/dist/git-tracker.d.ts.map +1 -1
- package/dist/git-tracker.js +250 -22
- package/dist/git-tracker.js.map +1 -1
- package/dist/git-utils.d.ts +95 -1
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +227 -81
- package/dist/git-utils.js.map +1 -1
- package/dist/git.d.ts +13 -4
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +12 -4
- package/dist/git.js.map +1 -1
- package/dist/gitignore-checker.d.ts.map +1 -1
- package/dist/gitignore-checker.js +15 -6
- package/dist/gitignore-checker.js.map +1 -1
- package/dist/glob/glob-pattern.js +5 -5
- package/dist/glob/glob-pattern.js.map +1 -1
- package/dist/index.d.ts +33 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -33
- package/dist/index.js.map +1 -1
- package/dist/listing-refusal.d.ts +112 -0
- package/dist/listing-refusal.d.ts.map +1 -0
- package/dist/listing-refusal.js +105 -0
- package/dist/listing-refusal.js.map +1 -0
- 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-containment.d.ts +64 -0
- package/dist/path-containment.d.ts.map +1 -0
- package/dist/path-containment.js +111 -0
- package/dist/path-containment.js.map +1 -0
- package/dist/path-core.d.ts +143 -18
- package/dist/path-core.d.ts.map +1 -1
- package/dist/path-core.js +171 -23
- package/dist/path-core.js.map +1 -1
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +42 -47
- package/dist/path-utils.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/process.d.ts +7 -0
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js +7 -0
- package/dist/process.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 +24 -10
- package/dist/project-utils.js.map +1 -1
- package/dist/project.d.ts +7 -5
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +7 -5
- package/dist/project.js.map +1 -1
- package/dist/safe-exec.d.ts +40 -11
- package/dist/safe-exec.d.ts.map +1 -1
- package/dist/safe-exec.js +111 -25
- package/dist/safe-exec.js.map +1 -1
- package/dist/skill-targets.d.ts +2 -2
- package/dist/skill-targets.js +2 -2
- package/dist/skill-test/auth-resolver.d.ts +10 -2
- package/dist/skill-test/auth-resolver.d.ts.map +1 -1
- package/dist/skill-test/auth-resolver.js +26 -11
- package/dist/skill-test/auth-resolver.js.map +1 -1
- package/dist/skill-test/index.d.ts +1 -1
- package/dist/skill-test/index.d.ts.map +1 -1
- package/dist/skill-test/index.js +1 -1
- package/dist/skill-test/index.js.map +1 -1
- package/dist/skill-test/spawn-claude.d.ts +30 -1
- package/dist/skill-test/spawn-claude.d.ts.map +1 -1
- package/dist/skill-test/spawn-claude.js +71 -5
- package/dist/skill-test/spawn-claude.js.map +1 -1
- package/dist/skill-test/transcript.d.ts +41 -2
- package/dist/skill-test/transcript.d.ts.map +1 -1
- package/dist/skill-test/transcript.js +55 -10
- package/dist/skill-test/transcript.js.map +1 -1
- package/dist/spawn-hardened.js +0 -1
- package/dist/spawn-hardened.js.map +1 -1
- package/dist/stdio-blocking.js +13 -14
- package/dist/stdio-blocking.js.map +1 -1
- package/dist/test-helpers.d.ts +130 -79
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +229 -124
- package/dist/test-helpers.js.map +1 -1
- package/dist/testing/executables.d.ts +32 -0
- package/dist/testing/executables.d.ts.map +1 -0
- package/dist/testing/executables.js +70 -0
- package/dist/testing/executables.js.map +1 -0
- package/dist/testing/hostile-tree.d.ts +79 -0
- package/dist/testing/hostile-tree.d.ts.map +1 -0
- package/dist/testing/hostile-tree.js +164 -0
- package/dist/testing/hostile-tree.js.map +1 -0
- package/dist/testing/platform-gates.d.ts +31 -0
- package/dist/testing/platform-gates.d.ts.map +1 -0
- package/dist/testing/platform-gates.js +31 -0
- package/dist/testing/platform-gates.js.map +1 -0
- package/dist/testing/temp-dir.d.ts +255 -0
- package/dist/testing/temp-dir.d.ts.map +1 -0
- package/dist/testing/temp-dir.js +363 -0
- package/dist/testing/temp-dir.js.map +1 -0
- package/dist/testing.d.ts +94 -3
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +119 -3
- package/dist/testing.js.map +1 -1
- package/dist/text-content.d.ts +197 -0
- package/dist/text-content.d.ts.map +1 -0
- package/dist/text-content.js +354 -0
- package/dist/text-content.js.map +1 -0
- package/dist/text-file.d.ts +45 -0
- package/dist/text-file.d.ts.map +1 -0
- package/dist/text-file.js +51 -0
- package/dist/text-file.js.map +1 -0
- package/dist/text.d.ts +16 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +16 -0
- package/dist/text.js.map +1 -0
- package/dist/timing-dump.d.ts +136 -0
- package/dist/timing-dump.d.ts.map +1 -0
- package/dist/timing-dump.js +229 -0
- package/dist/timing-dump.js.map +1 -0
- package/dist/windows-shell.d.ts +0 -1
- package/dist/windows-shell.d.ts.map +1 -1
- package/dist/windows-shell.js +0 -1
- package/dist/windows-shell.js.map +1 -1
- package/dist/zod-introspection.js +2 -2
- package/dist/zod-introspection.js.map +1 -1
- package/eslint/README.md +224 -50
- package/eslint/index.cjs +111 -97
- package/eslint/index.d.cts +16 -6
- package/eslint/rules/callee-name.cjs +23 -0
- package/eslint/rules/commands-import-boundary.cjs +148 -0
- package/eslint/rules/dead-import.cjs +62 -12
- package/eslint/rules/dirent-type-needs-symlink-check.cjs +282 -0
- package/eslint/rules/eslint-rule-factory.cjs +21 -3
- package/eslint/rules/exempt-path-matcher.cjs +2 -1
- package/eslint/rules/explicit-zod-strictness.cjs +120 -0
- package/eslint/rules/no-bare-dynamic-import-path.cjs +5 -1
- package/eslint/rules/no-bare-executable-spawn.cjs +70 -0
- package/eslint/rules/no-bare-symlink-in-tests.cjs +213 -0
- package/eslint/rules/no-blind-catch.cjs +171 -0
- package/eslint/rules/no-child-process-execSync.cjs +8 -0
- package/eslint/rules/no-decaying-referent.cjs +217 -0
- package/eslint/rules/no-dotdot-containment.cjs +160 -0
- package/eslint/rules/no-file-url-string-concat.cjs +4 -1
- package/eslint/rules/no-fragile-entrypoint-guard.cjs +228 -0
- package/eslint/rules/no-fs-mkdirSync.cjs +8 -0
- package/eslint/rules/no-fs-promises-cp.cjs +7 -0
- package/eslint/rules/no-fs-realpathSync.cjs +8 -0
- package/eslint/rules/no-hardcoded-path-split.cjs +29 -18
- package/eslint/rules/no-io-in-unit-tier.cjs +129 -0
- package/eslint/rules/no-literal-process-exit.cjs +129 -0
- package/eslint/rules/no-manual-path-normalize.cjs +146 -96
- package/eslint/rules/no-os-tmpdir.cjs +8 -0
- package/eslint/rules/no-path-operations-in-comparisons.cjs +7 -2
- package/eslint/rules/no-path-sep-in-strings.cjs +7 -2
- package/eslint/rules/no-path-startswith.cjs +7 -2
- package/eslint/rules/no-process-exit-in-phase.cjs +127 -0
- package/eslint/rules/no-raw-node-path.cjs +563 -0
- package/eslint/rules/no-raw-text-decode.cjs +305 -0
- package/eslint/rules/no-registry-count-pin.cjs +255 -0
- package/eslint/rules/no-self-package-import.cjs +168 -0
- package/eslint/rules/no-test-scoped-functions.cjs +10 -3
- package/eslint/rules/no-unix-shell-commands.cjs +6 -2
- package/eslint/rules/no-unsafe-root-join.cjs +23 -2
- package/eslint/rules/no-url-pathname-for-fs.cjs +5 -1
- package/eslint/rules/no-version-literal.cjs +151 -0
- package/eslint/rules/prefer-startswith-over-regex.cjs +33 -1
- package/eslint/rules/require-justified-skip.cjs +8 -2
- package/eslint/rules/safe-import.cjs +1 -1
- package/package.json +16 -16
- package/dist/link-auth/build-headers.d.ts +0 -34
- package/dist/link-auth/build-headers.d.ts.map +0 -1
- package/dist/link-auth/build-headers.js +0 -58
- package/dist/link-auth/build-headers.js.map +0 -1
- package/dist/link-auth/expand-macro.d.ts +0 -38
- package/dist/link-auth/expand-macro.d.ts.map +0 -1
- package/dist/link-auth/expand-macro.js +0 -133
- package/dist/link-auth/expand-macro.js.map +0 -1
- package/dist/link-auth/macros.yaml +0 -50
- package/dist/link-auth/resolve-token.d.ts +0 -83
- package/dist/link-auth/resolve-token.d.ts.map +0 -1
- package/dist/link-auth/resolve-token.js +0 -101
- package/dist/link-auth/resolve-token.js.map +0 -1
- package/dist/link-auth/resolve.d.ts +0 -102
- package/dist/link-auth/resolve.d.ts.map +0 -1
- package/dist/link-auth/resolve.js +0 -66
- package/dist/link-auth/resolve.js.map +0 -1
- package/dist/link-auth/rewrite.d.ts +0 -52
- package/dist/link-auth/rewrite.d.ts.map +0 -1
- package/dist/link-auth/rewrite.js +0 -102
- package/dist/link-auth/rewrite.js.map +0 -1
- package/dist/link-auth/select-provider.d.ts +0 -30
- package/dist/link-auth/select-provider.d.ts.map +0 -1
- package/dist/link-auth/select-provider.js +0 -55
- package/dist/link-auth/select-provider.js.map +0 -1
- package/dist/link-auth/template.d.ts +0 -40
- package/dist/link-auth/template.d.ts.map +0 -1
- package/dist/link-auth/template.js +0 -89
- package/dist/link-auth/template.js.map +0 -1
- package/dist/link-auth/transforms.d.ts +0 -46
- package/dist/link-auth/transforms.d.ts.map +0 -1
- package/dist/link-auth/transforms.js +0 -52
- package/dist/link-auth/transforms.js.map +0 -1
- package/dist/template-entry.d.ts +0 -10
- package/dist/template-entry.d.ts.map +0 -1
- package/dist/template-entry.js +0 -10
- package/dist/template-entry.js.map +0 -1
- package/dist/template.d.ts +0 -7
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -18
- package/dist/template.js.map +0 -1
- package/eslint/rules/no-path-join.cjs +0 -14
- package/eslint/rules/no-path-relative.cjs +0 -14
- package/eslint/rules/no-path-resolve.cjs +0 -14
- package/eslint/rules/path-function-rule-factory.cjs +0 -417
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `isUnderRoot` — the containment question a SINK asks.
|
|
3
|
+
*
|
|
4
|
+
* A delete, a copy, an uninstall: each takes a path that somebody else spelled
|
|
5
|
+
* (a manifest's `name:`, a `flatSkills` entry, a positional the user typed) and
|
|
6
|
+
* is about to act on `join(root, that)`. The question is whether the action
|
|
7
|
+
* lands inside the root, and the only honest answer comes from the
|
|
8
|
+
* filesystem: `startsWith('..')` on a lexical `relative()` misses a symlink
|
|
9
|
+
* inside the root that points out, refuses a member named `..cache`, and is
|
|
10
|
+
* blind to a drive letter — the sweep behind this module watched all three
|
|
11
|
+
* happen at exit 0.
|
|
12
|
+
*
|
|
13
|
+
* Both sides are canonicalized the same way, through the deepest existing
|
|
14
|
+
* ancestor, so a root reached through a symlink (macOS `/tmp`, a linked
|
|
15
|
+
* `~/.claude`) still contains its members, and a candidate that does not exist
|
|
16
|
+
* yet is judged by where creating it would land. Absence is reported as its
|
|
17
|
+
* own answer rather than folded into either side, because a delete sink and a
|
|
18
|
+
* create sink want opposite things from it.
|
|
19
|
+
*
|
|
20
|
+
* Lexical classification of an already-relative path — a projection identity,
|
|
21
|
+
* a report relativizer — is a different question with a different helper:
|
|
22
|
+
* `relativeEscapesRoot` in `path-core.ts`, which touches no filesystem.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Where a candidate stands relative to a root, as the filesystem sees it.
|
|
26
|
+
*
|
|
27
|
+
* - `inside` — the candidate exists and its realpath is a STRICT descendant of
|
|
28
|
+
* the root's realpath. A delete or copy may proceed.
|
|
29
|
+
* - `outside` — its realpath (or, when it does not exist, the realpath of its
|
|
30
|
+
* deepest existing ancestor with the missing remainder re-appended) is not
|
|
31
|
+
* under the root. The root itself is `outside` too: nothing is under itself,
|
|
32
|
+
* and a sink that could delete its own root has no business here.
|
|
33
|
+
* - `absent` — nothing exists at the candidate, and creating it would land
|
|
34
|
+
* inside the root. A create sink proceeds; a delete sink has nothing to do.
|
|
35
|
+
*/
|
|
36
|
+
export type Containment = 'inside' | 'outside' | 'absent';
|
|
37
|
+
/**
|
|
38
|
+
* Is `candidate` strictly under `root`, as the filesystem judges it?
|
|
39
|
+
*
|
|
40
|
+
* Both paths may be relative (resolved from cwd) or absolute, in either
|
|
41
|
+
* separator; neither has to exist. See {@link Containment} for the three
|
|
42
|
+
* answers and which sinks accept which.
|
|
43
|
+
*
|
|
44
|
+
* ⚠️ Costs one `lstat` per missing component plus two `realpath`s. That is
|
|
45
|
+
* nothing for a sink — a delete or a copy dwarfs it — and too much for a loop
|
|
46
|
+
* over every link in a corpus, which is why the projection and link lanes
|
|
47
|
+
* classify lexically with `relativeEscapesRoot` and never call this.
|
|
48
|
+
*
|
|
49
|
+
* @param root - The directory the action must stay inside
|
|
50
|
+
* @param candidate - The path the action is about to touch
|
|
51
|
+
* @returns `'inside'`, `'outside'`, or `'absent'`
|
|
52
|
+
* @throws When the OS refuses to examine either path for any reason but
|
|
53
|
+
* absence — a refusal is reported, never read as "not there"
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // A delete sink: only an existing, contained target may go.
|
|
57
|
+
* if (isUnderRoot(skillsDir, target) !== 'inside') throw new Error(`refusing to remove ${target}: not inside ${skillsDir}`);
|
|
58
|
+
* await rm(target, { recursive: true, force: true });
|
|
59
|
+
*
|
|
60
|
+
* // A create sink: absent-but-contained is exactly the happy path.
|
|
61
|
+
* if (isUnderRoot(skillsDir, dest) === 'outside') throw new Error(`refusing to install to ${dest}: not inside ${skillsDir}`);
|
|
62
|
+
*/
|
|
63
|
+
export declare function isUnderRoot(root: string, candidate: string): Containment;
|
|
64
|
+
//# sourceMappingURL=path-containment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-containment.d.ts","sourceRoot":"","sources":["../src/path-containment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAQH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAkD1D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CAQxE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `isUnderRoot` — the containment question a SINK asks.
|
|
3
|
+
*
|
|
4
|
+
* A delete, a copy, an uninstall: each takes a path that somebody else spelled
|
|
5
|
+
* (a manifest's `name:`, a `flatSkills` entry, a positional the user typed) and
|
|
6
|
+
* is about to act on `join(root, that)`. The question is whether the action
|
|
7
|
+
* lands inside the root, and the only honest answer comes from the
|
|
8
|
+
* filesystem: `startsWith('..')` on a lexical `relative()` misses a symlink
|
|
9
|
+
* inside the root that points out, refuses a member named `..cache`, and is
|
|
10
|
+
* blind to a drive letter — the sweep behind this module watched all three
|
|
11
|
+
* happen at exit 0.
|
|
12
|
+
*
|
|
13
|
+
* Both sides are canonicalized the same way, through the deepest existing
|
|
14
|
+
* ancestor, so a root reached through a symlink (macOS `/tmp`, a linked
|
|
15
|
+
* `~/.claude`) still contains its members, and a candidate that does not exist
|
|
16
|
+
* yet is judged by where creating it would land. Absence is reported as its
|
|
17
|
+
* own answer rather than folded into either side, because a delete sink and a
|
|
18
|
+
* create sink want opposite things from it.
|
|
19
|
+
*
|
|
20
|
+
* Lexical classification of an already-relative path — a projection identity,
|
|
21
|
+
* a report relativizer — is a different question with a different helper:
|
|
22
|
+
* `relativeEscapesRoot` in `path-core.ts`, which touches no filesystem.
|
|
23
|
+
*/
|
|
24
|
+
import { lstatSync } from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { isPathAbsentError } from './errors/errno.js';
|
|
27
|
+
import { normalizePath, safePath, toForwardSlash } from './path-utils.js';
|
|
28
|
+
/**
|
|
29
|
+
* The canonical spelling of `target`, from its deepest existing ancestor.
|
|
30
|
+
*
|
|
31
|
+
* Walks up until `lstat` answers, canonicalizes THAT with the same realpath
|
|
32
|
+
* every path helper uses, and re-appends the missing tail. A refusal is not
|
|
33
|
+
* an absence: `EACCES` on an ancestor, `ELOOP` on a cycle, an invalid name —
|
|
34
|
+
* the OS is saying it cannot examine the path, and a containment verdict
|
|
35
|
+
* built on the spelling it refused is the bug this module exists to remove.
|
|
36
|
+
* Those stay loud.
|
|
37
|
+
*
|
|
38
|
+
* `lstat` rather than `stat`, so a dangling symlink counts as existing: it is
|
|
39
|
+
* an entry the sink can act on (a delete removes the link), and its realpath
|
|
40
|
+
* failing is answered by {@link normalizePath} with the lexical spelling, which
|
|
41
|
+
* is where the entry is.
|
|
42
|
+
*/
|
|
43
|
+
function canonicalFromAncestor(target) {
|
|
44
|
+
const absolute = safePath.resolve(target);
|
|
45
|
+
const missing = [];
|
|
46
|
+
let candidate = absolute;
|
|
47
|
+
for (;;) {
|
|
48
|
+
if (entryExists(candidate)) {
|
|
49
|
+
return {
|
|
50
|
+
canonical: safePath.join(toForwardSlash(normalizePath(candidate)), ...missing),
|
|
51
|
+
exists: missing.length === 0,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const parent = toForwardSlash(path.dirname(candidate));
|
|
55
|
+
// Fixpoint at a filesystem root: `dirname` returns its own input, nothing
|
|
56
|
+
// on the path resolved, and the lexical form is the only answer there is.
|
|
57
|
+
if (parent === candidate) {
|
|
58
|
+
return { canonical: absolute, exists: false };
|
|
59
|
+
}
|
|
60
|
+
missing.unshift(path.basename(candidate));
|
|
61
|
+
candidate = parent;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Whether an entry (a file, a directory, or a link — dangling or not) is at `p`. */
|
|
65
|
+
function entryExists(p) {
|
|
66
|
+
try {
|
|
67
|
+
lstatSync(p);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (isPathAbsentError(error))
|
|
72
|
+
return false;
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Is `candidate` strictly under `root`, as the filesystem judges it?
|
|
78
|
+
*
|
|
79
|
+
* Both paths may be relative (resolved from cwd) or absolute, in either
|
|
80
|
+
* separator; neither has to exist. See {@link Containment} for the three
|
|
81
|
+
* answers and which sinks accept which.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ Costs one `lstat` per missing component plus two `realpath`s. That is
|
|
84
|
+
* nothing for a sink — a delete or a copy dwarfs it — and too much for a loop
|
|
85
|
+
* over every link in a corpus, which is why the projection and link lanes
|
|
86
|
+
* classify lexically with `relativeEscapesRoot` and never call this.
|
|
87
|
+
*
|
|
88
|
+
* @param root - The directory the action must stay inside
|
|
89
|
+
* @param candidate - The path the action is about to touch
|
|
90
|
+
* @returns `'inside'`, `'outside'`, or `'absent'`
|
|
91
|
+
* @throws When the OS refuses to examine either path for any reason but
|
|
92
|
+
* absence — a refusal is reported, never read as "not there"
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // A delete sink: only an existing, contained target may go.
|
|
96
|
+
* if (isUnderRoot(skillsDir, target) !== 'inside') throw new Error(`refusing to remove ${target}: not inside ${skillsDir}`);
|
|
97
|
+
* await rm(target, { recursive: true, force: true });
|
|
98
|
+
*
|
|
99
|
+
* // A create sink: absent-but-contained is exactly the happy path.
|
|
100
|
+
* if (isUnderRoot(skillsDir, dest) === 'outside') throw new Error(`refusing to install to ${dest}: not inside ${skillsDir}`);
|
|
101
|
+
*/
|
|
102
|
+
export function isUnderRoot(root, candidate) {
|
|
103
|
+
const rootReal = canonicalFromAncestor(root).canonical;
|
|
104
|
+
const target = canonicalFromAncestor(candidate);
|
|
105
|
+
const prefix = rootReal.endsWith('/') ? rootReal : `${rootReal}/`;
|
|
106
|
+
if (!target.canonical.startsWith(prefix)) {
|
|
107
|
+
return 'outside';
|
|
108
|
+
}
|
|
109
|
+
return target.exists ? 'inside' : 'absent';
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=path-containment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-containment.js","sourceRoot":"","sources":["../src/path-containment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAgB1E;;;;;;;;;;;;;;GAcG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,SAAS,GAAG,QAAQ,CAAC;IACzB,SAAS,CAAC;QACR,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO;gBACL,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC;gBAC9E,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC;aAC7B,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QACvD,0EAA0E;QAC1E,0EAA0E;QAC1E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAChD,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;QAC1C,SAAS,GAAG,MAAM,CAAC;IACrB,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,SAAS,WAAW,CAAC,CAAS;IAC5B,IAAI,CAAC;QACH,SAAS,CAAC,CAAC,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,iBAAiB,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,SAAiB;IACzD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;IACvD,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C,CAAC"}
|
package/dist/path-core.d.ts
CHANGED
|
@@ -10,6 +10,26 @@
|
|
|
10
10
|
* `mkdirSyncReal`, `resolveFromImportMeta`, `dynamicImportPath`) live in
|
|
11
11
|
* `./path-utils.ts` and are exposed via the `./fs` entry.
|
|
12
12
|
*/
|
|
13
|
+
import { VatError } from './errors/vat-error.js';
|
|
14
|
+
/**
|
|
15
|
+
* Thrown by {@link safePath.joinUnderRoot} when the joined path would land
|
|
16
|
+
* outside its root.
|
|
17
|
+
*
|
|
18
|
+
* A class with a code rather than a prefixed sentence: three packages used to
|
|
19
|
+
* recognise this refusal with `error.message.startsWith('safePath.joinUnderRoot:')`,
|
|
20
|
+
* which is a contract on prose. Dispatch with
|
|
21
|
+
* `isVatError(error, PathEscapesRootError.code)` — it survives the `src`/`dist`
|
|
22
|
+
* boundary that `instanceof` does not.
|
|
23
|
+
*/
|
|
24
|
+
export declare class PathEscapesRootError extends VatError {
|
|
25
|
+
/** The code every instance carries, for `isVatError(error, PathEscapesRootError.code)`. */
|
|
26
|
+
static readonly code = "PATH_ESCAPES_ROOT";
|
|
27
|
+
/**
|
|
28
|
+
* @param root - The root the path had to stay under
|
|
29
|
+
* @param detail - Which segment, or which result, escaped it
|
|
30
|
+
*/
|
|
31
|
+
constructor(root: string, detail: string);
|
|
32
|
+
}
|
|
13
33
|
/**
|
|
14
34
|
* Check if a path is absolute
|
|
15
35
|
*
|
|
@@ -44,8 +64,9 @@ export declare function isAbsoluteAnyPlatform(p: string): boolean;
|
|
|
44
64
|
/**
|
|
45
65
|
* True if `p` contains a `..` parent-directory traversal segment.
|
|
46
66
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
67
|
+
* Backslashes are read as separators on every host (the input is author-written
|
|
68
|
+
* config), then each `/`-delimited segment is inspected — so a `..` is caught
|
|
69
|
+
* regardless of the separator the author typed. A containment guard
|
|
49
70
|
* for config-supplied relative paths (skill `files:` dest values, glob magic
|
|
50
71
|
* remainders) that must never climb above their anchor directory.
|
|
51
72
|
*
|
|
@@ -56,13 +77,66 @@ export declare function isAbsoluteAnyPlatform(p: string): boolean;
|
|
|
56
77
|
* hasParentTraversalSegment('a..b/c') // false (".." must be a whole segment)
|
|
57
78
|
*/
|
|
58
79
|
export declare function hasParentTraversalSegment(p: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* True when a root-relative path — as `safePath.relative(root, p)` spells it —
|
|
82
|
+
* names something the root does not contain.
|
|
83
|
+
*
|
|
84
|
+
* The three shapes `path.relative` can return for an outsider: the parent
|
|
85
|
+
* itself (`..`), a climb through it (`../x`), and, on Windows only, an
|
|
86
|
+
* absolute path (a target on another drive has no relative spelling). A name
|
|
87
|
+
* that merely BEGINS with two dots (`..notes.md`) is a member and reads as one;
|
|
88
|
+
* the bare `startsWith('..')` this replaces refused it, dropped the file from
|
|
89
|
+
* the package and unlinked the reference, at exit 0.
|
|
90
|
+
*
|
|
91
|
+
* ⚠️ **Lexical, on purpose.** This classifies a relative path that was already
|
|
92
|
+
* computed; it does not ask the filesystem, so a symlink inside the root that
|
|
93
|
+
* points outside reads as inside here. That is the right answer for the
|
|
94
|
+
* callers that own no root to ask about — a projection identity, a permission
|
|
95
|
+
* pattern, a report relativizer — and the WRONG one for a delete or copy sink,
|
|
96
|
+
* which must ask {@link isUnderRoot} from `@vibe-agent-toolkit/utils` instead.
|
|
97
|
+
* The empty relative (the root itself) is not an escape; whether equality is
|
|
98
|
+
* acceptable is the caller's question and is asked beside this one.
|
|
99
|
+
*
|
|
100
|
+
* @param normalizedRelative - A forward-slashed root-relative path
|
|
101
|
+
* @returns True when the root does not contain it
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* relativeEscapesRoot(safePath.relative(root, p)) // the whole idiom
|
|
105
|
+
* relativeEscapesRoot('../x') // true
|
|
106
|
+
* relativeEscapesRoot('..notes.md') // false — a member whose name starts with dots
|
|
107
|
+
*/
|
|
108
|
+
export declare function relativeEscapesRoot(normalizedRelative: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* True when `name` can only ever be ONE directory entry under whatever it is
|
|
111
|
+
* joined to: non-empty, not `.` or `..`, no separator of either platform, no
|
|
112
|
+
* NUL, no drive-letter prefix.
|
|
113
|
+
*
|
|
114
|
+
* The check for a caller-controlled NAME — a skill name from a manifest, a
|
|
115
|
+
* session id, a positional the user typed — that is about to become
|
|
116
|
+
* `join(root, name)`. A name is not a path: `..cache` and `a..b` are legitimate
|
|
117
|
+
* entries, and `includes('..')` refused them while `startsWith` let `x/../..`
|
|
118
|
+
* through. The question is whether the join can land anywhere but directly
|
|
119
|
+
* under `root`, and that is answered by the segment's shape alone, with no
|
|
120
|
+
* filesystem — which is also why this belongs beside the path helpers rather
|
|
121
|
+
* than beside {@link isUnderRoot}, which is the check for a PATH.
|
|
122
|
+
*
|
|
123
|
+
* @param name - The proposed entry name
|
|
124
|
+
* @returns True when `join(root, name)` is a direct child of `root`
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* isSingleFsSegment('my-skill') // true
|
|
128
|
+
* isSingleFsSegment('..cache') // true — dots inside a name are just dots
|
|
129
|
+
* isSingleFsSegment('../victim') // false
|
|
130
|
+
* isSingleFsSegment('..') // false
|
|
131
|
+
*/
|
|
132
|
+
export declare function isSingleFsSegment(name: string): boolean;
|
|
59
133
|
/**
|
|
60
134
|
* Compute a `ValidationIssue.location`: an absolute source file path made
|
|
61
135
|
* relative to the scan/project root, forward-slashed.
|
|
62
136
|
*
|
|
63
137
|
* This is the ONE relativizer every VAT validation lane uses. `location` is
|
|
64
138
|
* contractually project-relative (see `ValidationIssue` in
|
|
65
|
-
* `@vibe-agent-toolkit/
|
|
139
|
+
* `@vibe-agent-toolkit/schema`), so producers must route through here
|
|
66
140
|
* rather than emitting `skillPath` directly — absolute locations leak the
|
|
67
141
|
* developer's home directory into CI logs and make `validation.allow` globs,
|
|
68
142
|
* which match against `location`, unwritable.
|
|
@@ -115,33 +189,84 @@ export declare function toAbsolutePath(p: string, baseDir: string): string;
|
|
|
115
189
|
*/
|
|
116
190
|
export declare function getRelativePath(from: string, to: string): string;
|
|
117
191
|
/**
|
|
118
|
-
* Convert a path
|
|
192
|
+
* Convert a NATIVE path — one the filesystem, `path.*`, `readdir` or git
|
|
193
|
+
* handed you — to forward slashes.
|
|
119
194
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
195
|
+
* Converts only where a backslash is a separator (win32). On POSIX a backslash is a
|
|
196
|
+
* legal filename character, so `docs/x\y.md` is one file and is returned
|
|
197
|
+
* unchanged: converting it would invent a phantom `docs/x/` directory and, in
|
|
198
|
+
* {@link safePath.joinUnderRoot}, turn an `x\..\..` NAME into a climb.
|
|
123
199
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
200
|
+
* For AUTHOR-WRITTEN text — an href, a glob, a config value, a CLI argument,
|
|
201
|
+
* an archive entry name — whose backslashes must read as separators on every
|
|
202
|
+
* host, use {@link toForwardSlashAnyPlatform}.
|
|
126
203
|
*
|
|
127
|
-
* @
|
|
128
|
-
*
|
|
129
|
-
* // Returns: 'C:/Users/docs/README.md'
|
|
204
|
+
* @param p - A native path
|
|
205
|
+
* @returns The path with forward slashes (identity on POSIX)
|
|
130
206
|
*
|
|
131
|
-
*
|
|
132
|
-
* //
|
|
207
|
+
* @example
|
|
208
|
+
* toForwardSlash('C:\\Users\\docs\\README.md') // win32: 'C:/Users/docs/README.md'
|
|
209
|
+
* toForwardSlash('docs/x\\y.md') // POSIX: 'docs/x\\y.md' (unchanged)
|
|
133
210
|
*/
|
|
134
211
|
export declare function toForwardSlash(p: string): string;
|
|
212
|
+
/**
|
|
213
|
+
* Convert every backslash to a forward slash, on every host.
|
|
214
|
+
*
|
|
215
|
+
* For AUTHOR-WRITTEN text that may carry Windows spellings regardless of where
|
|
216
|
+
* VAT runs — markdown hrefs, globs, config values, CLI arguments, zip entry
|
|
217
|
+
* names — and for containment guards that must refuse `..\x` everywhere.
|
|
218
|
+
* Never use it on a path read from the filesystem or git: on POSIX that
|
|
219
|
+
* backslash is part of a filename. Use {@link toForwardSlash} for those.
|
|
220
|
+
*
|
|
221
|
+
* @param text - Author-written path text
|
|
222
|
+
* @returns The text with every backslash replaced by `/`
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* toForwardSlashAnyPlatform('..\\evil') // '../evil' on every host
|
|
226
|
+
*/
|
|
227
|
+
export declare function toForwardSlashAnyPlatform(text: string): string;
|
|
228
|
+
/**
|
|
229
|
+
* Normalize text to Unicode NFC — the form in which two *visually identical*
|
|
230
|
+
* filenames compare equal.
|
|
231
|
+
*
|
|
232
|
+
* `é` has two encodings: precomposed NFC (`U+00E9`) and decomposed NFD
|
|
233
|
+
* (`e` + `U+0301`). They render identically and name the same file, yet they are
|
|
234
|
+
* different strings, so `===`, `toLowerCase()`, `Map.get()` and `Set.has()` all
|
|
235
|
+
* report them as different. `readdir` hands back whichever form is on disk —
|
|
236
|
+
* APFS preserves what was written, and decomposed names are common on macOS —
|
|
237
|
+
* while a markdown link typed in an editor almost always carries the composed
|
|
238
|
+
* form. The two sides of a filename comparison therefore disagree about a file
|
|
239
|
+
* that plainly exists.
|
|
240
|
+
*
|
|
241
|
+
* ⚠️ **This produces a COMPARISON KEY, never a path to open.** Do not normalize
|
|
242
|
+
* a path on its way to `fs.*`. macOS would not notice — it is
|
|
243
|
+
* normalization-*insensitive* at the syscall level, so `existsSync` answers the
|
|
244
|
+
* same for either form — but Linux is not: on ext4 the two forms are simply
|
|
245
|
+
* different byte sequences naming different files, so opening the normalized
|
|
246
|
+
* form of a decomposed filename fails outright. That asymmetry is exactly why
|
|
247
|
+
* this is not folded into {@link safePath.resolve}: its output is handed
|
|
248
|
+
* straight to the filesystem. Normalize where two strings are *compared*, and
|
|
249
|
+
* leave the string the filesystem receives alone.
|
|
250
|
+
*
|
|
251
|
+
* @param value - A filename, path segment, or whole path
|
|
252
|
+
* @returns The same text in NFC. Pure ASCII is returned unchanged.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* toNfc('cafe\u0301.md') === toNfc('caf\u00e9.md') // true — same file, two encodings
|
|
256
|
+
*/
|
|
257
|
+
export declare function toNfc(value: string): string;
|
|
135
258
|
/**
|
|
136
259
|
* Cross-platform safe path operations.
|
|
137
260
|
*
|
|
138
261
|
* Wraps Node's `path.join()`, `path.resolve()`, and `path.relative()` to always
|
|
139
|
-
* return forward-slash paths
|
|
262
|
+
* return forward-slash paths (converted through {@link toForwardSlash}, so a
|
|
263
|
+
* backslash inside a POSIX filename survives). On Windows, the native `path.*` functions return
|
|
140
264
|
* backslashes, which causes bugs when paths are used as Map keys, compared as
|
|
141
265
|
* strings, or matched with glob patterns.
|
|
142
266
|
*
|
|
143
267
|
* **Use these instead of importing from `node:path` directly.**
|
|
144
|
-
* ESLint
|
|
268
|
+
* An ESLint rule enforces this — see `no-raw-node-path` (its `functions` option
|
|
269
|
+
* table maps each of `join`/`resolve`/`relative` to its `safePath.*` replacement).
|
|
145
270
|
*
|
|
146
271
|
* @example
|
|
147
272
|
* ```typescript
|
|
@@ -152,7 +277,7 @@ export declare function toForwardSlash(p: string): string;
|
|
|
152
277
|
* safePath.resolve('/project', './docs') // → '/project/docs'
|
|
153
278
|
* safePath.relative('/project/docs', '/project') // → '..'
|
|
154
279
|
* safePath.joinUnderRoot('/harness', 'skill-abc') // → '/harness/skill-abc'
|
|
155
|
-
* safePath.joinUnderRoot('/harness', '../escape') // throws
|
|
280
|
+
* safePath.joinUnderRoot('/harness', '../escape') // throws PathEscapesRootError
|
|
156
281
|
* ```
|
|
157
282
|
*/
|
|
158
283
|
export declare const safePath: {
|
|
@@ -180,7 +305,7 @@ export declare const safePath: {
|
|
|
180
305
|
* skill-test staging code was vulnerable to on Windows.
|
|
181
306
|
*
|
|
182
307
|
* @returns Forward-slash absolute path guaranteed to be inside `root`.
|
|
183
|
-
* @throws {
|
|
308
|
+
* @throws {PathEscapesRootError} If the resolved path would escape `root`.
|
|
184
309
|
*
|
|
185
310
|
* @example
|
|
186
311
|
* ```typescript
|
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
|
|
1
|
+
{"version":3,"file":"path-core.d.ts","sourceRoot":"","sources":["../src/path-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;;;;;;GASG;AACH,qBAAa,oBAAqB,SAAQ,QAAQ;IAChD,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAI,uBAAuB;IAE3C;;;OAGG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAGzC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAGvE;AAKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUvD;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;AAKD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;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;CAiClD,CAAC"}
|