From 4f8c577ffd9f130c9cbbc42302c828ad77a24f75 Mon Sep 17 00:00:00 2001 From: Zak Date: Mon, 10 Aug 2026 13:12:11 +0700 Subject: [PATCH] feat(common): add install hook CLI --- .changeset/clean-install-hook-cli.md | 6 ++++++ README.md | 4 ++-- packages/common/package.json | 5 ++++- packages/common/src/cli/install.ts | 30 ++++++++++++++++++++++++++++ packages/common/tsup.config.ts | 1 + 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .changeset/clean-install-hook-cli.md create mode 100644 packages/common/src/cli/install.ts diff --git a/.changeset/clean-install-hook-cli.md b/.changeset/clean-install-hook-cli.md new file mode 100644 index 0000000..830e075 --- /dev/null +++ b/.changeset/clean-install-hook-cli.md @@ -0,0 +1,6 @@ +--- +'agoda-devfeedback-common': minor +--- + +Add a `devfeedback-install` CLI for invoking the exact install hooks from a +consuming repository without an inline `node -e` wrapper. diff --git a/README.md b/README.md index 8adc9f9..abfddfd 100644 --- a/README.md +++ b/README.md @@ -154,8 +154,8 @@ Two tiers, and the first one needs nothing from you. ```json { "scripts": { - "preinstall": "node -e \"try{require('agoda-devfeedback-common/hooks/preinstall')}catch(e){}\"", - "postinstall": "node -e \"try{require('agoda-devfeedback-common/hooks/postinstall')}catch(e){}\"" + "preinstall": "devfeedback-install preinstall || exit 0", + "postinstall": "devfeedback-install postinstall" }, "devDependencies": { "agoda-devfeedback-common": "^2.0.0" diff --git a/packages/common/package.json b/packages/common/package.json index 91adb51..ffc5f9f 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -5,6 +5,9 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", + "bin": { + "devfeedback-install": "./dist/cli/install.cjs" + }, "exports": { "./package.json": "./package.json", ".": { @@ -24,7 +27,7 @@ "dev": "tsup --watch", "check-types": "tsc --noEmit", "test": "vitest", - "postinstall": "node ./dist/hooks/postinstall.cjs --self || exit 0" + "postinstall": "node ./dist/cli/install.cjs postinstall --self || exit 0" }, "dependencies": { "axios": "1.8.4", diff --git a/packages/common/src/cli/install.ts b/packages/common/src/cli/install.ts new file mode 100644 index 0000000..3595491 --- /dev/null +++ b/packages/common/src/cli/install.ts @@ -0,0 +1,30 @@ +#!/usr/bin/env node + +type InstallHook = 'preinstall' | 'postinstall'; + +const usage = () => { + process.stderr.write('Usage: devfeedback-install [--self]\n'); +}; + +const run = async (hook: InstallHook): Promise => { + if (hook === 'preinstall') { + await import('../hooks/preinstall'); + } else { + await import('../hooks/postinstall'); + } +}; + +const hook = process.argv[2]; + +if (hook !== 'preinstall' && hook !== 'postinstall') { + usage(); + process.exitCode = 1; +} else { + void run(hook).catch((error: unknown) => { + // The hook modules are deliberately best-effort. This is only a guard for + // unexpected module-loading failures in the CLI itself. + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(`[devfeedback] install hook error: ${message}\n`); + process.exitCode = 0; + }); +} diff --git a/packages/common/tsup.config.ts b/packages/common/tsup.config.ts index 8a8ac38..7db88da 100644 --- a/packages/common/tsup.config.ts +++ b/packages/common/tsup.config.ts @@ -7,6 +7,7 @@ export default defineConfig({ // they need their own stable entry points under dist/hooks 'hooks/preinstall': 'src/hooks/preinstall.ts', 'hooks/postinstall': 'src/hooks/postinstall.ts', + 'cli/install': 'src/cli/install.ts', }, format: ['cjs', 'esm'], splitting: true,