claudekit-cli 3.34.1-dev.3 → 3.34.1-dev.5
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/index.js +155 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -44585,10 +44585,38 @@ var init_pnpm_detector = __esm(() => {
|
|
|
44585
44585
|
});
|
|
44586
44586
|
|
|
44587
44587
|
// src/domains/installation/package-managers/detection-core.ts
|
|
44588
|
-
import { existsSync as existsSync17 } from "node:fs";
|
|
44588
|
+
import { existsSync as existsSync17, realpathSync } from "node:fs";
|
|
44589
44589
|
import { chmod as chmod2, mkdir as mkdir6, readFile as readFile13, writeFile as writeFile7 } from "node:fs/promises";
|
|
44590
44590
|
import { platform as platform4 } from "node:os";
|
|
44591
|
-
import { join as join23 } from "node:path";
|
|
44591
|
+
import { join as join23, sep } from "node:path";
|
|
44592
|
+
function detectFromBinaryPath() {
|
|
44593
|
+
try {
|
|
44594
|
+
const scriptPath = process.argv[1];
|
|
44595
|
+
if (!scriptPath)
|
|
44596
|
+
return "unknown";
|
|
44597
|
+
let resolvedPath;
|
|
44598
|
+
try {
|
|
44599
|
+
resolvedPath = realpathSync(scriptPath);
|
|
44600
|
+
} catch {
|
|
44601
|
+
resolvedPath = scriptPath;
|
|
44602
|
+
}
|
|
44603
|
+
const normalized = resolvedPath.split(sep).join("/").toLowerCase();
|
|
44604
|
+
logger.verbose(`Binary path resolved: ${normalized}`);
|
|
44605
|
+
if (normalized.includes("/.bun/install/") || normalized.includes("/bun/install/global/")) {
|
|
44606
|
+
return "bun";
|
|
44607
|
+
}
|
|
44608
|
+
if (normalized.includes("/pnpm/global/") || normalized.includes("/.local/share/pnpm/")) {
|
|
44609
|
+
return "pnpm";
|
|
44610
|
+
}
|
|
44611
|
+
if (normalized.includes("/yarn/global/") || normalized.includes("/.config/yarn/")) {
|
|
44612
|
+
return "yarn";
|
|
44613
|
+
}
|
|
44614
|
+
if (normalized.includes("/npm/node_modules/") || normalized.includes("/usr/local/lib/node_modules/") || normalized.includes("/usr/lib/node_modules/") || normalized.includes("/opt/homebrew/lib/node_modules/") || normalized.includes("/.nvm/versions/node/") || normalized.includes("/n/versions/node/") || normalized.includes("/appdata/roaming/npm/")) {
|
|
44615
|
+
return "npm";
|
|
44616
|
+
}
|
|
44617
|
+
} catch {}
|
|
44618
|
+
return "unknown";
|
|
44619
|
+
}
|
|
44592
44620
|
function detectFromEnv() {
|
|
44593
44621
|
const userAgent = process.env.npm_config_user_agent;
|
|
44594
44622
|
if (userAgent) {
|
|
@@ -44605,13 +44633,14 @@ function detectFromEnv() {
|
|
|
44605
44633
|
const execPath = process.env.npm_execpath;
|
|
44606
44634
|
if (execPath) {
|
|
44607
44635
|
logger.debug(`Detected exec path: ${execPath}`);
|
|
44608
|
-
|
|
44636
|
+
const normalizedExec = execPath.replace(/\\/g, "/").toLowerCase();
|
|
44637
|
+
if (/\/bun([/.]|$)/.test(normalizedExec) || normalizedExec.startsWith("bun"))
|
|
44609
44638
|
return "bun";
|
|
44610
|
-
if (
|
|
44639
|
+
if (/\/yarn([/.]|$)/.test(normalizedExec) || normalizedExec.startsWith("yarn"))
|
|
44611
44640
|
return "yarn";
|
|
44612
|
-
if (
|
|
44641
|
+
if (/\/pnpm([/.]|$)/.test(normalizedExec) || normalizedExec.startsWith("pnpm"))
|
|
44613
44642
|
return "pnpm";
|
|
44614
|
-
if (
|
|
44643
|
+
if (/\/npm([/.]|$)/.test(normalizedExec) || normalizedExec.startsWith("npm"))
|
|
44615
44644
|
return "npm";
|
|
44616
44645
|
}
|
|
44617
44646
|
return "unknown";
|
|
@@ -44629,8 +44658,8 @@ async function readCachedPm() {
|
|
|
44629
44658
|
return null;
|
|
44630
44659
|
}
|
|
44631
44660
|
const age = Date.now() - data.detectedAt;
|
|
44632
|
-
if (age > CACHE_TTL) {
|
|
44633
|
-
logger.debug("Cache expired, will re-detect");
|
|
44661
|
+
if (age < 0 || age > CACHE_TTL) {
|
|
44662
|
+
logger.debug(age < 0 ? "Cache timestamp in future, ignoring" : "Cache expired, will re-detect");
|
|
44634
44663
|
return null;
|
|
44635
44664
|
}
|
|
44636
44665
|
const validPms = ["npm", "bun", "yarn", "pnpm"];
|
|
@@ -44739,6 +44768,18 @@ var init_package_manager_detector = __esm(() => {
|
|
|
44739
44768
|
PackageManagerDetector = class PackageManagerDetector {
|
|
44740
44769
|
static async detect() {
|
|
44741
44770
|
logger.verbose("PackageManagerDetector: Starting detection");
|
|
44771
|
+
const binaryPm = detectFromBinaryPath();
|
|
44772
|
+
if (binaryPm !== "unknown") {
|
|
44773
|
+
logger.verbose(`PackageManagerDetector: Detected from binary path: ${binaryPm}`);
|
|
44774
|
+
const cachedPm2 = await readCachedPm();
|
|
44775
|
+
if (cachedPm2 && cachedPm2 !== binaryPm) {
|
|
44776
|
+
logger.verbose(`PackageManagerDetector: Cache says ${cachedPm2}, binary says ${binaryPm} — updating cache`);
|
|
44777
|
+
await saveCachedPm(binaryPm, PackageManagerDetector.getVersion);
|
|
44778
|
+
} else if (!cachedPm2) {
|
|
44779
|
+
await saveCachedPm(binaryPm, PackageManagerDetector.getVersion);
|
|
44780
|
+
}
|
|
44781
|
+
return binaryPm;
|
|
44782
|
+
}
|
|
44742
44783
|
const envPm = detectFromEnv();
|
|
44743
44784
|
if (envPm !== "unknown") {
|
|
44744
44785
|
logger.verbose(`PackageManagerDetector: Detected from env: ${envPm}`);
|
|
@@ -45236,7 +45277,7 @@ var package_default;
|
|
|
45236
45277
|
var init_package = __esm(() => {
|
|
45237
45278
|
package_default = {
|
|
45238
45279
|
name: "claudekit-cli",
|
|
45239
|
-
version: "3.34.1-dev.
|
|
45280
|
+
version: "3.34.1-dev.5",
|
|
45240
45281
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
45241
45282
|
type: "module",
|
|
45242
45283
|
repository: {
|
|
@@ -45551,12 +45592,15 @@ Run 'ck update' to install`, "Update Check");
|
|
|
45551
45592
|
s.stop("Update failed");
|
|
45552
45593
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
45553
45594
|
if (errorMessage.includes("EACCES") || errorMessage.includes("EPERM") || errorMessage.includes("permission") || errorMessage.includes("Access is denied")) {
|
|
45554
|
-
|
|
45595
|
+
const permHint = pm === "npm" ? `
|
|
45555
45596
|
|
|
45556
|
-
Or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally`
|
|
45597
|
+
Or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally` : "";
|
|
45598
|
+
const isWindows3 = process.platform === "win32";
|
|
45599
|
+
const elevationHint = isWindows3 ? `Run your terminal as Administrator and retry: ${updateCmd}` : `sudo ${updateCmd}`;
|
|
45600
|
+
throw new CliUpdateError(`Permission denied. Try: ${elevationHint}${permHint}`);
|
|
45557
45601
|
}
|
|
45558
45602
|
logger.error(`Update failed: ${errorMessage}`);
|
|
45559
|
-
logger.info(
|
|
45603
|
+
logger.info(`Try running: ${updateCmd}`);
|
|
45560
45604
|
throw new CliUpdateError(`Update failed: ${errorMessage}
|
|
45561
45605
|
|
|
45562
45606
|
Manual update: ${updateCmd}`);
|
|
@@ -66041,7 +66085,7 @@ init_types2();
|
|
|
66041
66085
|
|
|
66042
66086
|
// src/domains/installation/utils/path-security.ts
|
|
66043
66087
|
init_types2();
|
|
66044
|
-
import { lstatSync as lstatSync2, realpathSync } from "node:fs";
|
|
66088
|
+
import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
66045
66089
|
import { relative as relative5, resolve as resolve10 } from "node:path";
|
|
66046
66090
|
var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
|
|
66047
66091
|
function isPathSafe(basePath, targetPath) {
|
|
@@ -66049,7 +66093,7 @@ function isPathSafe(basePath, targetPath) {
|
|
|
66049
66093
|
try {
|
|
66050
66094
|
const stat10 = lstatSync2(targetPath);
|
|
66051
66095
|
if (stat10.isSymbolicLink()) {
|
|
66052
|
-
const realTarget =
|
|
66096
|
+
const realTarget = realpathSync2(targetPath);
|
|
66053
66097
|
if (!realTarget.startsWith(resolvedBase)) {
|
|
66054
66098
|
return false;
|
|
66055
66099
|
}
|
|
@@ -73832,7 +73876,7 @@ import { join as join77 } from "node:path";
|
|
|
73832
73876
|
|
|
73833
73877
|
// src/domains/installation/deletion-handler.ts
|
|
73834
73878
|
import { existsSync as existsSync35, lstatSync as lstatSync3, readdirSync as readdirSync2, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
73835
|
-
import { dirname as dirname14, join as join64, relative as relative7, resolve as resolve12, sep } from "node:path";
|
|
73879
|
+
import { dirname as dirname14, join as join64, relative as relative7, resolve as resolve12, sep as sep2 } from "node:path";
|
|
73836
73880
|
|
|
73837
73881
|
// src/services/file-operations/manifest/manifest-reader.ts
|
|
73838
73882
|
init_metadata_migration();
|
|
@@ -74071,7 +74115,7 @@ function cleanupEmptyDirectories(filePath, claudeDir2) {
|
|
|
74071
74115
|
function deletePath(fullPath, claudeDir2) {
|
|
74072
74116
|
const normalizedPath = resolve12(fullPath);
|
|
74073
74117
|
const normalizedClaudeDir = resolve12(claudeDir2);
|
|
74074
|
-
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${
|
|
74118
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep2}`) && normalizedPath !== normalizedClaudeDir) {
|
|
74075
74119
|
throw new Error(`Path traversal detected: ${fullPath}`);
|
|
74076
74120
|
}
|
|
74077
74121
|
try {
|
|
@@ -74145,7 +74189,7 @@ async function handleDeletions(sourceMetadata, claudeDir2) {
|
|
|
74145
74189
|
const fullPath = join64(claudeDir2, path11);
|
|
74146
74190
|
const normalizedPath = resolve12(fullPath);
|
|
74147
74191
|
const normalizedClaudeDir = resolve12(claudeDir2);
|
|
74148
|
-
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${
|
|
74192
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep2}`)) {
|
|
74149
74193
|
logger.warning(`Skipping invalid path: ${path11}`);
|
|
74150
74194
|
result.errors.push(path11);
|
|
74151
74195
|
continue;
|
|
@@ -75168,8 +75212,8 @@ var path11 = {
|
|
|
75168
75212
|
win32: { sep: "\\" },
|
|
75169
75213
|
posix: { sep: "/" }
|
|
75170
75214
|
};
|
|
75171
|
-
var
|
|
75172
|
-
minimatch.sep =
|
|
75215
|
+
var sep3 = defaultPlatform === "win32" ? path11.win32.sep : path11.posix.sep;
|
|
75216
|
+
minimatch.sep = sep3;
|
|
75173
75217
|
var GLOBSTAR = Symbol("globstar **");
|
|
75174
75218
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
75175
75219
|
var qmark2 = "[^/]";
|
|
@@ -75850,6 +75894,9 @@ class FileScanner {
|
|
|
75850
75894
|
}
|
|
75851
75895
|
}
|
|
75852
75896
|
|
|
75897
|
+
// src/domains/installation/merger/settings-processor.ts
|
|
75898
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
75899
|
+
|
|
75853
75900
|
// src/domains/config/installed-settings-tracker.ts
|
|
75854
75901
|
init_shared();
|
|
75855
75902
|
import { existsSync as existsSync36 } from "node:fs";
|
|
@@ -75948,14 +75995,17 @@ init_settings_merger();
|
|
|
75948
75995
|
init_environment();
|
|
75949
75996
|
init_logger();
|
|
75950
75997
|
var import_fs_extra11 = __toESM(require_lib3(), 1);
|
|
75998
|
+
var import_semver2 = __toESM(require_semver2(), 1);
|
|
75951
75999
|
|
|
75952
76000
|
class SettingsProcessor {
|
|
76001
|
+
static MIN_TEAM_HOOKS_VERSION = "2.1.33";
|
|
75953
76002
|
isGlobal = false;
|
|
75954
76003
|
forceOverwriteSettings = false;
|
|
75955
76004
|
projectDir = "";
|
|
75956
76005
|
kitName = "engineer";
|
|
75957
76006
|
tracker = null;
|
|
75958
76007
|
installingKit;
|
|
76008
|
+
cachedVersion = undefined;
|
|
75959
76009
|
setGlobalFlag(isGlobal) {
|
|
75960
76010
|
this.isGlobal = isGlobal;
|
|
75961
76011
|
}
|
|
@@ -76001,8 +76051,9 @@ class SettingsProcessor {
|
|
|
76001
76051
|
} else {
|
|
76002
76052
|
const formattedContent = this.formatJsonContent(transformedSource);
|
|
76003
76053
|
await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
|
|
76054
|
+
let parsedSettings;
|
|
76004
76055
|
try {
|
|
76005
|
-
|
|
76056
|
+
parsedSettings = JSON.parse(formattedContent);
|
|
76006
76057
|
if (this.forceOverwriteSettings && destExists) {
|
|
76007
76058
|
logger.debug("Force overwrite enabled, replaced settings.json completely");
|
|
76008
76059
|
if (this.tracker) {
|
|
@@ -76011,6 +76062,7 @@ class SettingsProcessor {
|
|
|
76011
76062
|
}
|
|
76012
76063
|
await this.trackInstalledSettings(parsedSettings);
|
|
76013
76064
|
} catch {}
|
|
76065
|
+
await this.injectTeamHooksIfSupported(destFile, parsedSettings);
|
|
76014
76066
|
}
|
|
76015
76067
|
} catch (error) {
|
|
76016
76068
|
logger.error(`Failed to process settings.json: ${error}`);
|
|
@@ -76071,6 +76123,7 @@ class SettingsProcessor {
|
|
|
76071
76123
|
}
|
|
76072
76124
|
await SettingsMerger.writeSettingsFile(destFile, mergeResult.merged);
|
|
76073
76125
|
logger.success("Merged settings.json (user customizations preserved)");
|
|
76126
|
+
await this.injectTeamHooksIfSupported(destFile, mergeResult.merged);
|
|
76074
76127
|
}
|
|
76075
76128
|
async trackInstalledSettings(settings) {
|
|
76076
76129
|
if (!this.tracker)
|
|
@@ -76142,6 +76195,80 @@ class SettingsProcessor {
|
|
|
76142
76195
|
}
|
|
76143
76196
|
return transformed;
|
|
76144
76197
|
}
|
|
76198
|
+
detectClaudeCodeVersion() {
|
|
76199
|
+
if (this.cachedVersion !== undefined)
|
|
76200
|
+
return this.cachedVersion;
|
|
76201
|
+
try {
|
|
76202
|
+
const output2 = execSync4("claude --version", {
|
|
76203
|
+
encoding: "utf-8",
|
|
76204
|
+
timeout: 5000,
|
|
76205
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
76206
|
+
});
|
|
76207
|
+
const match2 = output2.match(/(\d+\.\d+\.\d+)/);
|
|
76208
|
+
this.cachedVersion = match2 ? match2[1] : null;
|
|
76209
|
+
} catch {
|
|
76210
|
+
this.cachedVersion = null;
|
|
76211
|
+
}
|
|
76212
|
+
return this.cachedVersion;
|
|
76213
|
+
}
|
|
76214
|
+
isVersionAtLeast(version, minimum) {
|
|
76215
|
+
const coerced = import_semver2.default.coerce(version);
|
|
76216
|
+
if (!coerced)
|
|
76217
|
+
return false;
|
|
76218
|
+
return import_semver2.default.gte(coerced, minimum);
|
|
76219
|
+
}
|
|
76220
|
+
async injectTeamHooksIfSupported(destFile, existingSettings) {
|
|
76221
|
+
const version = this.detectClaudeCodeVersion();
|
|
76222
|
+
if (!version) {
|
|
76223
|
+
logger.debug("Claude Code version not detected, skipping team hooks injection");
|
|
76224
|
+
return;
|
|
76225
|
+
}
|
|
76226
|
+
if (!this.isVersionAtLeast(version, SettingsProcessor.MIN_TEAM_HOOKS_VERSION)) {
|
|
76227
|
+
logger.debug(`Claude Code ${version} does not support team hooks (requires >= 2.1.33), skipping injection`);
|
|
76228
|
+
return;
|
|
76229
|
+
}
|
|
76230
|
+
logger.debug(`Claude Code ${version} detected, checking team hooks`);
|
|
76231
|
+
const settings = existingSettings ?? await SettingsMerger.readSettingsFile(destFile);
|
|
76232
|
+
if (!settings) {
|
|
76233
|
+
logger.warning("Failed to read settings file for team hooks injection");
|
|
76234
|
+
return;
|
|
76235
|
+
}
|
|
76236
|
+
const prefix = this.isGlobal ? isWindows() ? "%USERPROFILE%" : "$HOME" : isWindows() ? "%CLAUDE_PROJECT_DIR%" : "$CLAUDE_PROJECT_DIR";
|
|
76237
|
+
if (!settings.hooks) {
|
|
76238
|
+
settings.hooks = {};
|
|
76239
|
+
}
|
|
76240
|
+
let injected = false;
|
|
76241
|
+
const installedSettings = this.tracker ? await this.tracker.loadInstalledSettings() : { hooks: [], mcpServers: [] };
|
|
76242
|
+
const teamHooks = [
|
|
76243
|
+
{ event: "TaskCompleted", handler: "task-completed-handler.cjs" },
|
|
76244
|
+
{ event: "TeammateIdle", handler: "teammate-idle-handler.cjs" }
|
|
76245
|
+
];
|
|
76246
|
+
for (const { event, handler } of teamHooks) {
|
|
76247
|
+
const hookCommand = `node ${prefix}/.claude/hooks/${handler}`;
|
|
76248
|
+
const eventHooks = settings.hooks[event];
|
|
76249
|
+
if (eventHooks && eventHooks.length > 0)
|
|
76250
|
+
continue;
|
|
76251
|
+
if (this.tracker?.wasHookInstalled(hookCommand, installedSettings)) {
|
|
76252
|
+
logger.debug(`Skipping ${event} hook injection (previously removed by user)`);
|
|
76253
|
+
continue;
|
|
76254
|
+
}
|
|
76255
|
+
settings.hooks[event] = [{ hooks: [{ type: "command", command: hookCommand }] }];
|
|
76256
|
+
logger.info(`Injected ${event} hook`);
|
|
76257
|
+
injected = true;
|
|
76258
|
+
if (this.tracker) {
|
|
76259
|
+
this.tracker.trackHook(hookCommand, installedSettings);
|
|
76260
|
+
}
|
|
76261
|
+
}
|
|
76262
|
+
if (injected) {
|
|
76263
|
+
await SettingsMerger.writeSettingsFile(destFile, settings);
|
|
76264
|
+
if (this.tracker) {
|
|
76265
|
+
await this.tracker.saveInstalledSettings(installedSettings);
|
|
76266
|
+
}
|
|
76267
|
+
logger.success("Team hooks injected successfully");
|
|
76268
|
+
} else {
|
|
76269
|
+
logger.debug("Team hooks already present, no injection needed");
|
|
76270
|
+
}
|
|
76271
|
+
}
|
|
76145
76272
|
}
|
|
76146
76273
|
|
|
76147
76274
|
// src/domains/installation/merger/copy-executor.ts
|
|
@@ -81492,10 +81619,10 @@ init_dist2();
|
|
|
81492
81619
|
|
|
81493
81620
|
// src/commands/setup/phases/preflight-check.ts
|
|
81494
81621
|
init_dist2();
|
|
81495
|
-
import { execSync as
|
|
81622
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
81496
81623
|
function isGhInstalled() {
|
|
81497
81624
|
try {
|
|
81498
|
-
|
|
81625
|
+
execSync5("gh --version", { stdio: "pipe" });
|
|
81499
81626
|
return true;
|
|
81500
81627
|
} catch {
|
|
81501
81628
|
return false;
|
|
@@ -81503,7 +81630,7 @@ function isGhInstalled() {
|
|
|
81503
81630
|
}
|
|
81504
81631
|
function checkGhAuth() {
|
|
81505
81632
|
try {
|
|
81506
|
-
|
|
81633
|
+
execSync5("gh auth status", { stdio: "pipe" });
|
|
81507
81634
|
return true;
|
|
81508
81635
|
} catch {
|
|
81509
81636
|
return false;
|
|
@@ -81520,11 +81647,11 @@ function checkNodeVersion() {
|
|
|
81520
81647
|
}
|
|
81521
81648
|
function checkPython() {
|
|
81522
81649
|
try {
|
|
81523
|
-
|
|
81650
|
+
execSync5("python3 --version", { stdio: "pipe" });
|
|
81524
81651
|
return true;
|
|
81525
81652
|
} catch {
|
|
81526
81653
|
try {
|
|
81527
|
-
|
|
81654
|
+
execSync5("python --version", { stdio: "pipe" });
|
|
81528
81655
|
return true;
|
|
81529
81656
|
} catch {
|
|
81530
81657
|
return false;
|
|
@@ -82247,7 +82374,7 @@ async function detectInstallations() {
|
|
|
82247
82374
|
|
|
82248
82375
|
// src/commands/uninstall/removal-handler.ts
|
|
82249
82376
|
import { readdirSync as readdirSync5, rmSync as rmSync5 } from "node:fs";
|
|
82250
|
-
import { join as join99, resolve as resolve19, sep as
|
|
82377
|
+
import { join as join99, resolve as resolve19, sep as sep4 } from "node:path";
|
|
82251
82378
|
init_logger();
|
|
82252
82379
|
init_safe_prompts();
|
|
82253
82380
|
init_safe_spinner();
|
|
@@ -82390,7 +82517,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
|
|
|
82390
82517
|
try {
|
|
82391
82518
|
const resolvedPath = resolve19(filePath);
|
|
82392
82519
|
const resolvedBase = resolve19(baseDir);
|
|
82393
|
-
if (!resolvedPath.startsWith(resolvedBase +
|
|
82520
|
+
if (!resolvedPath.startsWith(resolvedBase + sep4) && resolvedPath !== resolvedBase) {
|
|
82394
82521
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
82395
82522
|
return false;
|
|
82396
82523
|
}
|
|
@@ -82398,7 +82525,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
|
|
|
82398
82525
|
if (stats.isSymbolicLink()) {
|
|
82399
82526
|
const realPath = await import_fs_extra37.realpath(filePath);
|
|
82400
82527
|
const resolvedReal = resolve19(realPath);
|
|
82401
|
-
if (!resolvedReal.startsWith(resolvedBase +
|
|
82528
|
+
if (!resolvedReal.startsWith(resolvedBase + sep4) && resolvedReal !== resolvedBase) {
|
|
82402
82529
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
82403
82530
|
return false;
|
|
82404
82531
|
}
|