wicked-crew 0.7.24 → 0.7.26
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/dist/api/endpoint-manifest-live.d.ts.map +1 -1
- package/dist/api/endpoint-manifest-live.js +5 -0
- package/dist/api/endpoint-manifest-live.js.map +1 -1
- package/dist/api/eval-compare.d.ts +306 -0
- package/dist/api/eval-compare.d.ts.map +1 -0
- package/dist/api/eval-compare.js +610 -0
- package/dist/api/eval-compare.js.map +1 -0
- package/dist/api/eval-sample.d.ts +158 -0
- package/dist/api/eval-sample.d.ts.map +1 -0
- package/dist/api/eval-sample.js +88 -0
- package/dist/api/eval-sample.js.map +1 -0
- package/dist/api/routes.d.ts +5 -0
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +31 -0
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts +12 -2
- package/dist/api/run-files.d.ts.map +1 -1
- package/dist/api/run-files.js +17 -5
- package/dist/api/run-files.js.map +1 -1
- package/dist/api/server.d.ts +20 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +62 -9
- package/dist/api/server.js.map +1 -1
- package/dist/api/skills.d.ts +88 -0
- package/dist/api/skills.d.ts.map +1 -0
- package/dist/api/skills.js +264 -0
- package/dist/api/skills.js.map +1 -0
- package/dist/api/testing.d.ts +2 -75
- package/dist/api/testing.d.ts.map +1 -1
- package/dist/api/testing.js +14 -28
- package/dist/api/testing.js.map +1 -1
- package/dist/core/adapter.d.ts +42 -0
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +83 -12
- package/dist/core/adapter.js.map +1 -1
- package/dist/interactive/bridge-root.d.ts +117 -7
- package/dist/interactive/bridge-root.d.ts.map +1 -1
- package/dist/interactive/bridge-root.js +229 -9
- package/dist/interactive/bridge-root.js.map +1 -1
- package/dist/interactive/doc-delete-routes.d.ts +2 -0
- package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
- package/dist/interactive/doc-delete-routes.js +3 -19
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/doc-list-routes.d.ts +42 -0
- package/dist/interactive/doc-list-routes.d.ts.map +1 -0
- package/dist/interactive/doc-list-routes.js +165 -0
- package/dist/interactive/doc-list-routes.js.map +1 -0
- package/dist/interactive/project-root.d.ts +36 -0
- package/dist/interactive/project-root.d.ts.map +1 -0
- package/dist/interactive/project-root.js +45 -0
- package/dist/interactive/project-root.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +4 -1
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +4 -22
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/projects/default-project.d.ts +10 -0
- package/dist/projects/default-project.d.ts.map +1 -0
- package/dist/projects/default-project.js +10 -0
- package/dist/projects/default-project.js.map +1 -0
- package/dist/projects/routes.d.ts +0 -2
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +1 -2
- package/dist/projects/routes.js.map +1 -1
- package/dist/skills/bundle.d.ts +94 -0
- package/dist/skills/bundle.d.ts.map +1 -0
- package/dist/skills/bundle.js +187 -0
- package/dist/skills/bundle.js.map +1 -0
- package/dist/skills/contain.d.ts +57 -0
- package/dist/skills/contain.d.ts.map +1 -0
- package/dist/skills/contain.js +90 -0
- package/dist/skills/contain.js.map +1 -0
- package/dist/skills/core-closure.d.ts +83 -0
- package/dist/skills/core-closure.d.ts.map +1 -0
- package/dist/skills/core-closure.js +130 -0
- package/dist/skills/core-closure.js.map +1 -0
- package/dist/skills/engine-env.d.ts +48 -0
- package/dist/skills/engine-env.d.ts.map +1 -0
- package/dist/skills/engine-env.js +69 -0
- package/dist/skills/engine-env.js.map +1 -0
- package/dist/skills/frontmatter.d.ts +77 -0
- package/dist/skills/frontmatter.d.ts.map +1 -0
- package/dist/skills/frontmatter.js +190 -0
- package/dist/skills/frontmatter.js.map +1 -0
- package/dist/skills/guards.d.ts +72 -0
- package/dist/skills/guards.d.ts.map +1 -0
- package/dist/skills/guards.js +147 -0
- package/dist/skills/guards.js.map +1 -0
- package/dist/skills/live-generations.d.ts +80 -0
- package/dist/skills/live-generations.d.ts.map +1 -0
- package/dist/skills/live-generations.js +163 -0
- package/dist/skills/live-generations.js.map +1 -0
- package/dist/skills/plugin-source.d.ts +109 -0
- package/dist/skills/plugin-source.d.ts.map +1 -0
- package/dist/skills/plugin-source.js +272 -0
- package/dist/skills/plugin-source.js.map +1 -0
- package/dist/skills/refs.d.ts +58 -0
- package/dist/skills/refs.d.ts.map +1 -0
- package/dist/skills/refs.js +133 -0
- package/dist/skills/refs.js.map +1 -0
- package/dist/skills/root-fence.d.ts +53 -0
- package/dist/skills/root-fence.d.ts.map +1 -0
- package/dist/skills/root-fence.js +109 -0
- package/dist/skills/root-fence.js.map +1 -0
- package/dist/skills/root-names.d.ts +42 -0
- package/dist/skills/root-names.d.ts.map +1 -0
- package/dist/skills/root-names.js +44 -0
- package/dist/skills/root-names.js.map +1 -0
- package/dist/skills/runtime.d.ts +130 -0
- package/dist/skills/runtime.d.ts.map +1 -0
- package/dist/skills/runtime.js +246 -0
- package/dist/skills/runtime.js.map +1 -0
- package/dist/skills/store.d.ts +895 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +3575 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/skills/tree.d.ts +292 -0
- package/dist/skills/tree.d.ts.map +1 -0
- package/dist/skills/tree.js +645 -0
- package/dist/skills/tree.js.map +1 -0
- package/dist/skills/venv.d.ts +52 -0
- package/dist/skills/venv.d.ts.map +1 -0
- package/dist/skills/venv.js +80 -0
- package/dist/skills/venv.js.map +1 -0
- package/dist/studio/assets/index-CK1uJWs2.css +32 -0
- package/dist/studio/assets/index-FcZg3WDR.js +539 -0
- package/dist/studio/index.html +2 -2
- package/dist/studio/testid-inventory.json +611 -7
- package/endpoint-manifest.json +183 -1
- package/package.json +4 -3
- package/dist/studio/assets/index-BmXt63Ij.js +0 -537
- package/dist/studio/assets/index-eso7X_3n.css +0 -32
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-tree primitives for the skills store: walk, hash, copy, remove — POSIX-relative paths,
|
|
3
|
+
* sorted, symlinks never followed.
|
|
4
|
+
*
|
|
5
|
+
* NO-FOLLOW EVERYWHERE (design v3 §API; codex review of #480). A plugin tree is copied INTO the
|
|
6
|
+
* daemon's root and later handed to worker spawns, so a link anywhere on a path the store reads or
|
|
7
|
+
* writes would turn "copy the plugin" into "copy whatever the link reaches" and "write this skill
|
|
8
|
+
* file" into "write wherever the link points". Therefore:
|
|
9
|
+
*
|
|
10
|
+
* - `walkFiles` refuses a symlinked ROOT (the skill dir itself replaced by a link) and skips
|
|
11
|
+
* symlink entries (never followed, never copied, never hashed); `walkTree` is the variant a
|
|
12
|
+
* VERIFICATION uses — it ENUMERATES link entries with their link text (still never followed)
|
|
13
|
+
* so an injected link cannot hide from `current`'s hash (codex round 5); a PRUNED directory
|
|
14
|
+
* (`SKIP_DIR_NAMES`: `.venv`, `node_modules`, `__pycache__`) is descended for CLASSIFICATION
|
|
15
|
+
* only — every entry beneath it is reported with its kind and marked `pruned`, and stays out of
|
|
16
|
+
* every file, hash and copy view (codex round 10: a link under `effective/node_modules/` used
|
|
17
|
+
* to be invisible to the validators because the walk stopped at the directory);
|
|
18
|
+
* - `copyFiles` PREFLIGHTS every destination — each `rel` must be a safe relative path (no `..`,
|
|
19
|
+
* `.`, empty or separator-carrying segment, no absolute/drive prefix, no NUL:
|
|
20
|
+
* `assertSafeRelSegments`) and symlink-free (`assertNoSymlinkComponents`) — BEFORE it creates a
|
|
21
|
+
* parent or writes a byte, independent of where the record came from (codex round 4: a
|
|
22
|
+
* manifest-sourced skill name became a copilot-view path `views/…/<name>/SKILL.md`, and a
|
|
23
|
+
* `../…` name would have joined out of the staging dir). A refused record writes NOTHING —
|
|
24
|
+
* not the records ahead of it either;
|
|
25
|
+
* - `writeFileAtomic` refuses a symlink at the target, opens its temp file with `O_EXCL`
|
|
26
|
+
* (fails on ANY pre-existing entry, a pre-planted symlink included) and `O_NOFOLLOW` under an
|
|
27
|
+
* unpredictable name, and preserves the target's mode bits (an executable support script
|
|
28
|
+
* stays executable across an in-place edit or a replace).
|
|
29
|
+
*
|
|
30
|
+
* # TOCTOU discipline inside the skills root (design v3.5 §3; codex round 8)
|
|
31
|
+
*
|
|
32
|
+
* The lstat walk is necessary, not sufficient: every file open inside the root uses `O_NOFOLLOW`
|
|
33
|
+
* where the platform has it (`readFileNoFollow`, `copyFileNoFollow`, `writeFileAtomic`'s temp
|
|
34
|
+
* file), and the lstat-then-open pattern is closed EVERYWHERE — Windows has no `O_NOFOLLOW` — with a
|
|
35
|
+
* post-open identity check (`fstat` dev/ino against the lstat result: the entry opened IS the entry
|
|
36
|
+
* the walk judged); copies read their SOURCE through such an open, never by path
|
|
37
|
+
* (`copyFileSync(path)` follows a source swapped for a link between enumeration and copy); a staged
|
|
38
|
+
* tree is re-walked (lstat) and re-hashed AFTER the copy and BEFORE the rename into place
|
|
39
|
+
* (store.ts `stagedTreeProblem`, `captureBaseline`, `publishSerialized`). Residual, documented: a
|
|
40
|
+
* directory component swapped between the walk and the rename by another writer with access to the
|
|
41
|
+
* crew-owned state home — mitigated by the single-writer daemon and the post-operation verification,
|
|
42
|
+
* not eliminated.
|
|
43
|
+
*/
|
|
44
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
45
|
+
import { chmodSync, closeSync, constants as fsConstants, fstatSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync, readlinkSync, renameSync, rmdirSync, rmSync, unlinkSync, writeSync, } from 'node:fs';
|
|
46
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
47
|
+
import { ATOMIC_TMP_INFIX } from './root-names.js';
|
|
48
|
+
/** `O_NOFOLLOW` where the platform has it (POSIX); `0` on Windows, where the post-open identity check alone closes the gap. */
|
|
49
|
+
const O_NOFOLLOW = fsConstants.O_NOFOLLOW ?? 0;
|
|
50
|
+
/**
|
|
51
|
+
* Directory names PRUNED from every file, hash and copy view (build caches, vendored deps, the
|
|
52
|
+
* per-baseline `uv sync` env): nothing beneath one is bundle content — never copied into a baseline
|
|
53
|
+
* or a generation, never hashed. The walk still DESCENDS them for classification (codex round 10),
|
|
54
|
+
* so a validator sees what such a directory holds (`TreeEntry.pruned`, `TreeListing.pruned`).
|
|
55
|
+
*/
|
|
56
|
+
export const SKIP_DIR_NAMES = new Set(['__pycache__', 'node_modules', '.venv']);
|
|
57
|
+
/** File names never copied into the root (Finder noise). */
|
|
58
|
+
export const SKIP_FILE_NAMES = new Set(['.DS_Store']);
|
|
59
|
+
export function toPosix(p) {
|
|
60
|
+
return sep === '/' ? p : p.split(sep).join('/');
|
|
61
|
+
}
|
|
62
|
+
/** A path the store would have to FOLLOW a symlink to reach — refused, never judged lexically. */
|
|
63
|
+
export class SymlinkComponentError extends Error {
|
|
64
|
+
path;
|
|
65
|
+
component;
|
|
66
|
+
constructor(path, component) {
|
|
67
|
+
super(`${path} crosses a symlink at ${component} — the skills root never follows links`);
|
|
68
|
+
this.path = path;
|
|
69
|
+
this.component = component;
|
|
70
|
+
this.name = 'SymlinkComponentError';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** A relative path whose SHAPE could join out of its root (`..`, an absolute piece, a separator in a
|
|
74
|
+
* segment, a NUL) — refused before any lstat, whatever produced it. */
|
|
75
|
+
export class UnsafePathSegmentError extends Error {
|
|
76
|
+
path;
|
|
77
|
+
reason;
|
|
78
|
+
constructor(path, reason) {
|
|
79
|
+
super(`unsafe path ${JSON.stringify(path)}: ${reason} — the joined path must stay inside its root`);
|
|
80
|
+
this.path = path;
|
|
81
|
+
this.reason = reason;
|
|
82
|
+
this.name = 'UnsafePathSegmentError';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Why ONE path component is not a safe segment, or `null`. A segment may not be empty, `.` or `..`,
|
|
87
|
+
* may not carry a separator (`/` or `\`), a NUL, or a drive prefix (`C:`). The ONE rule every
|
|
88
|
+
* joined component in the store goes through (contain.ts, `copyFiles`, the view generator).
|
|
89
|
+
*/
|
|
90
|
+
export function unsafeSegmentReason(seg) {
|
|
91
|
+
if (seg === '' || seg === '.' || seg === '..')
|
|
92
|
+
return `segment ${JSON.stringify(seg)}`;
|
|
93
|
+
if (seg.includes('/') || seg.includes('\\'))
|
|
94
|
+
return `segment ${JSON.stringify(seg)} carries a separator`;
|
|
95
|
+
if (seg.includes('\0'))
|
|
96
|
+
return 'NUL byte';
|
|
97
|
+
if (/^[A-Za-z]:/.test(seg))
|
|
98
|
+
return `segment ${JSON.stringify(seg)} carries a drive prefix`;
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Split a POSIX-relative path into segments, refusing anything that could escape: empty, absolute
|
|
103
|
+
* (`/…`), drive-prefixed, backslashes, NUL, and a `.` / `..` / empty segment. Throws
|
|
104
|
+
* `UnsafePathSegmentError`. Lexical only — the caller walks the result for symlinks.
|
|
105
|
+
*/
|
|
106
|
+
export function assertSafeRelSegments(rel) {
|
|
107
|
+
if (rel === '')
|
|
108
|
+
throw new UnsafePathSegmentError(rel, 'empty — the root itself is not a file');
|
|
109
|
+
if (rel.includes('\0'))
|
|
110
|
+
throw new UnsafePathSegmentError(rel, 'NUL byte');
|
|
111
|
+
if (rel.includes('\\'))
|
|
112
|
+
throw new UnsafePathSegmentError(rel, 'backslash — paths are POSIX');
|
|
113
|
+
if (rel.startsWith('/'))
|
|
114
|
+
throw new UnsafePathSegmentError(rel, 'absolute');
|
|
115
|
+
if (/^[A-Za-z]:/.test(rel))
|
|
116
|
+
throw new UnsafePathSegmentError(rel, 'drive prefix');
|
|
117
|
+
const segments = rel.split('/');
|
|
118
|
+
for (const seg of segments) {
|
|
119
|
+
const why = unsafeSegmentReason(seg);
|
|
120
|
+
if (why !== null)
|
|
121
|
+
throw new UnsafePathSegmentError(rel, why);
|
|
122
|
+
}
|
|
123
|
+
return segments;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* `join(root, ...segments)` after an lstat walk that refuses a symlink at ANY component — the
|
|
127
|
+
* leaf included. A component that does not exist yet ends the walk (a not-yet-written leaf, or
|
|
128
|
+
* its new parent dirs — the write creates them); so does a component whose parent turned out to
|
|
129
|
+
* be a REGULAR FILE (ENOTDIR — nothing below a file exists, and no link can be crossed through
|
|
130
|
+
* one; whether the caller may write there is the caller's preflight, `containedDestinations`).
|
|
131
|
+
* Any other filesystem error propagates: an unreadable component is not judged lexically. `root`
|
|
132
|
+
* itself is not walked — the caller decides what its root is (the store walks from the SKILLS
|
|
133
|
+
* root down, so a skill dir replaced by a link is a component, not a root).
|
|
134
|
+
*/
|
|
135
|
+
export function assertNoSymlinkComponents(root, segments) {
|
|
136
|
+
// The walk joins each segment onto its parent, so a `..` (or a separator smuggled inside a
|
|
137
|
+
// segment) would climb out of `root` before any lstat ran — refused lexically first, whatever
|
|
138
|
+
// the caller already checked (codex round 4: `copyFiles` used to trust its records' shape).
|
|
139
|
+
for (const seg of segments) {
|
|
140
|
+
const why = unsafeSegmentReason(seg);
|
|
141
|
+
if (why !== null)
|
|
142
|
+
throw new UnsafePathSegmentError(segments.join('/'), why);
|
|
143
|
+
}
|
|
144
|
+
let cur = root;
|
|
145
|
+
for (const seg of segments) {
|
|
146
|
+
cur = join(cur, seg);
|
|
147
|
+
let st;
|
|
148
|
+
try {
|
|
149
|
+
st = lstatSync(cur);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const code = err.code;
|
|
153
|
+
if (code === 'ENOENT' || code === 'ENOTDIR')
|
|
154
|
+
break;
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
if (st.isSymbolicLink())
|
|
158
|
+
throw new SymlinkComponentError(segments.join('/'), seg);
|
|
159
|
+
}
|
|
160
|
+
return join(root, ...segments);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* THE walker (design v3 no-follow everywhere; codex round 9 on #480): every entry under `root` —
|
|
164
|
+
* the root itself excluded — classified by lstat as a regular file, a directory, a symlink or
|
|
165
|
+
* something else (a socket, fifo, device …), sorted by `rel`, never following a link and never
|
|
166
|
+
* descending into one. NOTHING is invisible: an empty directory is an entry, a symlink is an entry
|
|
167
|
+
* with its link text, a special node is an entry of kind `other`. A directory named in
|
|
168
|
+
* `SKIP_DIR_NAMES` (`.venv`, `node_modules`, `__pycache__`) is reported AND descended (codex round
|
|
169
|
+
* 10): every entry beneath it is classified like any other and marked `pruned` with that
|
|
170
|
+
* directory's `rel`, so a validator SEES a link or a special node planted there — while the file,
|
|
171
|
+
* hash and copy views (`walkFiles`, `walkTree`'s `files` / `links` / `dirs` / `others`, and
|
|
172
|
+
* therefore `hashTree` and `copyFiles`) exclude the whole subtree exactly as before: nothing under
|
|
173
|
+
* a pruned directory is ever copied or hashed. `skipDir(rel)` is the caller's CLOSURE prune (the
|
|
174
|
+
* bundle walk drops `scripts/` dev tooling with it): content outside the closure is not reported
|
|
175
|
+
* and not descended — it is never reached, so never copied either. Every other view derives from
|
|
176
|
+
* this one. A missing `root` yields `[]` — callers treat optional plugin dirs (`schemas/`) as
|
|
177
|
+
* empty, not as errors; a `root` that IS a symlink is refused (`readdirSync` would follow it, and
|
|
178
|
+
* "list this skill's own files" must never enumerate a tree outside the store).
|
|
179
|
+
*/
|
|
180
|
+
export function walkEntries(root, skipDir) {
|
|
181
|
+
const out = [];
|
|
182
|
+
try {
|
|
183
|
+
if (lstatSync(root).isSymbolicLink())
|
|
184
|
+
throw new SymlinkComponentError(root, root);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
if (err.code === 'ENOENT')
|
|
188
|
+
return out;
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
const visit = (dir, relDir, pruned) => {
|
|
192
|
+
let entries;
|
|
193
|
+
try {
|
|
194
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (err.code === 'ENOENT' && relDir === '')
|
|
198
|
+
return;
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
const rel = relDir === '' ? entry.name : `${relDir}/${entry.name}`;
|
|
203
|
+
const abs = join(dir, entry.name);
|
|
204
|
+
if (entry.isSymbolicLink()) {
|
|
205
|
+
out.push({ rel, abs, kind: 'symlink', target: readlinkSync(abs), pruned });
|
|
206
|
+
}
|
|
207
|
+
else if (entry.isDirectory()) {
|
|
208
|
+
out.push({ rel, abs, kind: 'dir', pruned });
|
|
209
|
+
if (skipDir !== undefined && skipDir(rel))
|
|
210
|
+
continue;
|
|
211
|
+
// A pruned-name directory is descended for CLASSIFICATION: its entries carry the outermost
|
|
212
|
+
// pruned directory's rel (a `node_modules` inside a `.venv` is still pruned by the `.venv`).
|
|
213
|
+
visit(abs, rel, pruned ?? (SKIP_DIR_NAMES.has(entry.name) ? rel : null));
|
|
214
|
+
}
|
|
215
|
+
else if (entry.isFile()) {
|
|
216
|
+
out.push({ rel, abs, kind: 'file', pruned });
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
out.push({ rel, abs, kind: 'other', pruned });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
visit(root, '', null);
|
|
224
|
+
out.sort((a, b) => (a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0));
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Whether a walk entry is a regular file the store CARRIES — copies, hashes, records: a regular
|
|
229
|
+
* file outside every pruned directory that is not Finder noise (`SKIP_FILE_NAMES`).
|
|
230
|
+
*/
|
|
231
|
+
export function isCarriedFile(e) {
|
|
232
|
+
return e.kind === 'file' && e.pruned === null && !SKIP_FILE_NAMES.has(e.rel.split('/').pop() ?? '');
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Every regular file under `root`, sorted by `rel` — `walkEntries` filtered to the files the store
|
|
236
|
+
* carries (`isCarriedFile`: nothing beneath a pruned directory, no Finder noise). `skipDir(rel)`
|
|
237
|
+
* prunes a subtree; `SKIP_DIR_NAMES` / `SKIP_FILE_NAMES` always apply.
|
|
238
|
+
*/
|
|
239
|
+
export function walkFiles(root, skipDir) {
|
|
240
|
+
return walkEntries(root, skipDir)
|
|
241
|
+
.filter(isCarriedFile)
|
|
242
|
+
.map(({ rel, abs }) => ({ rel, abs }));
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* `walkEntries` split into what a verification consumes: files (Finder noise excluded), links
|
|
246
|
+
* (listed with their text, never followed or descended — codex round 5: a verification that skips
|
|
247
|
+
* links leaves an injected outside-pointing link invisible to the hash), directories and special
|
|
248
|
+
* nodes — each of these OUTSIDE every pruned directory — plus `pruned`: what the pruned
|
|
249
|
+
* directories hold. `SKIP_DIR_NAMES` (`.venv` / `node_modules` / `__pycache__`) keeps the
|
|
250
|
+
* subtree out of `files` / `links` / `dirs` / `others` (so out of every hash and copy) exactly as
|
|
251
|
+
* before, but the subtree is now WALKED and reported under `pruned` (codex round 10); the
|
|
252
|
+
* pruned-name directory entry itself is in `dirs`; a LINK bearing one of those names is listed like
|
|
253
|
+
* any link (the snapshot's `.venv` link is exactly that). `skipDir(rel)` is the caller's closure
|
|
254
|
+
* prune (the bundle walk drops the `scripts/` dev tooling with it — content there is never reached,
|
|
255
|
+
* and never copied either).
|
|
256
|
+
*/
|
|
257
|
+
export function walkTree(root, skipDir) {
|
|
258
|
+
const entries = walkEntries(root, skipDir);
|
|
259
|
+
const carried = entries.filter((e) => e.pruned === null);
|
|
260
|
+
return {
|
|
261
|
+
files: carried.filter(isCarriedFile).map(({ rel, abs }) => ({ rel, abs })),
|
|
262
|
+
links: carried.filter((e) => e.kind === 'symlink').map(({ rel, abs, target }) => ({ rel, abs, target: target ?? '' })),
|
|
263
|
+
dirs: carried.filter((e) => e.kind === 'dir').map((e) => e.rel),
|
|
264
|
+
others: carried.filter((e) => e.kind === 'other'),
|
|
265
|
+
pruned: entries.filter((e) => e.pruned !== null),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/** Every proper ancestor directory a set of POSIX-relative file paths implies (`a/b/c.md` → `a`, `a/b`), sorted. */
|
|
269
|
+
export function impliedDirs(rels) {
|
|
270
|
+
const out = new Set();
|
|
271
|
+
for (const rel of rels) {
|
|
272
|
+
const segments = rel.split('/');
|
|
273
|
+
for (let i = 1; i < segments.length; i += 1)
|
|
274
|
+
out.add(segments.slice(0, i).join('/'));
|
|
275
|
+
}
|
|
276
|
+
return [...out].sort();
|
|
277
|
+
}
|
|
278
|
+
export function sha256Hex(data) {
|
|
279
|
+
return createHash('sha256').update(data).digest('hex');
|
|
280
|
+
}
|
|
281
|
+
/** The leaf changed identity between the lstat and the open (a link swapped in, a file replaced) — refused, never read or copied (v3.5 §3). */
|
|
282
|
+
export class EntrySwappedError extends Error {
|
|
283
|
+
path;
|
|
284
|
+
constructor(path) {
|
|
285
|
+
super(`${path} is not the entry the walk judged — it changed between lstat and open (a symlink swapped in, or the file replaced); refused`);
|
|
286
|
+
this.path = path;
|
|
287
|
+
this.name = 'EntrySwappedError';
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Open the REGULAR FILE at `path` for reading without following a symlink at the leaf (`O_NOFOLLOW`
|
|
292
|
+
* where available), and prove the opened descriptor IS the entry lstat saw (dev/ino equal, a regular
|
|
293
|
+
* file) — the Windows close of the lstat-then-open gap, applied everywhere (v3.5 §3). Throws
|
|
294
|
+
* `SymlinkComponentError` for a link at the leaf, `EntrySwappedError` when the identity moved, and
|
|
295
|
+
* the filesystem's own error otherwise (ENOENT propagates). Answers the descriptor and its stats.
|
|
296
|
+
*/
|
|
297
|
+
export function openRegularNoFollow(path) {
|
|
298
|
+
const before = lstatSync(path);
|
|
299
|
+
if (before.isSymbolicLink())
|
|
300
|
+
throw new SymlinkComponentError(path, path);
|
|
301
|
+
if (!before.isFile())
|
|
302
|
+
throw new EntrySwappedError(path);
|
|
303
|
+
let fd;
|
|
304
|
+
try {
|
|
305
|
+
fd = openSync(path, fsConstants.O_RDONLY | O_NOFOLLOW);
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
// ELOOP: a link stood there by the time we opened — the swap this discipline exists for.
|
|
309
|
+
if (err.code === 'ELOOP')
|
|
310
|
+
throw new EntrySwappedError(path);
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
let stat;
|
|
314
|
+
try {
|
|
315
|
+
stat = fstatSync(fd);
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
closeSync(fd);
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
if (!stat.isFile() || stat.dev !== before.dev || stat.ino !== before.ino) {
|
|
322
|
+
closeSync(fd);
|
|
323
|
+
throw new EntrySwappedError(path);
|
|
324
|
+
}
|
|
325
|
+
return { fd, stat };
|
|
326
|
+
}
|
|
327
|
+
/** The bytes of the regular file at `path`, read through an `O_NOFOLLOW` open with the identity check (`openRegularNoFollow`). */
|
|
328
|
+
export function readFileNoFollow(path) {
|
|
329
|
+
const { fd } = openRegularNoFollow(path);
|
|
330
|
+
try {
|
|
331
|
+
return readFileSync(fd);
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
closeSync(fd);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Copy one regular file `src` → `dest`: the source is read through `openRegularNoFollow` (never by
|
|
339
|
+
* path — a source swapped for a link between enumeration and copy is refused), the destination is
|
|
340
|
+
* created `O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW` with the source's mode bits (an executable
|
|
341
|
+
* baseline script lands executable), so a pre-planted destination entry — a link included — fails
|
|
342
|
+
* the open instead of being written through.
|
|
343
|
+
*/
|
|
344
|
+
export function copyFileNoFollow(src, dest) {
|
|
345
|
+
const { fd: inFd, stat } = openRegularNoFollow(src);
|
|
346
|
+
let buf;
|
|
347
|
+
try {
|
|
348
|
+
buf = readFileSync(inFd);
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
closeSync(inFd);
|
|
352
|
+
}
|
|
353
|
+
const outFd = openSync(dest, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | O_NOFOLLOW, stat.mode & 0o777);
|
|
354
|
+
try {
|
|
355
|
+
let off = 0;
|
|
356
|
+
while (off < buf.length)
|
|
357
|
+
off += writeSync(outFd, buf, off, buf.length - off);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
closeSync(outFd);
|
|
361
|
+
rmSync(dest, { force: true });
|
|
362
|
+
throw err;
|
|
363
|
+
}
|
|
364
|
+
closeSync(outFd);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* One hash over a file set: sorted relative paths + content digests (`rel \0 sha256(content) \n`
|
|
368
|
+
* per file). Two trees with the same relative layout and bytes hash equal wherever they live —
|
|
369
|
+
* which is what lets a baseline snapshot and the effective copy be compared by hash alone.
|
|
370
|
+
*/
|
|
371
|
+
export function hashFileSet(files) {
|
|
372
|
+
return hashTree(files, []);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* One hash over a file set, its symlink entries AND its directory entries: the files as
|
|
376
|
+
* `hashFileSet` spells them, then every link as `rel \0 -> \0 <link text> \n` (sorted), then every
|
|
377
|
+
* directory as `rel \0 dir \n` (sorted; codex round 9 — an extra EMPTY directory planted in a
|
|
378
|
+
* generation used to leave the hash unchanged). With no links and no directories this IS
|
|
379
|
+
* `hashFileSet`, so a bundle's identity hashes as before; a link added, removed or re-pointed, or a
|
|
380
|
+
* directory added or removed, changes the hash — which is what lets `current` verification refuse
|
|
381
|
+
* an injected link or directory (codex rounds 5, 9). Only `rel`s, digests and link TEXT enter the
|
|
382
|
+
* hash, never what a link reaches: two trees with the same layout, bytes and link texts hash equal
|
|
383
|
+
* wherever they live. Publish hashes the directories its file set IMPLIES (`impliedDirs`); a
|
|
384
|
+
* verification hashes the directories it WALKED — equal iff the generation carries no directory
|
|
385
|
+
* beyond those.
|
|
386
|
+
*/
|
|
387
|
+
export function hashTree(files, links, dirs = []) {
|
|
388
|
+
const h = createHash('sha256');
|
|
389
|
+
for (const f of [...files].sort((a, b) => (a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0))) {
|
|
390
|
+
h.update(f.rel);
|
|
391
|
+
h.update('\0');
|
|
392
|
+
h.update(sha256Hex(readFileNoFollow(f.abs)));
|
|
393
|
+
h.update('\n');
|
|
394
|
+
}
|
|
395
|
+
for (const l of [...links].sort((a, b) => (a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0))) {
|
|
396
|
+
h.update(l.rel);
|
|
397
|
+
h.update('\0->\0');
|
|
398
|
+
h.update(l.target);
|
|
399
|
+
h.update('\n');
|
|
400
|
+
}
|
|
401
|
+
for (const d of [...dirs].sort()) {
|
|
402
|
+
h.update(d);
|
|
403
|
+
h.update('\0dir\n');
|
|
404
|
+
}
|
|
405
|
+
return h.digest('hex');
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Copy every record to `destRoot/<rel>`, creating parents. EVERY destination is preflighted
|
|
409
|
+
* first — the shape (`assertSafeRelSegments`: a `..`, an absolute or drive-prefixed piece, a
|
|
410
|
+
* separator inside a segment, a NUL is refused, whatever produced the record) and the walk
|
|
411
|
+
* (`assertNoSymlinkComponents`: a pre-planted link under the destination would redirect the
|
|
412
|
+
* copy) — and only then does the first byte move, so a refused record leaves NOTHING written
|
|
413
|
+
* (codex round 4: the per-record check used to run only when the record was reached, after the
|
|
414
|
+
* ones ahead of it had landed). Each file goes through `copyFileNoFollow` (v3.5 §3): the source is
|
|
415
|
+
* read through an `O_NOFOLLOW` open with the identity check — a source swapped for a symlink between
|
|
416
|
+
* enumeration and copy is refused — and the destination is created `O_EXCL | O_NOFOLLOW` with the
|
|
417
|
+
* source's mode bits, so an executable baseline script lands executable.
|
|
418
|
+
*/
|
|
419
|
+
export function copyFiles(files, destRoot) {
|
|
420
|
+
const plan = [];
|
|
421
|
+
for (const f of files) {
|
|
422
|
+
const dest = assertNoSymlinkComponents(destRoot, assertSafeRelSegments(f.rel));
|
|
423
|
+
plan.push({ src: f.abs, dest });
|
|
424
|
+
}
|
|
425
|
+
for (const { src, dest } of plan) {
|
|
426
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
427
|
+
copyFileNoFollow(src, dest);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Atomic write (tmp + rename), creating parents — the settings-store discipline, hardened:
|
|
432
|
+
*
|
|
433
|
+
* - the target is lstat'ed: a symlink there is refused (the rename would replace the link,
|
|
434
|
+
* but the caller's containment already forbids links, and a write "over" one is never what
|
|
435
|
+
* the file manager meant);
|
|
436
|
+
* - the temp file is opened `O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW`: POSIX fails that open on ANY existing
|
|
437
|
+
* entry — a symlink included, regardless of where it points — so a pre-planted temp symlink
|
|
438
|
+
* cannot redirect the bytes; the name carries 64 random bits so it cannot be pre-planted by
|
|
439
|
+
* guessing either;
|
|
440
|
+
* - the target's mode bits survive (an in-place edit of an executable support script keeps
|
|
441
|
+
* it executable); a new file takes `opts.mode` or the platform default.
|
|
442
|
+
*/
|
|
443
|
+
export function writeFileAtomic(path, content, opts = {}) {
|
|
444
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
445
|
+
let mode = opts.mode;
|
|
446
|
+
try {
|
|
447
|
+
const st = lstatSync(path);
|
|
448
|
+
if (st.isSymbolicLink())
|
|
449
|
+
throw new SymlinkComponentError(path, path);
|
|
450
|
+
if (st.isFile())
|
|
451
|
+
mode = st.mode & 0o777;
|
|
452
|
+
}
|
|
453
|
+
catch (err) {
|
|
454
|
+
if (err.code !== 'ENOENT')
|
|
455
|
+
throw err;
|
|
456
|
+
}
|
|
457
|
+
const tmp = `${path}${ATOMIC_TMP_INFIX}${randomBytes(8).toString('hex')}`;
|
|
458
|
+
const flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | O_NOFOLLOW;
|
|
459
|
+
const fd = mode === undefined ? openSync(tmp, flags) : openSync(tmp, flags, mode);
|
|
460
|
+
try {
|
|
461
|
+
const buf = typeof content === 'string' ? Buffer.from(content, 'utf8') : content;
|
|
462
|
+
let off = 0;
|
|
463
|
+
while (off < buf.length)
|
|
464
|
+
off += writeSync(fd, buf, off, buf.length - off);
|
|
465
|
+
}
|
|
466
|
+
catch (err) {
|
|
467
|
+
closeSync(fd);
|
|
468
|
+
rmSync(tmp, { force: true });
|
|
469
|
+
throw err;
|
|
470
|
+
}
|
|
471
|
+
closeSync(fd);
|
|
472
|
+
try {
|
|
473
|
+
renameSync(tmp, path);
|
|
474
|
+
}
|
|
475
|
+
catch (err) {
|
|
476
|
+
rmSync(tmp, { force: true });
|
|
477
|
+
throw err;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Remove the records, then prune directories left empty between each file and `upTo`
|
|
482
|
+
* (exclusive). Never removes a non-empty directory — a nested skill living under a disabled
|
|
483
|
+
* parent's directory stays exactly where it is.
|
|
484
|
+
*/
|
|
485
|
+
export function removeFiles(files, upTo) {
|
|
486
|
+
for (const f of files)
|
|
487
|
+
rmSync(f.abs, { force: true });
|
|
488
|
+
for (const f of files)
|
|
489
|
+
pruneEmptyDirs(dirname(f.abs), upTo);
|
|
490
|
+
}
|
|
491
|
+
/** Remove `dir` and its ancestors while they are empty, stopping at `upTo` (which is kept). */
|
|
492
|
+
export function pruneEmptyDirs(dir, upTo) {
|
|
493
|
+
let cur = dir;
|
|
494
|
+
for (;;) {
|
|
495
|
+
const rel = relative(upTo, cur);
|
|
496
|
+
if (rel === '' || rel.startsWith('..'))
|
|
497
|
+
return;
|
|
498
|
+
try {
|
|
499
|
+
rmdirSync(cur); // ENOTEMPTY / ENOENT both end the climb
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
cur = dirname(cur);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function isEnoent(err) {
|
|
508
|
+
return err.code === 'ENOENT';
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Every directory under `root` (root included, deepest first), symlinks never followed. `strict`
|
|
512
|
+
* propagates every error but ENOENT (an entry that vanished mid-walk); the lenient mode (the
|
|
513
|
+
* force-remove's) skips what it cannot list — `rmSync` reports what matters there.
|
|
514
|
+
*/
|
|
515
|
+
function directoriesUnder(root, strict) {
|
|
516
|
+
const out = [];
|
|
517
|
+
const visit = (dir) => {
|
|
518
|
+
let entries;
|
|
519
|
+
try {
|
|
520
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
if (strict && !isEnoent(err))
|
|
524
|
+
throw err;
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
for (const entry of entries) {
|
|
528
|
+
if (entry.isSymbolicLink() || !entry.isDirectory())
|
|
529
|
+
continue;
|
|
530
|
+
visit(join(dir, entry.name));
|
|
531
|
+
}
|
|
532
|
+
out.push(dir);
|
|
533
|
+
};
|
|
534
|
+
try {
|
|
535
|
+
if (!lstatSync(root).isDirectory())
|
|
536
|
+
return out;
|
|
537
|
+
}
|
|
538
|
+
catch (err) {
|
|
539
|
+
if (strict && !isEnoent(err))
|
|
540
|
+
throw err;
|
|
541
|
+
return out;
|
|
542
|
+
}
|
|
543
|
+
visit(root);
|
|
544
|
+
return out;
|
|
545
|
+
}
|
|
546
|
+
const WRITE_BITS = 0o222;
|
|
547
|
+
/**
|
|
548
|
+
* Strip the write bits from every directory and file under `root` — the shared per-baseline
|
|
549
|
+
* `.venv` is read-only by contract (design v3 §4): a worker's `uv run` from a snapshot must not
|
|
550
|
+
* install into, or remove from, an env every other snapshot links; a published snapshot is locked
|
|
551
|
+
* the same way (immutable by contract, verified by hash). Files first, then directories (deepest
|
|
552
|
+
* first), so the walk never has to re-open a directory it already closed. A permission failure
|
|
553
|
+
* PROPAGATES (codex round 2 on #480: "silently swallows permission failures while claiming to
|
|
554
|
+
* lock") — a tree this cannot lock is not locked, and the caller decides what that means (the
|
|
555
|
+
* store treats an unlockable env as a failed provisioning, blocking the publish). Only an entry
|
|
556
|
+
* that vanished mid-walk (ENOENT) is tolerated. A no-op on platforms without POSIX modes.
|
|
557
|
+
*/
|
|
558
|
+
export function makeTreeReadOnly(root) {
|
|
559
|
+
if (process.platform === 'win32')
|
|
560
|
+
return;
|
|
561
|
+
for (const dir of directoriesUnder(root, true)) {
|
|
562
|
+
let entries;
|
|
563
|
+
try {
|
|
564
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
if (isEnoent(err))
|
|
568
|
+
continue;
|
|
569
|
+
throw err;
|
|
570
|
+
}
|
|
571
|
+
for (const entry of entries) {
|
|
572
|
+
if (!entry.isFile())
|
|
573
|
+
continue;
|
|
574
|
+
const p = join(dir, entry.name);
|
|
575
|
+
try {
|
|
576
|
+
chmodSync(p, lstatSync(p).mode & 0o777 & ~WRITE_BITS);
|
|
577
|
+
}
|
|
578
|
+
catch (err) {
|
|
579
|
+
if (!isEnoent(err))
|
|
580
|
+
throw err;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
chmodSync(dir, lstatSync(dir).mode & 0o777 & ~WRITE_BITS);
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
if (!isEnoent(err))
|
|
588
|
+
throw err;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* `rmSync(root, { recursive: true, force: true })` that also removes a tree `makeTreeReadOnly`
|
|
594
|
+
* locked — OR a partial env whose lock FAILED, which can leave an UNLISTABLE directory (a `uv sync`
|
|
595
|
+
* that produced a `0o000`/`0o111` dir the lock choked on; codex round 3). Each directory has its
|
|
596
|
+
* owner `rwx` restored TOP-DOWN, before it is enumerated, so an unlistable dir becomes traversable
|
|
597
|
+
* and removable (unlinking an entry needs a writable, listable parent, whatever the entry's own
|
|
598
|
+
* mode). A missing root is a no-op.
|
|
599
|
+
*/
|
|
600
|
+
export function removeTreeForce(root) {
|
|
601
|
+
restoreDirPermsTopDown(root);
|
|
602
|
+
rmSync(root, { recursive: true, force: true });
|
|
603
|
+
}
|
|
604
|
+
/** Give every directory under `dir` (`dir` included, symlinks never followed) owner `rwx` — restored
|
|
605
|
+
* before the dir is read, so even a `0o000` directory can be enumerated and removed. Best-effort. */
|
|
606
|
+
function restoreDirPermsTopDown(dir) {
|
|
607
|
+
let st;
|
|
608
|
+
try {
|
|
609
|
+
st = lstatSync(dir);
|
|
610
|
+
}
|
|
611
|
+
catch {
|
|
612
|
+
return; // gone already
|
|
613
|
+
}
|
|
614
|
+
if (st.isSymbolicLink() || !st.isDirectory())
|
|
615
|
+
return;
|
|
616
|
+
try {
|
|
617
|
+
chmodSync(dir, (st.mode & 0o777) | 0o700);
|
|
618
|
+
}
|
|
619
|
+
catch {
|
|
620
|
+
/* not ours to chmod — rmSync below reports what matters */
|
|
621
|
+
}
|
|
622
|
+
let entries;
|
|
623
|
+
try {
|
|
624
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
return; // still unreadable (not ours) — rmSync reports it
|
|
628
|
+
}
|
|
629
|
+
for (const entry of entries) {
|
|
630
|
+
if (entry.isSymbolicLink() || !entry.isDirectory())
|
|
631
|
+
continue;
|
|
632
|
+
restoreDirPermsTopDown(join(dir, entry.name));
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/** Unlink one path without following it (a link is removed, its target untouched). */
|
|
636
|
+
export function unlinkNoFollow(path) {
|
|
637
|
+
try {
|
|
638
|
+
unlinkSync(path);
|
|
639
|
+
}
|
|
640
|
+
catch (err) {
|
|
641
|
+
if (err.code !== 'ENOENT')
|
|
642
|
+
throw err;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/skills/tree.ts"],"names":[],"mappings":"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"}
|