@webpieces/ai-hook-rules 0.2.123 → 0.2.125

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.
@@ -11,7 +11,5 @@ const fs = require('fs');
11
11
 
12
12
  const compiled = path.join(__dirname, '..', 'src', 'bin', 'postinstall.js');
13
13
  if (fs.existsSync(compiled)) {
14
- require(compiled).main().catch(function (err) {
15
- console.error(' [ai-hook-rules] postinstall warning:', err.message);
16
- });
14
+ require(compiled).main();
17
15
  }
@@ -9,10 +9,7 @@ const fs = require('fs');
9
9
  const compiled = path.join(__dirname, '..', 'src', 'bin', 'postinstall.js');
10
10
 
11
11
  if (fs.existsSync(compiled)) {
12
- require(compiled).main().catch(function (err) {
13
- console.error(' [ai-hook-rules] error:', err.message);
14
- process.exit(1);
15
- });
12
+ require(compiled).main();
16
13
  } else {
17
14
  console.error(' [ai-hook-rules] Package not built yet. Run the build first, or install from npm.');
18
15
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/ai-hook-rules",
3
- "version": "0.2.123",
3
+ "version": "0.2.125",
4
4
  "description": "Pluggable write-time validation framework for AI coding agents (@webpieces/ai-hook-rules). Claude Code PreToolUse + openclaw before_tool_call adapters share one rule engine.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -32,7 +32,7 @@
32
32
  "directory": "packages/tooling/ai-hook-rules"
33
33
  },
