linksee-memory 0.17.0 → 0.17.2
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 +260 -1081
- package/dist/bin/guard-hook.js +19 -4
- package/dist/bin/migrate-legacy.d.ts +33 -0
- package/dist/bin/migrate-legacy.js +501 -0
- package/dist/bin/runtime.d.ts +52 -0
- package/dist/bin/runtime.js +381 -0
- package/dist/bin/setup.js +191 -76
- package/dist/bin/share-draft.js +28 -28
- package/dist/bin/sync-session.js +10 -1
- package/dist/db/migrate.d.ts +82 -1
- package/dist/db/migrate.js +250 -40
- package/dist/lib/consolidate.d.ts +9 -0
- package/dist/lib/consolidate.js +14 -0
- package/dist/lib/drift-anchors.js +3 -3
- package/dist/lib/drift-detection.js +20 -20
- package/dist/lib/drift-view.js +16 -16
- package/dist/lib/guard-wiring.d.ts +47 -1
- package/dist/lib/guard-wiring.js +114 -11
- package/dist/lib/hook-runtime.d.ts +41 -0
- package/dist/lib/hook-runtime.js +202 -0
- package/dist/lib/map-import.js +17 -17
- package/dist/lib/native-hint.d.ts +5 -0
- package/dist/lib/native-hint.js +42 -0
- package/dist/lib/settings-file.d.ts +23 -0
- package/dist/lib/settings-file.js +137 -0
- package/dist/lib/test-faults.d.ts +3 -0
- package/dist/lib/test-faults.js +30 -0
- package/dist/mcp/prompts.js +59 -59
- package/dist/mcp/resources.js +7 -7
- package/dist/mcp/sampling.js +20 -20
- package/dist/mcp/server.js +182 -160
- package/dist/skill/SKILL.md +6 -14
- package/package.json +107 -107
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// linksee-memory runtime list | prune [--yes --scope-confirmed] [--settings <file>]… (0.17.2, L-1-148)
|
|
3
|
+
//
|
|
4
|
+
// setup (run through npx) installs each version under <memory dir>/runtime/<version>/ (about
|
|
5
|
+
// 35 MB each) and never deletes older ones. This command lists them and deletes, only when asked
|
|
6
|
+
// twice over (--yes AND --scope-confirmed), the versions nothing is confirmed to reference.
|
|
7
|
+
//
|
|
8
|
+
// Where a reference can be:
|
|
9
|
+
// user: ~/.claude/settings.json, ~/.claude/settings.local.json, ~/.claude.json, ~/.codex/config.toml
|
|
10
|
+
// project: <cwd>/.claude/settings.json, <cwd>/.claude/settings.local.json
|
|
11
|
+
// extra: every --settings <file>
|
|
12
|
+
// Project settings of OTHER repos (where `setup --project` was run) cannot be found from here.
|
|
13
|
+
// So --yes alone deletes nothing: --scope-confirmed says "I checked the other repos' .claude/
|
|
14
|
+
// settings*.json, or passed them all with --settings" (Codex review of #19).
|
|
15
|
+
//
|
|
16
|
+
// How a file is read (Codex review of #19: no raw-text grep as the only test):
|
|
17
|
+
// • JSON: parsed; every string (keys and values, at any depth) is checked for runtime/<version>
|
|
18
|
+
// after normalizing \ → /. Parse failure → could not confirm.
|
|
19
|
+
// • TOML (~/.codex/config.toml): a deliberately small line reader (Codex second review of #19:
|
|
20
|
+
// do not be clever). The ONLY lines it accepts are: blank, `# comment`, a `[table]` /
|
|
21
|
+
// `[[array]]` header of bare keys, and `bare.key = <value>` where the value is one string
|
|
22
|
+
// ("…" with escapes decoded, or '…'), a one-line array of such strings, a number, or
|
|
23
|
+
// true/false. Anything else - a quoted key, an inline table, a multi-line array or string, a
|
|
24
|
+
// date, an unknown form - makes the whole file "could not confirm". Every string it read
|
|
25
|
+
// (whatever the key) is checked for a runtime path.
|
|
26
|
+
// • In both, the raw text is ALSO searched (a match there only keeps a version, never deletes one).
|
|
27
|
+
// A default file that does not exist (ENOENT) references nothing. Anything else that cannot be
|
|
28
|
+
// confirmed → nothing is deleted, the reason is printed, exit 1.
|
|
29
|
+
// Never touched: .tmp-* (an install in progress), *.old-* (kept from a failed same-version swap),
|
|
30
|
+
// any name that is not a version, and the version this command runs from.
|
|
31
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
32
|
+
import { homedir } from 'node:os';
|
|
33
|
+
import { join, resolve } from 'node:path';
|
|
34
|
+
import { fileURLToPath } from 'node:url';
|
|
35
|
+
import { dirBytes, formatBytes } from '../lib/hook-runtime.js';
|
|
36
|
+
import { renameGuarded, rmGuarded } from '../lib/test-faults.js';
|
|
37
|
+
const VERSION_DIR = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?$/;
|
|
38
|
+
export function defaultSources(home, cwd) {
|
|
39
|
+
return [
|
|
40
|
+
join(home, '.claude', 'settings.json'),
|
|
41
|
+
join(home, '.claude', 'settings.local.json'),
|
|
42
|
+
join(home, '.claude.json'),
|
|
43
|
+
join(home, '.codex', 'config.toml'),
|
|
44
|
+
join(cwd, '.claude', 'settings.json'),
|
|
45
|
+
join(cwd, '.claude', 'settings.local.json'),
|
|
46
|
+
].map((path) => ({ path, explicit: false }));
|
|
47
|
+
}
|
|
48
|
+
export const normPath = (t) => {
|
|
49
|
+
const s = t.replace(/\\+/g, '/');
|
|
50
|
+
return process.platform === 'win32' ? s.toLowerCase() : s;
|
|
51
|
+
};
|
|
52
|
+
function jsonStrings(v, out) {
|
|
53
|
+
if (typeof v === 'string')
|
|
54
|
+
out.push(v);
|
|
55
|
+
else if (Array.isArray(v))
|
|
56
|
+
for (const x of v)
|
|
57
|
+
jsonStrings(x, out);
|
|
58
|
+
else if (v && typeof v === 'object')
|
|
59
|
+
for (const [k, x] of Object.entries(v)) {
|
|
60
|
+
out.push(k);
|
|
61
|
+
jsonStrings(x, out);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Parse one TOML string token at s[i]; returns [value, nextIndex] or null. */
|
|
65
|
+
function tomlString(s, i) {
|
|
66
|
+
if (s[i] === "'") {
|
|
67
|
+
if (s.startsWith("'''", i))
|
|
68
|
+
return null; // multi-line literal: not handled → unconfirmable
|
|
69
|
+
const j = s.indexOf("'", i + 1);
|
|
70
|
+
return j < 0 ? null : [s.slice(i + 1, j), j + 1];
|
|
71
|
+
}
|
|
72
|
+
if (s[i] !== '"' || s.startsWith('"""', i))
|
|
73
|
+
return null;
|
|
74
|
+
let out = '';
|
|
75
|
+
let j = i + 1;
|
|
76
|
+
while (j < s.length) {
|
|
77
|
+
const c = s[j];
|
|
78
|
+
if (c === '"')
|
|
79
|
+
return [out, j + 1];
|
|
80
|
+
if (c === '\\') {
|
|
81
|
+
const n = s[j + 1];
|
|
82
|
+
const map = { '"': '"', '\\': '\\', '/': '/', b: '\b', t: '\t', n: '\n', f: '\f', r: '\r' };
|
|
83
|
+
if (n in map) {
|
|
84
|
+
out += map[n];
|
|
85
|
+
j += 2;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (n === 'u' || n === 'U') {
|
|
89
|
+
const len = n === 'u' ? 4 : 8;
|
|
90
|
+
const hex = s.slice(j + 2, j + 2 + len);
|
|
91
|
+
if (!/^[0-9a-fA-F]+$/.test(hex) || hex.length !== len)
|
|
92
|
+
return null;
|
|
93
|
+
out += String.fromCodePoint(parseInt(hex, 16));
|
|
94
|
+
j += 2 + len;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
out += c;
|
|
100
|
+
j++;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const BARE = '[A-Za-z0-9_-]+(?:\\s*\\.\\s*[A-Za-z0-9_-]+)*';
|
|
105
|
+
const TOML_HEADER = new RegExp(`^\\[\\[?\\s*${BARE}\\s*\\]\\]?\\s*(#.*)?$`);
|
|
106
|
+
const TOML_KV = new RegExp(`^(${BARE})\\s*=\\s*(.*)$`);
|
|
107
|
+
const TOML_SCALAR = /^(?:true|false|[+-]?(?:0|[1-9](?:_?\d)*)(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d+)?)/;
|
|
108
|
+
/**
|
|
109
|
+
* Strict, small TOML line reader. Returns every string value it read, or an error naming the first
|
|
110
|
+
* line it does not accept (then the caller treats the file as "could not confirm").
|
|
111
|
+
*/
|
|
112
|
+
export function tomlStrings(text) {
|
|
113
|
+
const strings = [];
|
|
114
|
+
const lines = text.replace(/^\uFEFF/, '').split(/\r?\n/);
|
|
115
|
+
for (let n = 0; n < lines.length; n++) {
|
|
116
|
+
const line = lines[n].trim();
|
|
117
|
+
const bad = (why) => ({ strings, error: `line ${n + 1}: ${why}` });
|
|
118
|
+
if (line === '' || line.startsWith('#'))
|
|
119
|
+
continue;
|
|
120
|
+
if (line.startsWith('[')) {
|
|
121
|
+
if (TOML_HEADER.test(line))
|
|
122
|
+
continue;
|
|
123
|
+
return bad('not a [table] header of bare keys');
|
|
124
|
+
}
|
|
125
|
+
const m = line.match(TOML_KV);
|
|
126
|
+
if (!m)
|
|
127
|
+
return bad('not `bare_key = value` (quoted keys are not read)');
|
|
128
|
+
const rest = m[2];
|
|
129
|
+
let i = 0;
|
|
130
|
+
const skip = () => { while (i < rest.length && (rest[i] === ' ' || rest[i] === '\t'))
|
|
131
|
+
i++; };
|
|
132
|
+
const endOk = () => { skip(); return i >= rest.length || rest[i] === '#'; };
|
|
133
|
+
if (rest[0] === '"' || rest[0] === "'") {
|
|
134
|
+
const t = tomlString(rest, 0);
|
|
135
|
+
if (!t)
|
|
136
|
+
return bad('a string it cannot read (multi-line or unterminated)');
|
|
137
|
+
strings.push(t[0]);
|
|
138
|
+
i = t[1];
|
|
139
|
+
}
|
|
140
|
+
else if (rest[0] === '[') {
|
|
141
|
+
i = 1;
|
|
142
|
+
skip();
|
|
143
|
+
while (rest[i] !== ']') {
|
|
144
|
+
const t = tomlString(rest, i);
|
|
145
|
+
if (!t)
|
|
146
|
+
return bad('an array that is not one line of strings');
|
|
147
|
+
strings.push(t[0]);
|
|
148
|
+
i = t[1];
|
|
149
|
+
skip();
|
|
150
|
+
if (rest[i] === ',') {
|
|
151
|
+
i++;
|
|
152
|
+
skip();
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (rest[i] !== ']')
|
|
156
|
+
return bad('an array that is not one line of strings');
|
|
157
|
+
}
|
|
158
|
+
i++;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const sm = rest.match(TOML_SCALAR);
|
|
162
|
+
if (!sm)
|
|
163
|
+
return bad('a value type it does not read (inline table, date, ...)');
|
|
164
|
+
i = sm[0].length;
|
|
165
|
+
}
|
|
166
|
+
if (!endOk())
|
|
167
|
+
return bad('unexpected text after the value');
|
|
168
|
+
}
|
|
169
|
+
return { strings };
|
|
170
|
+
}
|
|
171
|
+
/** Read every source into normalized strings, or say why it could not be confirmed. */
|
|
172
|
+
export function readSources(sources) {
|
|
173
|
+
const texts = [];
|
|
174
|
+
const problems = [];
|
|
175
|
+
for (const s of sources) {
|
|
176
|
+
let raw;
|
|
177
|
+
try {
|
|
178
|
+
raw = readFileSync(s.path, 'utf8');
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
const code = e?.code;
|
|
182
|
+
if (code === 'ENOENT' && !s.explicit)
|
|
183
|
+
continue; // absent → references nothing
|
|
184
|
+
problems.push(`${s.path}: ${code === 'ENOENT' ? 'not found (passed with --settings)' : `could not read (${code ?? e?.message})`}`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const strings = [raw];
|
|
188
|
+
if (/\.toml$/i.test(s.path)) {
|
|
189
|
+
const t = tomlStrings(raw);
|
|
190
|
+
if (t.error) {
|
|
191
|
+
problems.push(`${s.path}: could not read as TOML (${t.error})`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
strings.push(...t.strings);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
let parsed;
|
|
198
|
+
try {
|
|
199
|
+
parsed = JSON.parse(raw.replace(/^/, ''));
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
problems.push(`${s.path}: not valid JSON (${e?.message?.split('\n')[0]})`);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
jsonStrings(parsed, strings);
|
|
206
|
+
}
|
|
207
|
+
texts.push({ path: s.path, strings: strings.map(normPath) });
|
|
208
|
+
}
|
|
209
|
+
return { texts, problems };
|
|
210
|
+
}
|
|
211
|
+
export function listRuntimes(memoryDir) {
|
|
212
|
+
const base = join(memoryDir, 'runtime');
|
|
213
|
+
if (!existsSync(base))
|
|
214
|
+
return { base, versions: [], others: [] };
|
|
215
|
+
let names;
|
|
216
|
+
try {
|
|
217
|
+
names = readdirSync(base);
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
return { base, versions: [], others: [], error: e?.message };
|
|
221
|
+
}
|
|
222
|
+
const versions = [];
|
|
223
|
+
const others = [];
|
|
224
|
+
for (const n of names.sort()) {
|
|
225
|
+
let dir = false;
|
|
226
|
+
try {
|
|
227
|
+
dir = statSync(join(base, n)).isDirectory();
|
|
228
|
+
}
|
|
229
|
+
catch { /* treat as other */ }
|
|
230
|
+
(dir && VERSION_DIR.test(n) ? versions : others).push(n);
|
|
231
|
+
}
|
|
232
|
+
return { base, versions, others };
|
|
233
|
+
}
|
|
234
|
+
export function pruneRuntimes(o) {
|
|
235
|
+
const log = o.log ?? ((l) => console.log(l));
|
|
236
|
+
const { base, versions, others, error } = listRuntimes(o.memoryDir);
|
|
237
|
+
if (error) {
|
|
238
|
+
log(`Could not list ${base}: ${error}. Nothing deleted.`);
|
|
239
|
+
return { code: 1, entries: [], problems: [error] };
|
|
240
|
+
}
|
|
241
|
+
if (versions.length === 0) {
|
|
242
|
+
log(`No runtime versions under ${base}.`);
|
|
243
|
+
for (const n of others)
|
|
244
|
+
log(` (left alone) ${n}`);
|
|
245
|
+
return { code: 0, entries: [], problems: [] };
|
|
246
|
+
}
|
|
247
|
+
const { texts, problems } = readSources(o.sources);
|
|
248
|
+
const self = o.selfRoot ? normPath(safeReal(o.selfRoot)) : '';
|
|
249
|
+
const entries = versions.map((v) => {
|
|
250
|
+
const dir = join(base, v);
|
|
251
|
+
const needle = `runtime/${normPath(v)}`;
|
|
252
|
+
const hit = (s) => s.includes(needle + '/') || s.endsWith(needle) || s.includes(needle + '"') || s.includes(needle + "'");
|
|
253
|
+
const referencedBy = texts.filter((t) => t.strings.some(hit)).map((t) => t.path);
|
|
254
|
+
const e = { version: v, dir, bytes: dirBytes(dir), referencedBy, decision: 'delete' };
|
|
255
|
+
const dirNorm = normPath(safeReal(dir)) + '/';
|
|
256
|
+
if (self && (self + '/').startsWith(dirNorm)) {
|
|
257
|
+
e.decision = 'keep-running';
|
|
258
|
+
e.reason = 'this command is running from it';
|
|
259
|
+
}
|
|
260
|
+
else if (referencedBy.length) {
|
|
261
|
+
e.decision = 'keep-referenced';
|
|
262
|
+
e.reason = `referenced by ${referencedBy.join(', ')}`;
|
|
263
|
+
}
|
|
264
|
+
else if (problems.length) {
|
|
265
|
+
e.decision = 'keep-unconfirmed';
|
|
266
|
+
e.reason = 'could not confirm that nothing references it (see below)';
|
|
267
|
+
}
|
|
268
|
+
return e;
|
|
269
|
+
});
|
|
270
|
+
const willDelete = o.yes && !!o.scopeConfirmed && problems.length === 0;
|
|
271
|
+
log(`Runtimes under ${base}:`);
|
|
272
|
+
for (const e of entries) {
|
|
273
|
+
const what = e.decision === 'delete'
|
|
274
|
+
? (willDelete ? 'delete' : 'no reference found (deletable with --yes --scope-confirmed)')
|
|
275
|
+
: `keep — ${e.reason}`;
|
|
276
|
+
log(` ${e.version.padEnd(10)} ${formatBytes(e.bytes).padStart(7)} ${what}`);
|
|
277
|
+
}
|
|
278
|
+
for (const n of others)
|
|
279
|
+
log(` (left alone) ${n}`);
|
|
280
|
+
if (problems.length) {
|
|
281
|
+
log(`Could not confirm references, so nothing is deleted:`);
|
|
282
|
+
for (const p of problems)
|
|
283
|
+
log(` • ${p}`);
|
|
284
|
+
}
|
|
285
|
+
log(`Checked: ${o.sources.map((s) => s.path).join(', ')}.`);
|
|
286
|
+
log(`Not checked: project settings of other repos. If you ran \`setup --project\` elsewhere, pass each repo's .claude/settings.json (and settings.local.json) with --settings.`);
|
|
287
|
+
let code = problems.length ? 1 : 0;
|
|
288
|
+
if (o.yes && !o.scopeConfirmed) {
|
|
289
|
+
log(`Nothing deleted: add --scope-confirmed once you have checked (or passed with --settings) the .claude/settings*.json of every other repo where you ran setup --project.`);
|
|
290
|
+
return { code: 1, entries, problems };
|
|
291
|
+
}
|
|
292
|
+
if (willDelete) {
|
|
293
|
+
for (const e of entries.filter((x) => x.decision === 'delete')) {
|
|
294
|
+
// Rename first so the version disappears at once (no half-deleted runtime under its own
|
|
295
|
+
// name), then remove the renamed folder.
|
|
296
|
+
const aside = join(base, `.pruning-${e.version}-${process.pid}`);
|
|
297
|
+
try {
|
|
298
|
+
renameGuarded(e.dir, aside);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
e.decision = 'delete-failed';
|
|
302
|
+
e.reason = err?.message;
|
|
303
|
+
code = 1;
|
|
304
|
+
log(` could not delete ${e.version} (${e.reason}); left as it was`);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
rmGuarded(aside, { recursive: true, force: true });
|
|
309
|
+
if (existsSync(aside))
|
|
310
|
+
throw new Error('folder still there');
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
e.decision = 'delete-failed';
|
|
314
|
+
e.reason = `moved to ${aside} but not fully removed (${err?.message})`;
|
|
315
|
+
code = 1;
|
|
316
|
+
log(` ${e.version}: ${e.reason}; delete that folder by hand`);
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
e.decision = 'deleted';
|
|
320
|
+
log(` deleted ${e.version} (${formatBytes(e.bytes)})`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return { code, entries, problems };
|
|
324
|
+
}
|
|
325
|
+
function safeReal(p) {
|
|
326
|
+
try {
|
|
327
|
+
return realpathSync(p);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return resolve(p);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function usage() {
|
|
334
|
+
return `Usage: npx -y linksee-memory runtime list [--settings <file>]...
|
|
335
|
+
npx -y linksee-memory runtime prune [--yes --scope-confirmed] [--settings <file>]...
|
|
336
|
+
|
|
337
|
+
Lists <memory dir>/runtime/<version> (installed by setup when run through npx) with sizes and
|
|
338
|
+
what references each one. prune deletes only versions no settings file references, and only with
|
|
339
|
+
both --yes and --scope-confirmed (= you checked, or passed with --settings, the .claude/settings*.json
|
|
340
|
+
of every other repo where you ran setup --project). If any settings file cannot be read or parsed,
|
|
341
|
+
nothing is deleted.`;
|
|
342
|
+
}
|
|
343
|
+
function main(argv) {
|
|
344
|
+
const [cmd, ...rest] = argv;
|
|
345
|
+
if (!cmd || cmd === '--help' || cmd === '-h' || (cmd !== 'list' && cmd !== 'prune')) {
|
|
346
|
+
console.log(usage());
|
|
347
|
+
return cmd && cmd !== '--help' && cmd !== '-h' ? 1 : 0;
|
|
348
|
+
}
|
|
349
|
+
const extra = [];
|
|
350
|
+
let yes = false;
|
|
351
|
+
let scopeConfirmed = false;
|
|
352
|
+
for (let i = 0; i < rest.length; i++) {
|
|
353
|
+
if (rest[i] === '--yes' && cmd === 'prune')
|
|
354
|
+
yes = true;
|
|
355
|
+
else if (rest[i] === '--scope-confirmed' && cmd === 'prune')
|
|
356
|
+
scopeConfirmed = true;
|
|
357
|
+
else if (rest[i] === '--settings' && rest[i + 1])
|
|
358
|
+
extra.push({ path: resolve(rest[++i]), explicit: true });
|
|
359
|
+
else {
|
|
360
|
+
console.error(`Unknown argument: ${rest[i]}\n\n${usage()}`);
|
|
361
|
+
return 1;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const home = homedir();
|
|
365
|
+
const memoryDir = process.env.LINKSEE_MEMORY_DIR ?? join(home, '.linksee-memory');
|
|
366
|
+
const selfRoot = join(fileURLToPath(import.meta.url), '..', '..', '..');
|
|
367
|
+
return pruneRuntimes({ memoryDir, sources: [...defaultSources(home, process.cwd()), ...extra], yes, scopeConfirmed, selfRoot }).code;
|
|
368
|
+
}
|
|
369
|
+
const isMain = (() => {
|
|
370
|
+
try {
|
|
371
|
+
const a = process.argv[1] ? realpathSync(process.argv[1]) : '';
|
|
372
|
+
const b = realpathSync(fileURLToPath(import.meta.url));
|
|
373
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
})();
|
|
379
|
+
if (isMain)
|
|
380
|
+
process.exit(main(process.argv.slice(2)));
|
|
381
|
+
//# sourceMappingURL=runtime.js.map
|