Skip to content

Advanced Topics

Advanced configuration patterns for complex setups.

For non-standard release naming, narrow the candidates with an assetPattern; a RegExp is accepted when a glob is not expressive enough. The platform and architecture are still matched automatically within the narrowed set:

export default defineTool((install) =>
install("github-release", {
repo: "owner/tool",
assetPattern: /^tool-(macos|linux)-(amd64|arm64)\.tar\.gz$/,
}).bin("tool"),
);

Use environment variables for runtime configuration:

const isDev = process.env.NODE_ENV === "development";
export default defineTool((install) =>
install("github-release", { repo: "owner/tool" })
.bin("tool")
.version(isDev ? "latest" : "v1.2.3")
.zsh((shell) => shell.env({ TOOL_LOG_LEVEL: isDev ? "debug" : "info" })),
);

Choose methods based on system capabilities:

export default defineTool((install, ctx) => {
if (ctx.systemInfo.platform === Platform.MacOS && process.env.HOMEBREW_PREFIX) {
return install("brew", { formula: "tool" }).bin("tool");
}
return install("github-release", { repo: "owner/tool" }).bin("tool");
});
export default defineTool((install) =>
install("github-release", { repo: "owner/tool" })
.bin("tool")
.hook("after-extract", async ({ extractDir, stagingDir, $ }) => {
if (extractDir && stagingDir) {
await $`cd ${extractDir} && ./configure --prefix=${stagingDir}`;
await $`cd ${extractDir} && make -j$(nproc)`;
await $`cd ${extractDir} && make install`;
}
}),
);

Combine .dependsOn() with hooks for version checks:

export default defineTool((install) =>
install("github-release", { repo: "owner/tool" })
.bin("tool")
.dependsOn("node")
.hook("before-install", async ({ log, $ }) => {
const result = await $`node --version`.noThrow();
if (result.exitCode !== 0) {
throw new Error("Node is required but not available");
}
log.info(`Using Node ${result.stdout.toString().trim()}`);
}),
);
export default defineTool((install, ctx) =>
install("github-release", { repo: "owner/tool" })
.bin("tool")
.zsh((shell) =>
shell.always(`
function expensive-fn() {
unfunction expensive-fn
source "${ctx.currentDir}/expensive.zsh"
expensive-fn "$@"
}
`),
),
);

A completion generated by running the tool is .completions({ cmd }), which resolves the command against the installed binary and owns the output path. See shell-completions.md.

export default defineTool((install) =>
install("github-release", { repo: "owner/tool" })
.bin("tool")
.hook("after-install", async ({ $, log }) => {
await Promise.all([$`tool setup-task-1`, $`tool setup-task-2`, $`tool setup-task-3`]);
log.info("All setup tasks completed");
}),
);