34
34
  "dependencies": {
35
- "@webpieces/rules-config": "0.2.123"
35
+ "@webpieces/rules-config": "0.2.125"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export declare function main(): Promise<void>;
2
+ export declare function main(): void;
@@ -5,7 +5,6 @@ exports.main = main;
5
5
  const tslib_1 = require("tslib");
6
6
  const fs = tslib_1.__importStar(require("fs"));
7
7
  const path = tslib_1.__importStar(require("path"));
8
- const readline = tslib_1.__importStar(require("readline"));
9
8
  const BRIDGE_CONTENT = `#!/usr/bin/env node\nrequire('@webpieces/ai-hook-rules/claude-code').main();\n`;
10
9
  function findProjectRoot() {
11
10
  // Walk up from this file's location to escape node_modules
@@ -72,56 +71,13 @@ function backupSettings(settingsPath) {
72
71
  console.log(' [ai-hook-rules] Backed up .claude/settings.json to .claude/settings.json.bak');
73
72
  }
74
73
  }
75
- function printManualInstructions() {
76
- console.log('');
77
- console.log(' [ai-hook-rules] To enable AI code-quality hooks, add this to .claude/settings.json:');
78
- console.log('');
79
- console.log(' {');
80
- console.log(' "hooks": {');
81
- console.log(' "PreToolUse": [{');
82
- console.log(' "matcher": "Write|Edit|MultiEdit|Bash",');
83
- console.log(' "hooks": [{');
84
- console.log(' "type": "command",');
85
- console.log(' "command": "node .webpieces/ai-hooks/claude-code-hook.js"');
86
- console.log(' }]');
87
- console.log(' }]');
88
- console.log(' }');
89
- console.log(' }');
90
- console.log('');
74
+ function setupSettings(settingsPath) {
75
+ // pnpm hides all postinstall output, so no point prompting or logging.
76
+ // The user already consented by running `pnpm approve-builds`.
77
+ backupSettings(settingsPath);
78
+ mergeHookIntoSettings(settingsPath);
91
79
  }
92
- function promptUser(settingsPath) {
93
- return new Promise((resolve) => {
94
- const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
95
- if (!isInteractive) {
96
- console.log(' [ai-hook-rules] Non-interactive terminal detected, skipping .claude/settings.json setup.');
97
- printManualInstructions();
98
- resolve();
99
- return;
100
- }
101
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
102
- console.log('');
103
- console.log(' [ai-hook-rules] Would like to add a PreToolUse hook to .claude/settings.json');
104
- console.log(' This enables AI code-quality validation (rules configured in webpieces.ai-hooks.json).');
105
- if (fs.existsSync(settingsPath)) {
106
- console.log(' Your current settings.json will be backed up to .claude/settings.json.bak');
107
- }
108
- console.log('');
109
- rl.question(' Proceed? [y/N] ', (answer) => {
110
- rl.close();
111
- const yes = answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes';
112
- if (yes) {
113
- backupSettings(settingsPath);
114
- mergeHookIntoSettings(settingsPath);
115
- console.log(' [ai-hook-rules] Added PreToolUse hook to .claude/settings.json');
116
- }
117
- else {
118
- printManualInstructions();
119
- }
120
- resolve();
121
- });
122
- });
123
- }
124
- async function main() {
80
+ function main() {
125
81
  const projectRoot = findProjectRoot();
126
82
  if (!projectRoot) {
127
83
  // Not running from node_modules (maybe local dev / workspace) — skip
@@ -141,14 +97,10 @@ async function main() {
141
97
  if (settingsAlreadyHasHook(settingsPath)) {
142
98
  return;
143
99
  }
144
- // 5. Prompt user to add the hook
145
- await promptUser(settingsPath);
100
+ // 5. Backup and add the hook (user consented via pnpm approve-builds)
101
+ setupSettings(settingsPath);
146
102
  }
147
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
148
103
  if (require.main === module) {
149
- main().catch((err) => {
150
- // Fail open — don't break pnpm install if postinstall crashes
151
- console.error(' [ai-hook-rules] postinstall warning:', err.message);
152
- });
104
+ main();
153
105
  }
154
106
  //# sourceMappingURL=postinstall.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/postinstall.ts"],"names":[],"mappings":";;;AA0JA,oBA2BC;;AApLD,+CAAyB;AACzB,mDAA6B;AAC7B,2DAAqC;AAErC,MAAM,cAAc,GAAG,gFAAgF,CAAC;AAExG,SAAS,eAAe;IACpB,2DAA2D;IAC3D,yFAAyF;IACzF,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,WAAmB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IAE9D,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC7C,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,mBAAmB,CAAC,WAAmB;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,yBAAyB,CAAC,CAAC;IACrE,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO;IAEtC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,8BAA8B,CAAC,CAAC;IACnG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO;IAEzC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAChD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IAE/C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;AACnD,CAAC;AAoBD,SAAS,YAAY;IACjB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,2BAA2B,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqB,CAAC;AAC/C,CAAC;AAED,SAAS,qBAAqB,CAAC,YAAoB;IAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAE/C,IAAI,QAAQ,GAAmB,EAAE,CAAC;IAClC,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAmB,CAAC;IACnF,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClB,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;IACxB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5C,QAAQ,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC;IACnC,CAAC;IAED,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,cAAc,CAAC,YAAoB;IACxC,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC;QACtC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;IAClG,CAAC;AACL,CAAC;AAED,SAAS,uBAAuB;IAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;IAC3F,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAmB,EAAE,EAAE;QACvC,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAClE,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,4FAA4F,CAAC,CAAC;YAC1G,uBAAuB,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;YACV,OAAO;QACX,CAAC;QAED,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;QAC9F,OAAO,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;QACxG,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,EAAE,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,MAAc,EAAE,EAAE;YAChD,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;YACzF,IAAI,GAAG,EAAE,CAAC;gBACN,cAAc,CAAC,YAAY,CAAC,CAAC;gBAC7B,qBAAqB,CAAC,YAAY,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;YACpF,CAAC;iBAAM,CAAC;gBACJ,uBAAuB,EAAE,CAAC;YAC9B,CAAC;YACD,OAAO,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAEM,KAAK,UAAU,IAAI;IACtB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,qEAAqE;QACrE,OAAO;IACX,CAAC;IAED,mCAAmC;IACnC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE9B,4BAA4B;IAC5B,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAEjC,2DAA2D;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO;IACX,CAAC;IAED,gEAAgE;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAC3D,IAAI,sBAAsB,CAAC,YAAY,CAAC,EAAE,CAAC;QACvC,OAAO;IACX,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC;AACnC,CAAC;AAED,8DAA8D;AAC9D,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACxB,8DAA8D;QAC9D,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["#!/usr/bin/env node\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as readline from 'readline';\n\nconst BRIDGE_CONTENT = `#!/usr/bin/env node\\nrequire('@webpieces/ai-hook-rules/claude-code').main();\\n`;\n\nfunction findProjectRoot(): string | null {\n // Walk up from this file's location to escape node_modules\n // e.g. /project/node_modules/@webpieces/ai-hook-rules/src/bin/postinstall.js -> /project\n let dir = __dirname;\n while (dir !== path.dirname(dir)) {\n dir = path.dirname(dir);\n const base = path.basename(dir);\n if (base === 'node_modules') {\n return path.dirname(dir);\n }\n }\n return null;\n}\n\nfunction createBridgeFile(projectRoot: string): void {\n const hooksDir = path.join(projectRoot, '.webpieces', 'ai-hooks');\n const bridgePath = path.join(hooksDir, 'claude-code-hook.js');\n\n fs.mkdirSync(hooksDir, { recursive: true });\n fs.writeFileSync(bridgePath, BRIDGE_CONTENT);\n fs.chmodSync(bridgePath, 0o755);\n console.log(' [ai-hook-rules] Created .webpieces/ai-hooks/claude-code-hook.js');\n}\n\nfunction seedConfigIfMissing(projectRoot: string): void {\n const configPath = path.join(projectRoot, 'webpieces.ai-hooks.json');\n if (fs.existsSync(configPath)) return;\n\n const templatePath = path.join(__dirname, '..', '..', 'templates', 'webpieces.ai-hooks.seed.json');\n if (!fs.existsSync(templatePath)) return;\n\n fs.copyFileSync(templatePath, configPath);\n console.log(' [ai-hook-rules] Created webpieces.ai-hooks.json (default config)');\n}\n\nfunction settingsAlreadyHasHook(settingsPath: string): boolean {\n if (!fs.existsSync(settingsPath)) return false;\n\n const content = fs.readFileSync(settingsPath, 'utf8');\n return content.includes('claude-code-hook.js');\n}\n\ninterface HookEntry {\n matcher: string;\n hooks: Array<{ type: string; command: string }>;\n}\n\ninterface SettingsTemplate {\n hooks: {\n PreToolUse: HookEntry[];\n };\n}\n\ninterface ClaudeSettings {\n hooks?: {\n PreToolUse?: HookEntry[];\n };\n [key: string]: string | number | boolean | object | null | undefined;\n}\n\nfunction loadTemplate(): SettingsTemplate {\n const templatePath = path.join(__dirname, '..', '..', 'templates', 'claude-settings-hook.json');\n const raw = fs.readFileSync(templatePath, 'utf8');\n return JSON.parse(raw) as SettingsTemplate;\n}\n\nfunction mergeHookIntoSettings(settingsPath: string): void {\n const template = loadTemplate();\n const hookEntry = template.hooks.PreToolUse[0];\n\n let settings: ClaudeSettings = {};\n if (fs.existsSync(settingsPath)) {\n settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')) as ClaudeSettings;\n }\n\n if (!settings.hooks) {\n settings.hooks = {};\n }\n if (!Array.isArray(settings.hooks.PreToolUse)) {\n settings.hooks.PreToolUse = [];\n }\n\n settings.hooks.PreToolUse.push(hookEntry);\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 4) + '\\n');\n}\n\nfunction backupSettings(settingsPath: string): void {\n if (fs.existsSync(settingsPath)) {\n const bakPath = settingsPath + '.bak';\n fs.copyFileSync(settingsPath, bakPath);\n console.log(' [ai-hook-rules] Backed up .claude/settings.json to .claude/settings.json.bak');\n }\n}\n\nfunction printManualInstructions(): void {\n console.log('');\n console.log(' [ai-hook-rules] To enable AI code-quality hooks, add this to .claude/settings.json:');\n console.log('');\n console.log(' {');\n console.log(' \"hooks\": {');\n console.log(' \"PreToolUse\": [{');\n console.log(' \"matcher\": \"Write|Edit|MultiEdit|Bash\",');\n console.log(' \"hooks\": [{');\n console.log(' \"type\": \"command\",');\n console.log(' \"command\": \"node .webpieces/ai-hooks/claude-code-hook.js\"');\n console.log(' }]');\n console.log(' }]');\n console.log(' }');\n console.log(' }');\n console.log('');\n}\n\nfunction promptUser(settingsPath: string): Promise<void> {\n return new Promise((resolve: () => void) => {\n const isInteractive = process.stdin.isTTY && process.stdout.isTTY;\n if (!isInteractive) {\n console.log(' [ai-hook-rules] Non-interactive terminal detected, skipping .claude/settings.json setup.');\n printManualInstructions();\n resolve();\n return;\n }\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n\n console.log('');\n console.log(' [ai-hook-rules] Would like to add a PreToolUse hook to .claude/settings.json');\n console.log(' This enables AI code-quality validation (rules configured in webpieces.ai-hooks.json).');\n if (fs.existsSync(settingsPath)) {\n console.log(' Your current settings.json will be backed up to .claude/settings.json.bak');\n }\n console.log('');\n\n rl.question(' Proceed? [y/N] ', (answer: string) => {\n rl.close();\n const yes = answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes';\n if (yes) {\n backupSettings(settingsPath);\n mergeHookIntoSettings(settingsPath);\n console.log(' [ai-hook-rules] Added PreToolUse hook to .claude/settings.json');\n } else {\n printManualInstructions();\n }\n resolve();\n });\n });\n}\n\nexport async function main(): Promise<void> {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n // Not running from node_modules (maybe local dev / workspace) — skip\n return;\n }\n\n // 1. Always create the bridge file\n createBridgeFile(projectRoot);\n\n // 2. Seed config if missing\n seedConfigIfMissing(projectRoot);\n\n // 3. Check if .claude/ exists — if not, skip settings.json\n const claudeDir = path.join(projectRoot, '.claude');\n if (!fs.existsSync(claudeDir)) {\n return;\n }\n\n // 4. Check if settings.json already has the hook — if yes, done\n const settingsPath = path.join(claudeDir, 'settings.json');\n if (settingsAlreadyHasHook(settingsPath)) {\n return;\n }\n\n // 5. Prompt user to add the hook\n await promptUser(settingsPath);\n}\n\n// eslint-disable-next-line @webpieces/no-unmanaged-exceptions\nif (require.main === module) {\n main().catch((err: Error) => {\n // Fail open — don't break pnpm install if postinstall crashes\n console.error(' [ai-hook-rules] postinstall warning:', err.message);\n });\n}\n"]}
1
+ {"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/postinstall.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nconst BRIDGE_CONTENT = `#!/usr/bin/env node\\nrequire('@webpieces/ai-hook-rules/claude-code').main();\\n`;\n\nfunction findProjectRoot(): string | null {\n // Walk up from this file's location to escape node_modules\n // e.g. /project/node_modules/@webpieces/ai-hook-rules/src/bin/postinstall.js -> /project\n let dir = __dirname;\n while (dir !== path.dirname(dir)) {\n dir = path.dirname(dir);\n const base = path.basename(dir);\n if (base === 'node_modules') {\n return path.dirname(dir);\n }\n }\n return null;\n}\n\nfunction createBridgeFile(projectRoot: string): void {\n const hooksDir = path.join(projectRoot, '.webpieces', 'ai-hooks');\n const bridgePath = path.join(hooksDir, 'claude-code-hook.js');\n\n fs.mkdirSync(hooksDir, { recursive: true });\n fs.writeFileSync(bridgePath, BRIDGE_CONTENT);\n fs.chmodSync(bridgePath, 0o755);\n console.log(' [ai-hook-rules] Created .webpieces/ai-hooks/claude-code-hook.js');\n}\n\nfunction seedConfigIfMissing(projectRoot: string): void {\n const configPath = path.join(projectRoot, 'webpieces.ai-hooks.json');\n if (fs.existsSync(configPath)) return;\n\n const templatePath = path.join(__dirname, '..', '..', 'templates', 'webpieces.ai-hooks.seed.json');\n if (!fs.existsSync(templatePath)) return;\n\n fs.copyFileSync(templatePath, configPath);\n console.log(' [ai-hook-rules] Created webpieces.ai-hooks.json (default config)');\n}\n\nfunction settingsAlreadyHasHook(settingsPath: string): boolean {\n if (!fs.existsSync(settingsPath)) return false;\n\n const content = fs.readFileSync(settingsPath, 'utf8');\n return content.includes('claude-code-hook.js');\n}\n\ninterface HookEntry {\n matcher: string;\n hooks: Array<{ type: string; command: string }>;\n}\n\ninterface SettingsTemplate {\n hooks: {\n PreToolUse: HookEntry[];\n };\n}\n\ninterface ClaudeSettings {\n hooks?: {\n PreToolUse?: HookEntry[];\n };\n [key: string]: string | number | boolean | object | null | undefined;\n}\n\nfunction loadTemplate(): SettingsTemplate {\n const templatePath = path.join(__dirname, '..', '..', 'templates', 'claude-settings-hook.json');\n const raw = fs.readFileSync(templatePath, 'utf8');\n return JSON.parse(raw) as SettingsTemplate;\n}\n\nfunction mergeHookIntoSettings(settingsPath: string): void {\n const template = loadTemplate();\n const hookEntry = template.hooks.PreToolUse[0];\n\n let settings: ClaudeSettings = {};\n if (fs.existsSync(settingsPath)) {\n settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')) as ClaudeSettings;\n }\n\n if (!settings.hooks) {\n settings.hooks = {};\n }\n if (!Array.isArray(settings.hooks.PreToolUse)) {\n settings.hooks.PreToolUse = [];\n }\n\n settings.hooks.PreToolUse.push(hookEntry);\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 4) + '\\n');\n}\n\nfunction backupSettings(settingsPath: string): void {\n if (fs.existsSync(settingsPath)) {\n const bakPath = settingsPath + '.bak';\n fs.copyFileSync(settingsPath, bakPath);\n console.log(' [ai-hook-rules] Backed up .claude/settings.json to .claude/settings.json.bak');\n }\n}\n\n\nfunction setupSettings(settingsPath: string): void {\n // pnpm hides all postinstall output, so no point prompting or logging.\n // The user already consented by running `pnpm approve-builds`.\n backupSettings(settingsPath);\n mergeHookIntoSettings(settingsPath);\n}\n\nexport function main(): void {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n // Not running from node_modules (maybe local dev / workspace) — skip\n return;\n }\n\n // 1. Always create the bridge file\n createBridgeFile(projectRoot);\n\n // 2. Seed config if missing\n seedConfigIfMissing(projectRoot);\n\n // 3. Check if .claude/ exists — if not, skip settings.json\n const claudeDir = path.join(projectRoot, '.claude');\n if (!fs.existsSync(claudeDir)) {\n return;\n }\n\n // 4. Check if settings.json already has the hook — if yes, done\n const settingsPath = path.join(claudeDir, 'settings.json');\n if (settingsAlreadyHasHook(settingsPath)) {\n return;\n }\n\n // 5. Backup and add the hook (user consented via pnpm approve-builds)\n setupSettings(settingsPath);\n}\n\nif (require.main === module) {\n main();\n}\n"]}