mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 16:45:01 +00:00
refactor(hooks): dedupe install parameter wiring
This commit is contained in:
@@ -87,6 +87,43 @@ function expectInstallFailureContains(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function writeHookPackManifest(params: {
|
||||||
|
pkgDir: string;
|
||||||
|
hooks: string[];
|
||||||
|
dependencies?: Record<string, string>;
|
||||||
|
}) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(params.pkgDir, "package.json"),
|
||||||
|
JSON.stringify({
|
||||||
|
name: "@openclaw/test-hooks",
|
||||||
|
version: "0.0.1",
|
||||||
|
openclaw: { hooks: params.hooks },
|
||||||
|
...(params.dependencies ? { dependencies: params.dependencies } : {}),
|
||||||
|
}),
|
||||||
|
"utf-8",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installArchiveFixture(params: { fileName: string; contents: Buffer }) {
|
||||||
|
const fixture = writeArchiveFixture(params);
|
||||||
|
const result = await installHooksFromArchive({
|
||||||
|
archivePath: fixture.archivePath,
|
||||||
|
hooksDir: fixture.hooksDir,
|
||||||
|
});
|
||||||
|
return { fixture, result };
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectPathInstallFailureContains(
|
||||||
|
result: Awaited<ReturnType<typeof installHooksFromPath>>,
|
||||||
|
snippet: string,
|
||||||
|
) {
|
||||||
|
expect(result.ok).toBe(false);
|
||||||
|
if (result.ok) {
|
||||||
|
throw new Error("expected install failure");
|
||||||
|
}
|
||||||
|
expect(result.error).toContain(snippet);
|
||||||
|
}
|
||||||
|
|
||||||
describe("installHooksFromArchive", () => {
|
describe("installHooksFromArchive", () => {
|
||||||
it.each([
|
it.each([
|
||||||
{
|
{
|
||||||
@@ -104,10 +141,9 @@ describe("installHooksFromArchive", () => {
|
|||||||
expectedHook: "tar-hook",
|
expectedHook: "tar-hook",
|
||||||
},
|
},
|
||||||
])("installs hook packs from $name archives", async (tc) => {
|
])("installs hook packs from $name archives", async (tc) => {
|
||||||
const fixture = writeArchiveFixture({ fileName: tc.fileName, contents: tc.contents });
|
const { fixture, result } = await installArchiveFixture({
|
||||||
const result = await installHooksFromArchive({
|
fileName: tc.fileName,
|
||||||
archivePath: fixture.archivePath,
|
contents: tc.contents,
|
||||||
hooksDir: fixture.hooksDir,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.ok).toBe(true);
|
expect(result.ok).toBe(true);
|
||||||
@@ -136,10 +172,9 @@ describe("installHooksFromArchive", () => {
|
|||||||
expectedDetail: "escapes destination",
|
expectedDetail: "escapes destination",
|
||||||
},
|
},
|
||||||
])("rejects $name archives with traversal entries", async (tc) => {
|
])("rejects $name archives with traversal entries", async (tc) => {
|
||||||
const fixture = writeArchiveFixture({ fileName: tc.fileName, contents: tc.contents });
|
const { result } = await installArchiveFixture({
|
||||||
const result = await installHooksFromArchive({
|
fileName: tc.fileName,
|
||||||
archivePath: fixture.archivePath,
|
contents: tc.contents,
|
||||||
hooksDir: fixture.hooksDir,
|
|
||||||
});
|
});
|
||||||
expectInstallFailureContains(result, ["failed to extract archive", tc.expectedDetail]);
|
expectInstallFailureContains(result, ["failed to extract archive", tc.expectedDetail]);
|
||||||
});
|
});
|
||||||
@@ -154,10 +189,9 @@ describe("installHooksFromArchive", () => {
|
|||||||
contents: tarReservedIdBuffer,
|
contents: tarReservedIdBuffer,
|
||||||
},
|
},
|
||||||
])("rejects hook packs with $name", async (tc) => {
|
])("rejects hook packs with $name", async (tc) => {
|
||||||
const fixture = writeArchiveFixture({ fileName: "hooks.tar", contents: tc.contents });
|
const { result } = await installArchiveFixture({
|
||||||
const result = await installHooksFromArchive({
|
fileName: "hooks.tar",
|
||||||
archivePath: fixture.archivePath,
|
contents: tc.contents,
|
||||||
hooksDir: fixture.hooksDir,
|
|
||||||
});
|
});
|
||||||
expectInstallFailureContains(result, ["reserved path segment"]);
|
expectInstallFailureContains(result, ["reserved path segment"]);
|
||||||
});
|
});
|
||||||
@@ -169,16 +203,11 @@ describe("installHooksFromPath", () => {
|
|||||||
const stateDir = makeTempDir();
|
const stateDir = makeTempDir();
|
||||||
const pkgDir = path.join(workDir, "package");
|
const pkgDir = path.join(workDir, "package");
|
||||||
fs.mkdirSync(path.join(pkgDir, "hooks", "one-hook"), { recursive: true });
|
fs.mkdirSync(path.join(pkgDir, "hooks", "one-hook"), { recursive: true });
|
||||||
fs.writeFileSync(
|
writeHookPackManifest({
|
||||||
path.join(pkgDir, "package.json"),
|
pkgDir,
|
||||||
JSON.stringify({
|
hooks: ["./hooks/one-hook"],
|
||||||
name: "@openclaw/test-hooks",
|
dependencies: { "left-pad": "1.3.0" },
|
||||||
version: "0.0.1",
|
});
|
||||||
openclaw: { hooks: ["./hooks/one-hook"] },
|
|
||||||
dependencies: { "left-pad": "1.3.0" },
|
|
||||||
}),
|
|
||||||
"utf-8",
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(pkgDir, "hooks", "one-hook", "HOOK.md"),
|
path.join(pkgDir, "hooks", "one-hook", "HOOK.md"),
|
||||||
[
|
[
|
||||||
@@ -249,15 +278,10 @@ describe("installHooksFromPath", () => {
|
|||||||
const outsideHookDir = path.join(workDir, "outside");
|
const outsideHookDir = path.join(workDir, "outside");
|
||||||
fs.mkdirSync(pkgDir, { recursive: true });
|
fs.mkdirSync(pkgDir, { recursive: true });
|
||||||
fs.mkdirSync(outsideHookDir, { recursive: true });
|
fs.mkdirSync(outsideHookDir, { recursive: true });
|
||||||
fs.writeFileSync(
|
writeHookPackManifest({
|
||||||
path.join(pkgDir, "package.json"),
|
pkgDir,
|
||||||
JSON.stringify({
|
hooks: ["../outside"],
|
||||||
name: "@openclaw/test-hooks",
|
});
|
||||||
version: "0.0.1",
|
|
||||||
openclaw: { hooks: ["../outside"] },
|
|
||||||
}),
|
|
||||||
"utf-8",
|
|
||||||
);
|
|
||||||
fs.writeFileSync(path.join(outsideHookDir, "HOOK.md"), "---\nname: outside\n---\n", "utf-8");
|
fs.writeFileSync(path.join(outsideHookDir, "HOOK.md"), "---\nname: outside\n---\n", "utf-8");
|
||||||
fs.writeFileSync(path.join(outsideHookDir, "handler.ts"), "export default async () => {};\n");
|
fs.writeFileSync(path.join(outsideHookDir, "handler.ts"), "export default async () => {};\n");
|
||||||
|
|
||||||
@@ -266,11 +290,7 @@ describe("installHooksFromPath", () => {
|
|||||||
hooksDir: path.join(stateDir, "hooks"),
|
hooksDir: path.join(stateDir, "hooks"),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.ok).toBe(false);
|
expectPathInstallFailureContains(result, "openclaw.hooks entry escapes package directory");
|
||||||
if (result.ok) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
expect(result.error).toContain("openclaw.hooks entry escapes package directory");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects hook pack entries that escape via symlink", async () => {
|
it("rejects hook pack entries that escape via symlink", async () => {
|
||||||
@@ -288,26 +308,20 @@ describe("installHooksFromPath", () => {
|
|||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fs.writeFileSync(
|
writeHookPackManifest({
|
||||||
path.join(pkgDir, "package.json"),
|
pkgDir,
|
||||||
JSON.stringify({
|
hooks: ["./linked"],
|
||||||
name: "@openclaw/test-hooks",
|
});
|
||||||
version: "0.0.1",
|
|
||||||
openclaw: { hooks: ["./linked"] },
|
|
||||||
}),
|
|
||||||
"utf-8",
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await installHooksFromPath({
|
const result = await installHooksFromPath({
|
||||||
path: pkgDir,
|
path: pkgDir,
|
||||||
hooksDir: path.join(stateDir, "hooks"),
|
hooksDir: path.join(stateDir, "hooks"),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.ok).toBe(false);
|
expectPathInstallFailureContains(
|
||||||
if (result.ok) {
|
result,
|
||||||
return;
|
"openclaw.hooks entry resolves outside package directory",
|
||||||
}
|
);
|
||||||
expect(result.error).toContain("openclaw.hooks entry resolves outside package directory");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,30 @@ export type HookNpmIntegrityDriftParams = {
|
|||||||
|
|
||||||
const defaultLogger: HookInstallLogger = {};
|
const defaultLogger: HookInstallLogger = {};
|
||||||
|
|
||||||
|
type HookInstallForwardParams = {
|
||||||
|
hooksDir?: string;
|
||||||
|
timeoutMs?: number;
|
||||||
|
logger?: HookInstallLogger;
|
||||||
|
mode?: "install" | "update";
|
||||||
|
dryRun?: boolean;
|
||||||
|
expectedHookPackId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type HookPackageInstallParams = { packageDir: string } & HookInstallForwardParams;
|
||||||
|
type HookArchiveInstallParams = { archivePath: string } & HookInstallForwardParams;
|
||||||
|
type HookPathInstallParams = { path: string } & HookInstallForwardParams;
|
||||||
|
|
||||||
|
function buildHookInstallForwardParams(params: HookInstallForwardParams): HookInstallForwardParams {
|
||||||
|
return {
|
||||||
|
hooksDir: params.hooksDir,
|
||||||
|
timeoutMs: params.timeoutMs,
|
||||||
|
logger: params.logger,
|
||||||
|
mode: params.mode,
|
||||||
|
dryRun: params.dryRun,
|
||||||
|
expectedHookPackId: params.expectedHookPackId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function validateHookId(hookId: string): string | null {
|
function validateHookId(hookId: string): string | null {
|
||||||
if (!hookId) {
|
if (!hookId) {
|
||||||
return "invalid hook name: missing";
|
return "invalid hook name: missing";
|
||||||
@@ -113,6 +137,54 @@ async function resolveInstallTargetDir(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resolveAvailableHookInstallTarget(params: {
|
||||||
|
id: string;
|
||||||
|
hooksDir?: string;
|
||||||
|
mode: "install" | "update";
|
||||||
|
alreadyExistsError: (targetDir: string) => string;
|
||||||
|
}): Promise<{ ok: true; targetDir: string } | { ok: false; error: string }> {
|
||||||
|
const targetDirResult = await resolveInstallTargetDir(params.id, params.hooksDir);
|
||||||
|
if (!targetDirResult.ok) {
|
||||||
|
return targetDirResult;
|
||||||
|
}
|
||||||
|
const targetDir = targetDirResult.targetDir;
|
||||||
|
const availability = await ensureInstallTargetAvailable({
|
||||||
|
mode: params.mode,
|
||||||
|
targetDir,
|
||||||
|
alreadyExistsError: params.alreadyExistsError(targetDir),
|
||||||
|
});
|
||||||
|
if (!availability.ok) {
|
||||||
|
return availability;
|
||||||
|
}
|
||||||
|
return { ok: true, targetDir };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installFromResolvedHookDir(
|
||||||
|
resolvedDir: string,
|
||||||
|
params: HookInstallForwardParams,
|
||||||
|
): Promise<InstallHooksResult> {
|
||||||
|
const manifestPath = path.join(resolvedDir, "package.json");
|
||||||
|
if (await fileExists(manifestPath)) {
|
||||||
|
return await installHookPackageFromDir({
|
||||||
|
packageDir: resolvedDir,
|
||||||
|
hooksDir: params.hooksDir,
|
||||||
|
timeoutMs: params.timeoutMs,
|
||||||
|
logger: params.logger,
|
||||||
|
mode: params.mode,
|
||||||
|
dryRun: params.dryRun,
|
||||||
|
expectedHookPackId: params.expectedHookPackId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return await installHookFromDir({
|
||||||
|
hookDir: resolvedDir,
|
||||||
|
hooksDir: params.hooksDir,
|
||||||
|
logger: params.logger,
|
||||||
|
mode: params.mode,
|
||||||
|
dryRun: params.dryRun,
|
||||||
|
expectedHookPackId: params.expectedHookPackId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function resolveHookNameFromDir(hookDir: string): Promise<string> {
|
async function resolveHookNameFromDir(hookDir: string): Promise<string> {
|
||||||
const hookMdPath = path.join(hookDir, "HOOK.md");
|
const hookMdPath = path.join(hookDir, "HOOK.md");
|
||||||
if (!(await fileExists(hookMdPath))) {
|
if (!(await fileExists(hookMdPath))) {
|
||||||
@@ -139,15 +211,9 @@ async function validateHookDir(hookDir: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installHookPackageFromDir(params: {
|
async function installHookPackageFromDir(
|
||||||
packageDir: string;
|
params: HookPackageInstallParams,
|
||||||
hooksDir?: string;
|
): Promise<InstallHooksResult> {
|
||||||
timeoutMs?: number;
|
|
||||||
logger?: HookInstallLogger;
|
|
||||||
mode?: "install" | "update";
|
|
||||||
dryRun?: boolean;
|
|
||||||
expectedHookPackId?: string;
|
|
||||||
}): Promise<InstallHooksResult> {
|
|
||||||
const { logger, timeoutMs, mode, dryRun } = resolveTimedInstallModeOptions(params, defaultLogger);
|
const { logger, timeoutMs, mode, dryRun } = resolveTimedInstallModeOptions(params, defaultLogger);
|
||||||
|
|
||||||
const manifestPath = path.join(params.packageDir, "package.json");
|
const manifestPath = path.join(params.packageDir, "package.json");
|
||||||
@@ -182,19 +248,16 @@ async function installHookPackageFromDir(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetDirResult = await resolveInstallTargetDir(hookPackId, params.hooksDir);
|
const target = await resolveAvailableHookInstallTarget({
|
||||||
if (!targetDirResult.ok) {
|
id: hookPackId,
|
||||||
return { ok: false, error: targetDirResult.error };
|
hooksDir: params.hooksDir,
|
||||||
}
|
|
||||||
const targetDir = targetDirResult.targetDir;
|
|
||||||
const availability = await ensureInstallTargetAvailable({
|
|
||||||
mode,
|
mode,
|
||||||
targetDir,
|
alreadyExistsError: (targetDir) => `hook pack already exists: ${targetDir} (delete it first)`,
|
||||||
alreadyExistsError: `hook pack already exists: ${targetDir} (delete it first)`,
|
|
||||||
});
|
});
|
||||||
if (!availability.ok) {
|
if (!target.ok) {
|
||||||
return availability;
|
return target;
|
||||||
}
|
}
|
||||||
|
const targetDir = target.targetDir;
|
||||||
|
|
||||||
const resolvedHooks = [] as string[];
|
const resolvedHooks = [] as string[];
|
||||||
for (const entry of hookEntries) {
|
for (const entry of hookEntries) {
|
||||||
@@ -277,19 +340,16 @@ async function installHookFromDir(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetDirResult = await resolveInstallTargetDir(hookName, params.hooksDir);
|
const target = await resolveAvailableHookInstallTarget({
|
||||||
if (!targetDirResult.ok) {
|
id: hookName,
|
||||||
return { ok: false, error: targetDirResult.error };
|
hooksDir: params.hooksDir,
|
||||||
}
|
|
||||||
const targetDir = targetDirResult.targetDir;
|
|
||||||
const availability = await ensureInstallTargetAvailable({
|
|
||||||
mode,
|
mode,
|
||||||
targetDir,
|
alreadyExistsError: (targetDir) => `hook already exists: ${targetDir} (delete it first)`,
|
||||||
alreadyExistsError: `hook already exists: ${targetDir} (delete it first)`,
|
|
||||||
});
|
});
|
||||||
if (!availability.ok) {
|
if (!target.ok) {
|
||||||
return availability;
|
return target;
|
||||||
}
|
}
|
||||||
|
const targetDir = target.targetDir;
|
||||||
|
|
||||||
if (dryRun) {
|
if (dryRun) {
|
||||||
return { ok: true, hookPackId: hookName, hooks: [hookName], targetDir };
|
return { ok: true, hookPackId: hookName, hooks: [hookName], targetDir };
|
||||||
@@ -312,15 +372,9 @@ async function installHookFromDir(params: {
|
|||||||
return { ok: true, hookPackId: hookName, hooks: [hookName], targetDir };
|
return { ok: true, hookPackId: hookName, hooks: [hookName], targetDir };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function installHooksFromArchive(params: {
|
export async function installHooksFromArchive(
|
||||||
archivePath: string;
|
params: HookArchiveInstallParams,
|
||||||
hooksDir?: string;
|
): Promise<InstallHooksResult> {
|
||||||
timeoutMs?: number;
|
|
||||||
logger?: HookInstallLogger;
|
|
||||||
mode?: "install" | "update";
|
|
||||||
dryRun?: boolean;
|
|
||||||
expectedHookPackId?: string;
|
|
||||||
}): Promise<InstallHooksResult> {
|
|
||||||
const logger = params.logger ?? defaultLogger;
|
const logger = params.logger ?? defaultLogger;
|
||||||
const timeoutMs = params.timeoutMs ?? 120_000;
|
const timeoutMs = params.timeoutMs ?? 120_000;
|
||||||
const archivePathResult = await resolveArchiveSourcePath(params.archivePath);
|
const archivePathResult = await resolveArchiveSourcePath(params.archivePath);
|
||||||
@@ -334,29 +388,18 @@ export async function installHooksFromArchive(params: {
|
|||||||
tempDirPrefix: "openclaw-hook-",
|
tempDirPrefix: "openclaw-hook-",
|
||||||
timeoutMs,
|
timeoutMs,
|
||||||
logger,
|
logger,
|
||||||
onExtracted: async (rootDir) => {
|
onExtracted: async (rootDir) =>
|
||||||
const manifestPath = path.join(rootDir, "package.json");
|
await installFromResolvedHookDir(
|
||||||
if (await fileExists(manifestPath)) {
|
rootDir,
|
||||||
return await installHookPackageFromDir({
|
buildHookInstallForwardParams({
|
||||||
packageDir: rootDir,
|
|
||||||
hooksDir: params.hooksDir,
|
hooksDir: params.hooksDir,
|
||||||
timeoutMs,
|
timeoutMs,
|
||||||
logger,
|
logger,
|
||||||
mode: params.mode,
|
mode: params.mode,
|
||||||
dryRun: params.dryRun,
|
dryRun: params.dryRun,
|
||||||
expectedHookPackId: params.expectedHookPackId,
|
expectedHookPackId: params.expectedHookPackId,
|
||||||
});
|
}),
|
||||||
}
|
),
|
||||||
|
|
||||||
return await installHookFromDir({
|
|
||||||
hookDir: rootDir,
|
|
||||||
hooksDir: params.hooksDir,
|
|
||||||
logger,
|
|
||||||
mode: params.mode,
|
|
||||||
dryRun: params.dryRun,
|
|
||||||
expectedHookPackId: params.expectedHookPackId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,54 +429,36 @@ export async function installHooksFromNpmSpec(params: {
|
|||||||
logger.warn?.(message);
|
logger.warn?.(message);
|
||||||
},
|
},
|
||||||
installFromArchive: installHooksFromArchive,
|
installFromArchive: installHooksFromArchive,
|
||||||
archiveInstallParams: {
|
archiveInstallParams: buildHookInstallForwardParams({
|
||||||
hooksDir: params.hooksDir,
|
hooksDir: params.hooksDir,
|
||||||
timeoutMs,
|
timeoutMs,
|
||||||
logger,
|
logger,
|
||||||
mode,
|
mode,
|
||||||
dryRun,
|
dryRun,
|
||||||
expectedHookPackId,
|
expectedHookPackId,
|
||||||
},
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function installHooksFromPath(params: {
|
export async function installHooksFromPath(
|
||||||
path: string;
|
params: HookPathInstallParams,
|
||||||
hooksDir?: string;
|
): Promise<InstallHooksResult> {
|
||||||
timeoutMs?: number;
|
|
||||||
logger?: HookInstallLogger;
|
|
||||||
mode?: "install" | "update";
|
|
||||||
dryRun?: boolean;
|
|
||||||
expectedHookPackId?: string;
|
|
||||||
}): Promise<InstallHooksResult> {
|
|
||||||
const pathResult = await resolveExistingInstallPath(params.path);
|
const pathResult = await resolveExistingInstallPath(params.path);
|
||||||
if (!pathResult.ok) {
|
if (!pathResult.ok) {
|
||||||
return pathResult;
|
return pathResult;
|
||||||
}
|
}
|
||||||
const { resolvedPath: resolved, stat } = pathResult;
|
const { resolvedPath: resolved, stat } = pathResult;
|
||||||
|
const forwardParams = buildHookInstallForwardParams({
|
||||||
|
hooksDir: params.hooksDir,
|
||||||
|
timeoutMs: params.timeoutMs,
|
||||||
|
logger: params.logger,
|
||||||
|
mode: params.mode,
|
||||||
|
dryRun: params.dryRun,
|
||||||
|
expectedHookPackId: params.expectedHookPackId,
|
||||||
|
});
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
if (stat.isDirectory()) {
|
||||||
const manifestPath = path.join(resolved, "package.json");
|
return await installFromResolvedHookDir(resolved, forwardParams);
|
||||||
if (await fileExists(manifestPath)) {
|
|
||||||
return await installHookPackageFromDir({
|
|
||||||
packageDir: resolved,
|
|
||||||
hooksDir: params.hooksDir,
|
|
||||||
timeoutMs: params.timeoutMs,
|
|
||||||
logger: params.logger,
|
|
||||||
mode: params.mode,
|
|
||||||
dryRun: params.dryRun,
|
|
||||||
expectedHookPackId: params.expectedHookPackId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return await installHookFromDir({
|
|
||||||
hookDir: resolved,
|
|
||||||
hooksDir: params.hooksDir,
|
|
||||||
logger: params.logger,
|
|
||||||
mode: params.mode,
|
|
||||||
dryRun: params.dryRun,
|
|
||||||
expectedHookPackId: params.expectedHookPackId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resolveArchiveKind(resolved)) {
|
if (!resolveArchiveKind(resolved)) {
|
||||||
@@ -442,11 +467,6 @@ export async function installHooksFromPath(params: {
|
|||||||
|
|
||||||
return await installHooksFromArchive({
|
return await installHooksFromArchive({
|
||||||
archivePath: resolved,
|
archivePath: resolved,
|
||||||
hooksDir: params.hooksDir,
|
...forwardParams,
|
||||||
timeoutMs: params.timeoutMs,
|
|
||||||
logger: params.logger,
|
|
||||||
mode: params.mode,
|
|
||||||
dryRun: params.dryRun,
|
|
||||||
expectedHookPackId: params.expectedHookPackId,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user