@fatsolutions/ganchos 1.0.1 → 1.0.3

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.
@@ -1,16 +1,22 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
1
3
  export const dependencies = {
2
4
  "eslint": "9.39.2",
3
5
  "@eslint/js": "9.39.2",
4
- "eslint-config-prettier": "10.1.8", // includes prettier
6
+ // includes prettier
7
+ "eslint-config-prettier": "10.1.8",
5
8
  "typescript-eslint": "8.51.0",
6
9
  };
7
10
  export const configFiles = [
8
11
  "eslint.config.js",
9
12
  ".prettierrc"
10
13
  ];
11
- export function getInstallCommand(deps) {
14
+ export function getInstallCommand(deps, projectRoot) {
12
15
  const packages = Object.entries(deps)
13
16
  .map(([name, version]) => `${name}@${version}`)
14
17
  .join(' ');
15
- return `pnpm add -D -w --ignore-scripts ${packages}`;
18
+ // Check if in a pnpm workspace
19
+ const isWorkspace = existsSync(join(projectRoot, 'pnpm-workspace.yaml'));
20
+ const workspaceFlag = isWorkspace ? '-w ' : '';
21
+ return `pnpm add -D ${workspaceFlag}--ignore-scripts ${packages}`;
16
22
  }
@@ -1,7 +1,11 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+
1
4
  export const dependencies: Record<string, string> = {
2
5
  "eslint": "9.39.2",
3
6
  "@eslint/js": "9.39.2",
4
- "eslint-config-prettier": "10.1.8", // includes prettier
7
+ // includes prettier
8
+ "eslint-config-prettier": "10.1.8",
5
9
  "typescript-eslint": "8.51.0",
6
10
  };
7
11
 
@@ -10,9 +14,14 @@ export const configFiles: string[] = [
10
14
  ".prettierrc"
11
15
  ];
12
16
 
13
- export function getInstallCommand(deps: Record<string, string>): string {
17
+ export function getInstallCommand(deps: Record<string, string>, projectRoot: string): string {
14
18
  const packages = Object.entries(deps)
15
19
  .map(([name, version]) => `${name}@${version}`)
16
20
  .join(' ');
17
- return `pnpm add -D -w --ignore-scripts ${packages}`;
21
+
22
+ // Check if in a pnpm workspace
23
+ const isWorkspace = existsSync(join(projectRoot, 'pnpm-workspace.yaml'));
24
+ const workspaceFlag = isWorkspace ? '-w ' : '';
25
+
26
+ return `pnpm add -D ${workspaceFlag}--ignore-scripts ${packages}`;
18
27
  }
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { enableLanguages } from "./lib/config.js";
5
+ import { installHook, installHookTools } from "./lib/hooks.js";
6
+ import { getConfigPath } from "./lib/paths.js";
7
+ async function appendToExclude(projectRoot, entries) {
8
+ const excludePath = path.join(projectRoot, ".git", "info", "exclude");
9
+ try {
10
+ const existing = await fs.readFile(excludePath, "utf-8");
11
+ const linesToAdd = entries.filter((entry) => !existing.includes(entry));
12
+ if (linesToAdd.length > 0) {
13
+ await fs.appendFile(excludePath, "\n" + linesToAdd.join("\n") + "\n");
14
+ }
15
+ } catch {
16
+ }
17
+ }
18
+ async function bootstrap() {
19
+ const projectRoot = process.env.INIT_CWD || process.cwd();
20
+ const selfPkgPath = path.join(projectRoot, "package.json");
21
+ try {
22
+ const selfPkg = JSON.parse(await fs.readFile(selfPkgPath, "utf-8"));
23
+ if (selfPkg.name === "@fatsolutions/ganchos") {
24
+ return;
25
+ }
26
+ } catch {
27
+ return;
28
+ }
29
+ const configPath = getConfigPath(projectRoot);
30
+ try {
31
+ await fs.access(configPath);
32
+ console.log("Ganchos: Already configured, skipping bootstrap.");
33
+ return;
34
+ } catch {
35
+ }
36
+ try {
37
+ await fs.access(path.join(projectRoot, ".git"));
38
+ } catch {
39
+ console.log("Ganchos: Not a git repository, skipping bootstrap.");
40
+ return;
41
+ }
42
+ const pkgPath = path.join(projectRoot, "package.json");
43
+ const pkgContent = await fs.readFile(pkgPath, "utf-8");
44
+ const pkg = JSON.parse(pkgContent);
45
+ const ganchosConfig = pkg.ganchos;
46
+ if (!ganchosConfig?.languages?.length) {
47
+ console.log('Ganchos: No languages configured in package.json "ganchos" field, skipping.');
48
+ console.log('Ganchos: Add { "ganchos": { "languages": ["typescript"] } } to enable.');
49
+ return;
50
+ }
51
+ console.log("Ganchos: Setting up git hooks...");
52
+ await enableLanguages(projectRoot, ganchosConfig.languages);
53
+ console.log(`Ganchos: Enabled languages: ${ganchosConfig.languages.join(", ")}`);
54
+ await installHookTools(projectRoot);
55
+ await installHook(projectRoot);
56
+ await appendToExclude(projectRoot, [".ganchos.json"]);
57
+ console.log("Ganchos: Setup complete!");
58
+ }
59
+ bootstrap().catch((err) => {
60
+ console.error("Ganchos: Bootstrap failed:", err);
61
+ process.exit(1);
62
+ });
@@ -4,7 +4,7 @@ async function disableCommand(languages) {
4
4
  try {
5
5
  await disableLanguages(projectRoot, languages);
6
6
  console.log(`Disabled: ${languages.join(", ")}`);
7
- console.log("Run `npx fat-hooks install` to apply changes.");
7
+ console.log('Run `npx "@fatsolutions/ganchos" install` to apply changes.');
8
8
  } catch (err) {
9
9
  if (err instanceof Error) {
10
10
  console.error(`Error: ${err.message}`);
@@ -11,7 +11,7 @@ async function enableCommand(languages) {
11
11
  try {
12
12
  await enableLanguages(projectRoot, languages);
13
13
  console.log(`Enabled: ${languages.join(", ")}`);
14
- console.log("Run `npx fat-hooks install` to apply changes.");
14
+ console.log('Run `npx "@fatsolutions/ganchos" install` to apply changes.');
15
15
  } catch (err) {
16
16
  if (err instanceof Error) {
17
17
  console.error(`Error: ${err.message}`);
@@ -8,7 +8,7 @@ async function installCommand() {
8
8
  const enabledLanguages = config.languages.filter((l) => l.enabled).map((l) => l.name);
9
9
  if (enabledLanguages.length === 0) {
10
10
  console.log("No languages enabled. Enable languages first with:");
11
- console.log(" npx fat-hooks enable javascript typescript python");
11
+ console.log(' npx "@fatsolutions/ganchos" enable javascript typescript python');
12
12
  return;
13
13
  }
14
14
  await installHookTools(projectRoot);
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { listCommand } from "./commands/list.js";
6
6
  import { enableCommand } from "./commands/enable.js";
7
7
  import { disableCommand } from "./commands/disable.js";
8
8
  const program = new Command();
9
- program.name("fat-hooks").description("Git Hook Manager for Polyglot Monorepos").version("1.0.0");
9
+ program.name('"@fatsolutions/ganchos"').description("Git Hook Manager for Polyglot Monorepos").version("1.0.0");
10
10
  program.command("install").description("Install git hooks based on configuration").action(installCommand);
11
11
  program.command("generate").description("Generate hook content to stdout (for inspection)").action(generateCommand);
12
12
  program.command("list").description("List configured languages").action(listCommand);
@@ -1,11 +1,11 @@
1
1
  import { FatHooksConfig } from '../types/index.js';
2
2
 
3
3
  /**
4
- * Read configuration from fat-hooks.json, creating default if missing.
4
+ * Read configuration from ".ganchos.json", creating default if missing.
5
5
  */
6
6
  declare function readConfig(projectRoot: string): Promise<FatHooksConfig>;
7
7
  /**
8
- * Write configuration to fat-hooks.json.
8
+ * Write configuration to "@fatsolutions/ganchos".json.
9
9
  */
10
10
  declare function writeConfig(projectRoot: string, config: FatHooksConfig): Promise<void>;
11
11
  /**
package/dist/lib/hooks.js CHANGED
@@ -5,7 +5,7 @@ import { getHookScript, getGitHooksDir, getLanguageConfigDir } from "./paths.js"
5
5
  import { readConfig } from "./config.js";
6
6
  const HOOK_HEADER = `#!/bin/sh
7
7
  # Auto-generated pre-commit hook
8
- # DO NOT EDIT - managed by fat-hooks
8
+ # DO NOT EDIT - managed by "@fatsolutions/ganchos"
9
9
 
10
10
  set -e
11
11
 
@@ -61,7 +61,7 @@ async function installHookTools(projectRoot) {
61
61
  }
62
62
  const installModule = await import(installModulePath);
63
63
  if (installModule.dependencies && installModule.getInstallCommand) {
64
- const cmd = installModule.getInstallCommand(installModule.dependencies);
64
+ const cmd = installModule.getInstallCommand(installModule.dependencies, projectRoot);
65
65
  console.log(`Installing ${lang.name} tools: ${cmd}`);
66
66
  execSync(cmd, { cwd: projectRoot, stdio: "inherit" });
67
67
  }
@@ -5,7 +5,7 @@ interface LanguageConfig {
5
5
  interface LanguageInstallModule {
6
6
  dependencies: Record<string, string>;
7
7
  configFiles: string[];
8
- getInstallCommand: (deps: Record<string, string>) => string;
8
+ getInstallCommand: (deps: Record<string, string>, projectRoot: string) => string;
9
9
  }
10
10
  interface FatHooksConfig {
11
11
  version: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fatsolutions/ganchos",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Git Hook Manager for Polyglot Monorepos, developed in house by FatSolutions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,6 +38,7 @@
38
38
  "registry": "https://registry.npmjs.org"
39
39
  },
40
40
  "scripts": {
41
+ "postinstall": "node dist/bootstrap.js",
41
42
  "build": "tsup && tsc -p tsconfig.configs.json",
42
43
  "build:dev": "tsc -p tsconfig.build.json && tsc -p tsconfig.configs.json",
43
44
  "dev": "tsup --watch",