@webpieces/ai-hook-rules 0.3.149 → 0.3.150

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/ai-hook-rules",
3
- "version": "0.3.149",
3
+ "version": "0.3.150",
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.3.149"
35
+ "@webpieces/rules-config": "0.3.150"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -47,10 +47,10 @@ const noSymbolDiTokensRule = {
47
47
  files: ['**/*.ts', '**/*.tsx'],
48
48
  defaultOptions: { allowedPaths: [] },
49
49
  fixHint: [
50
- '(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',
51
- '(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',
52
- '(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule — no Symbol needed.',
53
- 'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',
50
+ 'Option 1: Use @provideSingleton() on the class and inject by type — no Symbol needed.',
51
+ 'Option 2: Implement an API interface — import the Symbol from the API definition and use @provideSingletonAs(TOKEN).',
52
+ 'Option 3: External lib class (DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...).inSingletonScope() — no Symbol.',
53
+ 'Option 4 (last resort): // webpieces-disable no-symbol-di-tokens -- <reason>',
54
54
  ],
55
55
  check(ctx) {
56
56
  const allowedPaths = ctx.options['allowedPaths'] ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EditRule, EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\n\nconst SYMBOL_DI_REGEX = /=\\s*Symbol(?:\\.for)?\\(/;\n\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\nfunction globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*') {\n if (pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n re += '[^/]*';\n i += 1;\n continue;\n }\n if (ch === '?') {\n re += '[^/]';\n i += 1;\n continue;\n }\n if ('.+^$(){}|[]\\\\'.includes(ch)) {\n re += '\\\\' + ch;\n i += 1;\n continue;\n }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n}\n\nfunction isAllowedPath(relativePath: string, allowedPaths: readonly string[]): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(relativePath))) return true;\n return allowedPaths.some((pattern: string) => globToRegex(pattern).test(relativePath));\n}\n\nconst noSymbolDiTokensRule: EditRule = {\n name: 'no-symbol-di-tokens',\n description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',\n scope: 'edit',\n files: ['**/*.ts', '**/*.tsx'],\n defaultOptions: { allowedPaths: [] },\n fixHint: [\n '(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',\n '(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',\n '(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule — no Symbol needed.',\n 'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',\n ],\n\n check(ctx: EditContext): readonly Violation[] {\n const allowedPaths = (ctx.options['allowedPaths'] as string[] | undefined) ?? [];\n if (isAllowedPath(ctx.relativePath, allowedPaths)) return [];\n\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!SYMBOL_DI_REGEX.test(stripped ?? '')) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, 'no-symbol-di-tokens')) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i]?.trim() ?? '',\n 'Symbol() used as a DI token. Mostly we avoid Symbol if we can — see fix options below.',\n ));\n }\n return violations;\n },\n};\n\nexport default noSymbolDiTokensRule;\n"]}
1
+ {"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EditRule, EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\n\nconst SYMBOL_DI_REGEX = /=\\s*Symbol(?:\\.for)?\\(/;\n\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\nfunction globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*') {\n if (pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n re += '[^/]*';\n i += 1;\n continue;\n }\n if (ch === '?') {\n re += '[^/]';\n i += 1;\n continue;\n }\n if ('.+^$(){}|[]\\\\'.includes(ch)) {\n re += '\\\\' + ch;\n i += 1;\n continue;\n }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n}\n\nfunction isAllowedPath(relativePath: string, allowedPaths: readonly string[]): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(relativePath))) return true;\n return allowedPaths.some((pattern: string) => globToRegex(pattern).test(relativePath));\n}\n\nconst noSymbolDiTokensRule: EditRule = {\n name: 'no-symbol-di-tokens',\n description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',\n scope: 'edit',\n files: ['**/*.ts', '**/*.tsx'],\n defaultOptions: { allowedPaths: [] },\n fixHint: [\n 'Option 1: Use @provideSingleton() on the class and inject by type — no Symbol needed.',\n 'Option 2: Implement an API interface — import the Symbol from the API definition and use @provideSingletonAs(TOKEN).',\n 'Option 3: External lib class (DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...).inSingletonScope() — no Symbol.',\n 'Option 4 (last resort): // webpieces-disable no-symbol-di-tokens -- <reason>',\n ],\n\n check(ctx: EditContext): readonly Violation[] {\n const allowedPaths = (ctx.options['allowedPaths'] as string[] | undefined) ?? [];\n if (isAllowedPath(ctx.relativePath, allowedPaths)) return [];\n\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!SYMBOL_DI_REGEX.test(stripped ?? '')) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, 'no-symbol-di-tokens')) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i]?.trim() ?? '',\n 'Symbol() used as a DI token. Mostly we avoid Symbol if we can — see fix options below.',\n ));\n }\n return violations;\n },\n};\n\nexport default noSymbolDiTokensRule;\n"]}
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ const tslib_1 = require("tslib");
5
+ const child_process_1 = require("child_process");
6
+ const fs = tslib_1.__importStar(require("fs"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
9
+ const git_findForkPoint_1 = require("./workflow/git-findForkPoint");
10
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
11
+ function validateCleanTree(currentBranch) {
12
+ if (currentBranch === 'main') {
13
+ process.stderr.write('❌ Error: Already on main branch. No need to update from main.\n');
14
+ process.exit(1);
15
+ }
16
+ process.stderr.write(`Current branch: ${currentBranch}\n`);
17
+ const hasDirtyFiles = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', 'HEAD', '--']).status !== 0;
18
+ if (!hasDirtyFiles)
19
+ return;
20
+ const changedFiles = (0, child_process_1.execSync)('git diff --name-only HEAD', { encoding: 'utf8' }).trim();
21
+ process.stderr.write('\n');
22
+ process.stderr.write(SEP);
23
+ process.stderr.write('❌ ERROR: You have uncommitted changes\n');
24
+ process.stderr.write(SEP);
25
+ process.stderr.write('\n');
26
+ process.stderr.write('Please commit or stash your changes before updating from main.\n');
27
+ process.stderr.write('\n');
28
+ process.stderr.write('Files with changes:\n');
29
+ process.stderr.write(changedFiles + '\n');
30
+ process.stderr.write('\n');
31
+ process.stderr.write('\x1b[1;31mTo commit your changes, run:\n');
32
+ process.stderr.write(' git add -A && git commit -m "your message"\x1b[0m\n');
33
+ process.stderr.write('\n');
34
+ process.stderr.write('Or to stash them temporarily:\n');
35
+ process.stderr.write(' git stash\n');
36
+ process.stderr.write(' ./scripts/git-updateFromMain.sh\n');
37
+ process.stderr.write(' git stash pop\n');
38
+ process.stderr.write('\n');
39
+ process.stderr.write(SEP);
40
+ process.exit(1);
41
+ }
42
+ function printHashPoints(hashes, currentBranch, mergeDir) {
43
+ process.stderr.write('📍 The 3 Hash Points:\n');
44
+ process.stderr.write(` 1. Fork point (A): ${hashes.hashForkPoint}\n`);
45
+ process.stderr.write(` (where ${currentBranch} diverged from main)\n`);
46
+ process.stderr.write('\n');
47
+ process.stderr.write(` 2. Feature HEAD (B): ${hashes.hashFeatureHead}\n`);
48
+ process.stderr.write(` (tip of ${currentBranch})\n`);
49
+ process.stderr.write('\n');
50
+ process.stderr.write(` 3. Main HEAD (C): ${hashes.hashMainHead}\n`);
51
+ process.stderr.write(' (current origin/main)\n');
52
+ process.stderr.write('\n');
53
+ process.stderr.write(`Merge directory: ${mergeDir}\n`);
54
+ process.stderr.write('\n');
55
+ }
56
+ async function main() {
57
+ const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
58
+ const featureName = (0, git_readAiBranchName_1.getFeatureName)();
59
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
60
+ const mergeDir = path.join(repoRoot, 'webpiecesTmp', `merge-${featureName}`);
61
+ fs.mkdirSync(mergeDir, { recursive: true });
62
+ validateCleanTree(currentBranch);
63
+ process.stderr.write('\n');
64
+ process.stderr.write(SEP);
65
+ process.stderr.write('📍 Gathering Merge Context\n');
66
+ process.stderr.write(SEP);
67
+ process.stderr.write('\n');
68
+ process.stderr.write('Fetching latest changes from origin/main...\n');
69
+ (0, child_process_1.spawnSync)('git', ['fetch', 'origin', 'main'], { stdio: 'inherit' });
70
+ await (0, git_findForkPoint_1.findForkPoint)('merge');
71
+ const hashesFile = path.join(mergeDir, 'updatemain-hashes.json');
72
+ const hashes = JSON.parse(fs.readFileSync(hashesFile, 'utf8'));
73
+ printHashPoints(hashes, currentBranch, mergeDir);
74
+ if (hashes.hashForkPoint === hashes.hashMainHead) {
75
+ process.stderr.write(SEP);
76
+ process.stderr.write('✅ Already up to date with main!\n');
77
+ process.stderr.write(SEP);
78
+ process.stderr.write('\n');
79
+ process.stderr.write('Your branch has not diverged from main.\n');
80
+ process.stderr.write('There are no new changes from main to merge.\n');
81
+ process.stderr.write('\n');
82
+ process.stderr.write(SEP);
83
+ process.exit(0);
84
+ }
85
+ process.stderr.write('Main has advanced. Merge will be needed.\n');
86
+ process.stderr.write('\n');
87
+ process.stderr.write(SEP);
88
+ process.stderr.write('\n');
89
+ }
90
+ if (require.main === module) {
91
+ main().catch((err) => {
92
+ const message = err instanceof Error ? err.message : String(err);
93
+ process.stderr.write(message + '\n');
94
+ process.exit(1);
95
+ });
96
+ }
97
+ //# sourceMappingURL=git-gatherInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-gatherInfo.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/scripts/git-gatherInfo.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { findForkPoint } from './workflow/git-findForkPoint';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\ninterface HashPoints {\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n}\n\nfunction validateCleanTree(currentBranch: string): void {\n if (currentBranch === 'main') {\n process.stderr.write('❌ Error: Already on main branch. No need to update from main.\\n');\n process.exit(1);\n }\n\n process.stderr.write(`Current branch: ${currentBranch}\\n`);\n\n const hasDirtyFiles = spawnSync('git', ['diff-index', '--quiet', 'HEAD', '--']).status !== 0;\n if (!hasDirtyFiles) return;\n\n const changedFiles = execSync('git diff --name-only HEAD', { encoding: 'utf8' }).trim();\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('❌ ERROR: You have uncommitted changes\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write('Please commit or stash your changes before updating from main.\\n');\n process.stderr.write('\\n');\n process.stderr.write('Files with changes:\\n');\n process.stderr.write(changedFiles + '\\n');\n process.stderr.write('\\n');\n process.stderr.write('\\x1b[1;31mTo commit your changes, run:\\n');\n process.stderr.write(' git add -A && git commit -m \"your message\"\\x1b[0m\\n');\n process.stderr.write('\\n');\n process.stderr.write('Or to stash them temporarily:\\n');\n process.stderr.write(' git stash\\n');\n process.stderr.write(' ./scripts/git-updateFromMain.sh\\n');\n process.stderr.write(' git stash pop\\n');\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.exit(1);\n}\n\nfunction printHashPoints(hashes: HashPoints, currentBranch: string, mergeDir: string): void {\n process.stderr.write('📍 The 3 Hash Points:\\n');\n process.stderr.write(` 1. Fork point (A): ${hashes.hashForkPoint}\\n`);\n process.stderr.write(` (where ${currentBranch} diverged from main)\\n`);\n process.stderr.write('\\n');\n process.stderr.write(` 2. Feature HEAD (B): ${hashes.hashFeatureHead}\\n`);\n process.stderr.write(` (tip of ${currentBranch})\\n`);\n process.stderr.write('\\n');\n process.stderr.write(` 3. Main HEAD (C): ${hashes.hashMainHead}\\n`);\n process.stderr.write(' (current origin/main)\\n');\n process.stderr.write('\\n');\n process.stderr.write(`Merge directory: ${mergeDir}\\n`);\n process.stderr.write('\\n');\n}\n\nexport async function main(): Promise<void> {\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const featureName = getFeatureName();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const mergeDir = path.join(repoRoot, 'webpiecesTmp', `merge-${featureName}`);\n fs.mkdirSync(mergeDir, { recursive: true });\n\n validateCleanTree(currentBranch);\n\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('📍 Gathering Merge Context\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write('Fetching latest changes from origin/main...\\n');\n spawnSync('git', ['fetch', 'origin', 'main'], { stdio: 'inherit' });\n\n await findForkPoint('merge');\n\n const hashesFile = path.join(mergeDir, 'updatemain-hashes.json');\n const hashes = JSON.parse(fs.readFileSync(hashesFile, 'utf8')) as HashPoints;\n\n printHashPoints(hashes, currentBranch, mergeDir);\n\n if (hashes.hashForkPoint === hashes.hashMainHead) {\n process.stderr.write(SEP);\n process.stderr.write('✅ Already up to date with main!\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write('Your branch has not diverged from main.\\n');\n process.stderr.write('There are no new changes from main to merge.\\n');\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.exit(0);\n }\n\n process.stderr.write('Main has advanced. Merge will be needed.\\n');\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ const child_process_1 = require("child_process");
5
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
6
+ async function main() {
7
+ process.stdout.write(SEP);
8
+ process.stdout.write('📝 Staging Merge Changes for Review\n');
9
+ process.stdout.write(SEP);
10
+ process.stdout.write('\n');
11
+ const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
12
+ const originMainResult = (0, child_process_1.spawnSync)('git', ['rev-parse', 'origin/main'], { encoding: 'utf8' });
13
+ const mainFallbackResult = (0, child_process_1.spawnSync)('git', ['rev-parse', 'main'], { encoding: 'utf8' });
14
+ const newForkPoint = (originMainResult.status === 0
15
+ ? (originMainResult.stdout ?? '')
16
+ : (mainFallbackResult.stdout ?? '')).trim();
17
+ const inMergeState = (0, child_process_1.spawnSync)('git', ['rev-parse', '--verify', 'MERGE_HEAD']).status === 0;
18
+ let oldForkPoint;
19
+ if (inMergeState) {
20
+ const mergeHead = (0, child_process_1.execSync)('git rev-parse MERGE_HEAD', { encoding: 'utf8' }).trim();
21
+ const result = (0, child_process_1.spawnSync)('git', ['merge-base', mergeHead, 'origin/main'], { encoding: 'utf8' });
22
+ oldForkPoint = (result.stdout ?? '').trim();
23
+ }
24
+ else {
25
+ const result = (0, child_process_1.spawnSync)('git', ['merge-base', 'HEAD', 'origin/main'], { encoding: 'utf8' });
26
+ oldForkPoint = (result.stdout ?? '').trim();
27
+ }
28
+ process.stdout.write(`Branch: ${currentBranch}\n`);
29
+ process.stdout.write(`Old fork point: ${oldForkPoint.slice(0, 12)}\n`);
30
+ process.stdout.write(`New fork point: ${newForkPoint.slice(0, 12)}\n`);
31
+ process.stdout.write('\n');
32
+ process.stdout.write('Staging all resolved changes...\n');
33
+ (0, child_process_1.spawnSync)('git', ['add', '-A'], { stdio: 'inherit' });
34
+ process.stdout.write('\n');
35
+ process.stdout.write(SEP);
36
+ process.stdout.write('✅ All changes staged for review\n');
37
+ process.stdout.write(SEP);
38
+ process.stdout.write('\n');
39
+ process.stdout.write('📋 Review staged changes with:\n');
40
+ process.stdout.write(' git diff --cached\n');
41
+ process.stdout.write('\n');
42
+ process.stdout.write('📋 View list of changed files:\n');
43
+ process.stdout.write(' git status\n');
44
+ process.stdout.write('\n');
45
+ process.stdout.write('⚠️ REVIEW CAREFULLY before committing!\n');
46
+ process.stdout.write('\n');
47
+ process.stdout.write('When ready to commit, the git-updateFromMain.sh script will continue.\n');
48
+ process.stdout.write('\n');
49
+ }
50
+ if (require.main === module) {
51
+ main().catch((err) => {
52
+ const message = err instanceof Error ? err.message : String(err);
53
+ process.stderr.write(message + '\n');
54
+ process.exit(1);
55
+ });
56
+ }
57
+ //# sourceMappingURL=git-mergeComplete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-mergeComplete.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/scripts/git-mergeComplete.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n process.stdout.write(SEP);\n process.stdout.write('📝 Staging Merge Changes for Review\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n\n const originMainResult = spawnSync('git', ['rev-parse', 'origin/main'], { encoding: 'utf8' });\n const mainFallbackResult = spawnSync('git', ['rev-parse', 'main'], { encoding: 'utf8' });\n const newForkPoint = (\n originMainResult.status === 0\n ? (originMainResult.stdout ?? '')\n : (mainFallbackResult.stdout ?? '')\n ).trim();\n\n const inMergeState = spawnSync('git', ['rev-parse', '--verify', 'MERGE_HEAD']).status === 0;\n\n let oldForkPoint: string;\n if (inMergeState) {\n const mergeHead = execSync('git rev-parse MERGE_HEAD', { encoding: 'utf8' }).trim();\n const result = spawnSync('git', ['merge-base', mergeHead, 'origin/main'], { encoding: 'utf8' });\n oldForkPoint = (result.stdout ?? '').trim();\n } else {\n const result = spawnSync('git', ['merge-base', 'HEAD', 'origin/main'], { encoding: 'utf8' });\n oldForkPoint = (result.stdout ?? '').trim();\n }\n\n process.stdout.write(`Branch: ${currentBranch}\\n`);\n process.stdout.write(`Old fork point: ${oldForkPoint.slice(0, 12)}\\n`);\n process.stdout.write(`New fork point: ${newForkPoint.slice(0, 12)}\\n`);\n process.stdout.write('\\n');\n\n process.stdout.write('Staging all resolved changes...\\n');\n spawnSync('git', ['add', '-A'], { stdio: 'inherit' });\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('✅ All changes staged for review\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('📋 Review staged changes with:\\n');\n process.stdout.write(' git diff --cached\\n');\n process.stdout.write('\\n');\n process.stdout.write('📋 View list of changed files:\\n');\n process.stdout.write(' git status\\n');\n process.stdout.write('\\n');\n process.stdout.write('⚠️ REVIEW CAREFULLY before committing!\\n');\n process.stdout.write('\\n');\n process.stdout.write('When ready to commit, the git-updateFromMain.sh script will continue.\\n');\n process.stdout.write('\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ const tslib_1 = require("tslib");
5
+ const child_process_1 = require("child_process");
6
+ const fs = tslib_1.__importStar(require("fs"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const readline = tslib_1.__importStar(require("readline"));
9
+ const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
10
+ const git_gatherInfo_1 = require("./git-gatherInfo");
11
+ const cleanTmp_1 = require("./workflow/cleanTmp");
12
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
13
+ function getAiMergePreference() {
14
+ const settingsFile = path.join(process.env['HOME'] ?? '', '.webpieces', 'settings.json');
15
+ if (!fs.existsSync(settingsFile))
16
+ return null;
17
+ const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
18
+ if (settings.ai_merge_conflicts === true)
19
+ return 'yes';
20
+ if (settings.ai_merge_conflicts === false)
21
+ return 'no';
22
+ return null;
23
+ }
24
+ function saveAiMergePreference(useAi) {
25
+ const settingsDir = path.join(process.env['HOME'] ?? '', '.webpieces');
26
+ const settingsFile = path.join(settingsDir, 'settings.json');
27
+ fs.mkdirSync(settingsDir, { recursive: true });
28
+ let settings = {};
29
+ if (fs.existsSync(settingsFile)) {
30
+ settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
31
+ }
32
+ settings.ai_merge_conflicts = useAi;
33
+ fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n');
34
+ }
35
+ function askQuestion(rl, question) {
36
+ return new Promise((resolve) => {
37
+ rl.question(question, resolve);
38
+ });
39
+ }
40
+ function saveConflictContext(conflictedFiles, mergeDir, forkPoint, featureHead, mainHead) {
41
+ for (const file of conflictedFiles) {
42
+ const safePath = file.replace(/\//g, '__');
43
+ const fileDir = path.join(mergeDir, `updatemain-${safePath}`);
44
+ fs.mkdirSync(fileDir, { recursive: true });
45
+ const forkContent = (0, child_process_1.spawnSync)('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });
46
+ fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), forkContent.status === 0 ? (forkContent.stdout ?? '') : '(file did not exist)\n');
47
+ const featureContent = (0, child_process_1.spawnSync)('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });
48
+ fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), featureContent.status === 0 ? (featureContent.stdout ?? '') : '(file did not exist)\n');
49
+ const mainContent = (0, child_process_1.spawnSync)('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });
50
+ fs.writeFileSync(path.join(fileDir, 'C-main.txt'), mainContent.status === 0 ? (mainContent.stdout ?? '') : '(file did not exist)\n');
51
+ const baResult = (0, child_process_1.spawnSync)('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });
52
+ fs.writeFileSync(path.join(fileDir, 'B-A.diff'), baResult.stdout ?? '');
53
+ const caResult = (0, child_process_1.spawnSync)('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });
54
+ fs.writeFileSync(path.join(fileDir, 'C-A.diff'), caResult.stdout ?? '');
55
+ }
56
+ }
57
+ async function waitForCleanCommit(rl, prompt) {
58
+ let committed = false;
59
+ while (!committed) {
60
+ const ans = await askQuestion(rl, prompt);
61
+ process.stdout.write('\n');
62
+ if (ans.toLowerCase() === 'y') {
63
+ const isClean = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', 'HEAD', '--']).status === 0;
64
+ if (isClean) {
65
+ committed = true;
66
+ }
67
+ else {
68
+ process.stdout.write('❌ You still have uncommitted changes\n\n');
69
+ }
70
+ }
71
+ }
72
+ }
73
+ async function resolveAiMerge(rl, repoRoot, mergeDir) {
74
+ process.stdout.write('\n' + SEP + '🤖 Calling AI to Resolve Conflicts\n' + SEP + '\n');
75
+ (0, child_process_1.spawnSync)('claude', [
76
+ '--allowed-tools', 'Edit Write Read Bash Glob Grep',
77
+ '--append-system-prompt',
78
+ 'Read .claude/commands/wp-merge.md and follow ALL instructions in that file to resolve the merge conflicts.',
79
+ 'Start resolving the merge conflicts now.',
80
+ ], { stdio: 'inherit', cwd: repoRoot });
81
+ process.stdout.write('\n' + SEP + '✅ AI Merge Summary ✅\n' + SEP + '\n');
82
+ process.stdout.write('Review what I did before committing:\n');
83
+ process.stdout.write(" 1. Read each file's resolution details BELOW (quick read)\n");
84
+ process.stdout.write(' 2. Diff each file in your IDE making sure AI did nothing extra\n');
85
+ process.stdout.write(' 3. Delete any remaining A/B/C comment blocks in the code\n\n');
86
+ process.stdout.write(`Full merge context available in: ${mergeDir}\n\n`);
87
+ const mergeSummaryFile = path.join(mergeDir, 'merge-summary.md');
88
+ if (fs.existsSync(mergeSummaryFile)) {
89
+ process.stdout.write(fs.readFileSync(mergeSummaryFile, 'utf8'));
90
+ }
91
+ else {
92
+ process.stdout.write('ℹ️ No merge summary file was generated by AI.\n');
93
+ process.stdout.write(` (Expected: ${mergeSummaryFile})\n`);
94
+ }
95
+ process.stdout.write('\n' + SEP + '⚠️ IMPORTANT: SCROLL UP to AI Merge Summary section\n' + SEP + '\n');
96
+ process.stdout.write('When done reviewing, run:\n\n git add -A && git commit -m "Merge main into feature branch"\n\n');
97
+ await waitForCleanCommit(rl, 'Have you scrolled up to ✅ AI Merge Summary ✅ and done a quick read? Did you commit it per instructions? (y/n) ');
98
+ fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');
99
+ process.stdout.write('\n' + SEP);
100
+ }
101
+ async function resolveManualMerge(rl, mergeDir) {
102
+ process.stdout.write('\n' + SEP + '🛠️ Manual Merge Required\n' + SEP + '\n');
103
+ let committed = false;
104
+ while (!committed) {
105
+ process.stdout.write('Please resolve conflicts manually\n');
106
+ process.stdout.write(`Merge context available in: ${mergeDir}\n\n`);
107
+ const ans = await askQuestion(rl, 'Are you done merging and committing? (y/n) ');
108
+ process.stdout.write('\n');
109
+ if (ans.toLowerCase() === 'y') {
110
+ const isClean = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', 'HEAD', '--']).status === 0;
111
+ if (isClean) {
112
+ committed = true;
113
+ }
114
+ else {
115
+ process.stdout.write('❌ You still have uncommitted changes\n\n');
116
+ }
117
+ }
118
+ }
119
+ fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');
120
+ }
121
+ async function handleConflicts(currentBranch, mergeDir, hashes, rl, repoRoot) {
122
+ process.stdout.write('\n' + SEP + '⚠️ Conflicts Detected\n' + SEP + '\n');
123
+ process.stdout.write('Conflicting files:\n');
124
+ const conflictedFilesRaw = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();
125
+ process.stdout.write(conflictedFilesRaw + '\n\n');
126
+ fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), conflictedFilesRaw + '\n');
127
+ const conflictedFiles = conflictedFilesRaw.split('\n').filter((f) => f.trim() !== '');
128
+ saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);
129
+ process.stdout.write(`✅ Merge context saved to: ${mergeDir}\n\n`);
130
+ const settingsFile = path.join(process.env['HOME'] ?? '', '.webpieces', 'settings.json');
131
+ const savedPref = getAiMergePreference();
132
+ let useAi;
133
+ if (savedPref !== null) {
134
+ useAi = savedPref === 'yes';
135
+ process.stdout.write(`Using saved preference: ${useAi ? 'AI merge' : 'Manual merge'} (from ${settingsFile})\n`);
136
+ process.stdout.write(`To change, edit ${settingsFile} and set "ai_merge_conflicts"\n\n`);
137
+ }
138
+ else {
139
+ process.stdout.write(SEP + `⚠️ Your choice will be saved to: ${settingsFile}\n` + ' You can edit this file later to change your preference.\n' + SEP + '\n');
140
+ const answer = await askQuestion(rl, 'Would you like AI to help resolve conflicts? (y/n) ');
141
+ process.stdout.write('\n');
142
+ useAi = answer.toLowerCase() === 'y';
143
+ saveAiMergePreference(useAi);
144
+ process.stdout.write(`✅ Saved preference: ${useAi ? 'AI merge' : 'Manual merge'}\n\n`);
145
+ }
146
+ if (useAi) {
147
+ await resolveAiMerge(rl, repoRoot, mergeDir);
148
+ }
149
+ else {
150
+ await resolveManualMerge(rl, mergeDir);
151
+ }
152
+ void currentBranch;
153
+ }
154
+ function printFinalSummary(currentBranch, backupBranch, prNumber, mergeDir, hasRemote) {
155
+ process.stdout.write('\n' + SEP);
156
+ if (hasRemote) {
157
+ process.stdout.write(prNumber ? `✅ Successfully Updated PR #${prNumber}\n` : '✅ Successfully Updated Remote Branch\n');
158
+ }
159
+ else {
160
+ process.stdout.write('✅ Branch Updated from Main\n');
161
+ }
162
+ process.stdout.write(SEP + '\n📋 Summary:\n');
163
+ process.stdout.write(` Branch: ${currentBranch}\n`);
164
+ if (hasRemote && prNumber) {
165
+ process.stdout.write(` PR: #${prNumber}\n`);
166
+ }
167
+ else if (!hasRemote) {
168
+ process.stdout.write(' Base: main (latest)\n');
169
+ }
170
+ else {
171
+ process.stdout.write(' PR: (none found - create with gh pr create)\n');
172
+ }
173
+ process.stdout.write(` Backup: ${backupBranch}\n`);
174
+ process.stdout.write(` Merge context: ${mergeDir}\n`);
175
+ process.stdout.write('\nNext steps:\n');
176
+ if (hasRemote) {
177
+ process.stdout.write(' 1. Review changes on GitHub\n');
178
+ process.stdout.write(' 2. Continue development or create more commits\n');
179
+ }
180
+ else {
181
+ process.stdout.write(' 1. Test your changes\n');
182
+ process.stdout.write(' 2. Create PR with: gh pr create\n');
183
+ }
184
+ process.stdout.write(` 3. Delete old backup when safe: git branch -D ${backupBranch}\n\n`);
185
+ process.stdout.write(SEP);
186
+ }
187
+ function createBackup(currentBranch) {
188
+ process.stdout.write('\n' + SEP + '💾 Creating Incremental Backup\n' + SEP + '\n');
189
+ let n = 1;
190
+ while ((0, child_process_1.spawnSync)('git', ['show-ref', '--verify', '--quiet', `refs/heads/${currentBranch}Backup${n}`]).status === 0) {
191
+ n += 1;
192
+ }
193
+ const backupBranch = `${currentBranch}Backup${n}`;
194
+ process.stdout.write(`Creating backup: ${backupBranch}\n`);
195
+ (0, child_process_1.spawnSync)('git', ['checkout', '-b', backupBranch], { stdio: 'inherit' });
196
+ (0, child_process_1.spawnSync)('git', ['checkout', currentBranch], { stdio: 'inherit' });
197
+ process.stdout.write(`✅ Backup created: ${backupBranch}\n\n`);
198
+ return backupBranch;
199
+ }
200
+ async function finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber, mergeDir) {
201
+ process.stdout.write('\n' + SEP + '🗑️ Cleaning Up Old Branch\n' + SEP + '\n');
202
+ process.stdout.write(`Deleting local branch: ${currentBranch} (backed up as ${backupBranch})\n`);
203
+ (0, child_process_1.spawnSync)('git', ['branch', '-D', currentBranch], { stdio: 'inherit' });
204
+ process.stdout.write('\n');
205
+ const remoteExists = (0, child_process_1.spawnSync)('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;
206
+ if (remoteExists) {
207
+ process.stdout.write(SEP + (prNumber ? `🔍 Updating Existing PR #${prNumber}\n` : '🔍 Updating Remote Branch (no PR found)\n') + SEP + '\n');
208
+ if (prNumber) {
209
+ process.stdout.write(`✅ Updating PR #${prNumber} with squashed changes\n`);
210
+ }
211
+ else {
212
+ process.stdout.write('⚠️ Remote branch exists but no PR found (PR check may have failed)\n Syncing remote branch anyway...\n');
213
+ }
214
+ process.stdout.write(`\nForce pushing ${squashBranch} to origin/${currentBranch}...\n`);
215
+ (0, child_process_1.spawnSync)('git', ['push', '-u', '--force-with-lease', 'origin', `${squashBranch}:${currentBranch}`], { stdio: 'inherit' });
216
+ (0, child_process_1.spawnSync)('git', ['checkout', squashBranch], { stdio: 'inherit' });
217
+ (0, child_process_1.spawnSync)('git', ['branch', '-m', currentBranch], { stdio: 'inherit' });
218
+ }
219
+ else {
220
+ process.stdout.write(SEP + '📝 No Remote Branch to Update\n' + SEP + '\n');
221
+ (0, child_process_1.spawnSync)('git', ['checkout', squashBranch], { stdio: 'inherit' });
222
+ (0, child_process_1.spawnSync)('git', ['branch', '-m', currentBranch], { stdio: 'inherit' });
223
+ process.stdout.write(`ℹ️ No remote branch found for ${currentBranch} (local only)\n\n`);
224
+ }
225
+ printFinalSummary(currentBranch, backupBranch, prNumber, mergeDir, remoteExists);
226
+ }
227
+ async function main() {
228
+ const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
229
+ const featureName = (0, git_readAiBranchName_1.getFeatureName)();
230
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
231
+ const mergeDir = path.join(repoRoot, 'webpiecesTmp', `merge-${featureName}`);
232
+ fs.mkdirSync(mergeDir, { recursive: true });
233
+ process.stdout.write('\n' + SEP + '🔄 Squash-Merge Workflow\n' + SEP + '\n');
234
+ process.stdout.write('Gathering merge context...\n');
235
+ await (0, git_gatherInfo_1.main)();
236
+ const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8'));
237
+ process.stdout.write('\nChecking for existing PR...\n');
238
+ const prResult = (0, child_process_1.spawnSync)('gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'], { encoding: 'utf8' });
239
+ const prNumber = prResult.status === 0 ? (prResult.stdout ?? '').trim() : '';
240
+ process.stdout.write(prNumber ? `✅ Found existing PR #${prNumber} (will be updated after merge)\n\n` : 'ℹ️ No existing PR found (you can create one later with gh pr create)\n\n');
241
+ const backupBranch = createBackup(currentBranch);
242
+ process.stdout.write(SEP + '🔄 Creating Temporary Squash Branch\n' + SEP + '\n');
243
+ const squashBranch = `${currentBranch}Squash`;
244
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
245
+ if ((0, child_process_1.spawnSync)('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {
246
+ process.stdout.write(`⚠️ Found existing ${squashBranch} from previous run\n`);
247
+ const answer = await askQuestion(rl, 'Delete and start fresh? (y/n) ');
248
+ process.stdout.write('\n');
249
+ if (answer.toLowerCase() === 'y') {
250
+ (0, child_process_1.spawnSync)('git', ['branch', '-D', squashBranch], { stdio: 'inherit' });
251
+ }
252
+ else {
253
+ process.stdout.write('❌ Aborting. Please clean up manually.\n');
254
+ rl.close();
255
+ process.exit(1);
256
+ }
257
+ }
258
+ process.stdout.write('Updating local main branch...\n');
259
+ (0, child_process_1.spawnSync)('git', ['checkout', 'main'], { stdio: 'inherit' });
260
+ (0, child_process_1.spawnSync)('git', ['pull', 'origin', 'main'], { stdio: 'inherit' });
261
+ process.stdout.write(`Creating new branch: ${squashBranch} from main...\n\n`);
262
+ (0, child_process_1.spawnSync)('git', ['checkout', '-b', squashBranch], { stdio: 'inherit' });
263
+ process.stdout.write(SEP + `🔀 Squash Merging ${currentBranch}\n` + SEP + '\n');
264
+ const mergeResult = (0, child_process_1.spawnSync)('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });
265
+ if (mergeResult.status === 0) {
266
+ process.stdout.write('\n✅ Squash merge successful (no conflicts)\n\n');
267
+ const nothingStaged = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;
268
+ if (nothingStaged) {
269
+ process.stdout.write('ℹ️ Branch already up-to-date with main (nothing to merge)\n');
270
+ }
271
+ else {
272
+ (0, child_process_1.spawnSync)('git', ['commit', '-m', `Squash merge of ${currentBranch}`], { stdio: 'inherit' });
273
+ }
274
+ }
275
+ else {
276
+ await handleConflicts(currentBranch, mergeDir, hashes, rl, repoRoot);
277
+ }
278
+ rl.close();
279
+ await finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber, mergeDir);
280
+ await (0, cleanTmp_1.main)();
281
+ }
282
+ if (require.main === module) {
283
+ main().catch((err) => {
284
+ const message = err instanceof Error ? err.message : String(err);
285
+ process.stderr.write(message + '\n');
286
+ process.exit(1);
287
+ });
288
+ }
289
+ //# sourceMappingURL=git-updateFromMain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-updateFromMain.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/scripts/git-updateFromMain.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as readline from 'readline';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { main as gatherInfo } from './git-gatherInfo';\nimport { main as cleanTmp } from './workflow/cleanTmp';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\ninterface WebpiecesSettings {\n ai_merge_conflicts?: boolean;\n}\n\ninterface HashPoints {\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n}\n\nfunction getAiMergePreference(): 'yes' | 'no' | null {\n const settingsFile = path.join(process.env['HOME'] ?? '', '.webpieces', 'settings.json');\n if (!fs.existsSync(settingsFile)) return null;\n const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')) as WebpiecesSettings;\n if (settings.ai_merge_conflicts === true) return 'yes';\n if (settings.ai_merge_conflicts === false) return 'no';\n return null;\n}\n\nfunction saveAiMergePreference(useAi: boolean): void {\n const settingsDir = path.join(process.env['HOME'] ?? '', '.webpieces');\n const settingsFile = path.join(settingsDir, 'settings.json');\n fs.mkdirSync(settingsDir, { recursive: true });\n let settings: WebpiecesSettings = {};\n if (fs.existsSync(settingsFile)) {\n settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')) as WebpiecesSettings;\n }\n settings.ai_merge_conflicts = useAi;\n fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\\n');\n}\n\nfunction askQuestion(rl: readline.Interface, question: string): Promise<string> {\n return new Promise<string>((resolve: (answer: string) => void) => {\n rl.question(question, resolve);\n });\n}\n\nfunction saveConflictContext(conflictedFiles: string[], mergeDir: string, forkPoint: string, featureHead: string, mainHead: string): void {\n for (const file of conflictedFiles) {\n const safePath = file.replace(/\\//g, '__');\n const fileDir = path.join(mergeDir, `updatemain-${safePath}`);\n fs.mkdirSync(fileDir, { recursive: true });\n\n const forkContent = spawnSync('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), forkContent.status === 0 ? (forkContent.stdout ?? '') : '(file did not exist)\\n');\n\n const featureContent = spawnSync('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), featureContent.status === 0 ? (featureContent.stdout ?? '') : '(file did not exist)\\n');\n\n const mainContent = spawnSync('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-main.txt'), mainContent.status === 0 ? (mainContent.stdout ?? '') : '(file did not exist)\\n');\n\n const baResult = spawnSync('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-A.diff'), baResult.stdout ?? '');\n\n const caResult = spawnSync('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-A.diff'), caResult.stdout ?? '');\n }\n}\n\nasync function waitForCleanCommit(rl: readline.Interface, prompt: string): Promise<void> {\n let committed = false;\n while (!committed) {\n const ans = await askQuestion(rl, prompt);\n process.stdout.write('\\n');\n if (ans.toLowerCase() === 'y') {\n const isClean = spawnSync('git', ['diff-index', '--quiet', 'HEAD', '--']).status === 0;\n if (isClean) {\n committed = true;\n } else {\n process.stdout.write('❌ You still have uncommitted changes\\n\\n');\n }\n }\n }\n}\n\nasync function resolveAiMerge(rl: readline.Interface, repoRoot: string, mergeDir: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '🤖 Calling AI to Resolve Conflicts\\n' + SEP + '\\n');\n\n spawnSync('claude', [\n '--allowed-tools', 'Edit Write Read Bash Glob Grep',\n '--append-system-prompt',\n 'Read .claude/commands/wp-merge.md and follow ALL instructions in that file to resolve the merge conflicts.',\n 'Start resolving the merge conflicts now.',\n ], { stdio: 'inherit', cwd: repoRoot });\n\n process.stdout.write('\\n' + SEP + '✅ AI Merge Summary ✅\\n' + SEP + '\\n');\n process.stdout.write('Review what I did before committing:\\n');\n process.stdout.write(\" 1. Read each file's resolution details BELOW (quick read)\\n\");\n process.stdout.write(' 2. Diff each file in your IDE making sure AI did nothing extra\\n');\n process.stdout.write(' 3. Delete any remaining A/B/C comment blocks in the code\\n\\n');\n process.stdout.write(`Full merge context available in: ${mergeDir}\\n\\n`);\n\n const mergeSummaryFile = path.join(mergeDir, 'merge-summary.md');\n if (fs.existsSync(mergeSummaryFile)) {\n process.stdout.write(fs.readFileSync(mergeSummaryFile, 'utf8'));\n } else {\n process.stdout.write('ℹ️ No merge summary file was generated by AI.\\n');\n process.stdout.write(` (Expected: ${mergeSummaryFile})\\n`);\n }\n\n process.stdout.write('\\n' + SEP + '⚠️ IMPORTANT: SCROLL UP to AI Merge Summary section\\n' + SEP + '\\n');\n process.stdout.write('When done reviewing, run:\\n\\n git add -A && git commit -m \"Merge main into feature branch\"\\n\\n');\n\n await waitForCleanCommit(rl, 'Have you scrolled up to ✅ AI Merge Summary ✅ and done a quick read? Did you commit it per instructions? (y/n) ');\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n process.stdout.write('\\n' + SEP);\n}\n\nasync function resolveManualMerge(rl: readline.Interface, mergeDir: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '🛠️ Manual Merge Required\\n' + SEP + '\\n');\n\n let committed = false;\n while (!committed) {\n process.stdout.write('Please resolve conflicts manually\\n');\n process.stdout.write(`Merge context available in: ${mergeDir}\\n\\n`);\n\n const ans = await askQuestion(rl, 'Are you done merging and committing? (y/n) ');\n process.stdout.write('\\n');\n\n if (ans.toLowerCase() === 'y') {\n const isClean = spawnSync('git', ['diff-index', '--quiet', 'HEAD', '--']).status === 0;\n if (isClean) {\n committed = true;\n } else {\n process.stdout.write('❌ You still have uncommitted changes\\n\\n');\n }\n }\n }\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n}\n\nasync function handleConflicts(currentBranch: string, mergeDir: string, hashes: HashPoints, rl: readline.Interface, repoRoot: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '⚠️ Conflicts Detected\\n' + SEP + '\\n');\n process.stdout.write('Conflicting files:\\n');\n\n const conflictedFilesRaw = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n process.stdout.write(conflictedFilesRaw + '\\n\\n');\n\n fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), conflictedFilesRaw + '\\n');\n const conflictedFiles = conflictedFilesRaw.split('\\n').filter((f: string) => f.trim() !== '');\n\n saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);\n process.stdout.write(`✅ Merge context saved to: ${mergeDir}\\n\\n`);\n\n const settingsFile = path.join(process.env['HOME'] ?? '', '.webpieces', 'settings.json');\n const savedPref = getAiMergePreference();\n let useAi: boolean;\n\n if (savedPref !== null) {\n useAi = savedPref === 'yes';\n process.stdout.write(`Using saved preference: ${useAi ? 'AI merge' : 'Manual merge'} (from ${settingsFile})\\n`);\n process.stdout.write(`To change, edit ${settingsFile} and set \"ai_merge_conflicts\"\\n\\n`);\n } else {\n process.stdout.write(SEP + `⚠️ Your choice will be saved to: ${settingsFile}\\n` + ' You can edit this file later to change your preference.\\n' + SEP + '\\n');\n const answer = await askQuestion(rl, 'Would you like AI to help resolve conflicts? (y/n) ');\n process.stdout.write('\\n');\n useAi = answer.toLowerCase() === 'y';\n saveAiMergePreference(useAi);\n process.stdout.write(`✅ Saved preference: ${useAi ? 'AI merge' : 'Manual merge'}\\n\\n`);\n }\n\n if (useAi) {\n await resolveAiMerge(rl, repoRoot, mergeDir);\n } else {\n await resolveManualMerge(rl, mergeDir);\n }\n\n void currentBranch;\n}\n\nfunction printFinalSummary(currentBranch: string, backupBranch: string, prNumber: string, mergeDir: string, hasRemote: boolean): void {\n process.stdout.write('\\n' + SEP);\n if (hasRemote) {\n process.stdout.write(prNumber ? `✅ Successfully Updated PR #${prNumber}\\n` : '✅ Successfully Updated Remote Branch\\n');\n } else {\n process.stdout.write('✅ Branch Updated from Main\\n');\n }\n process.stdout.write(SEP + '\\n📋 Summary:\\n');\n process.stdout.write(` Branch: ${currentBranch}\\n`);\n if (hasRemote && prNumber) {\n process.stdout.write(` PR: #${prNumber}\\n`);\n } else if (!hasRemote) {\n process.stdout.write(' Base: main (latest)\\n');\n } else {\n process.stdout.write(' PR: (none found - create with gh pr create)\\n');\n }\n process.stdout.write(` Backup: ${backupBranch}\\n`);\n process.stdout.write(` Merge context: ${mergeDir}\\n`);\n process.stdout.write('\\nNext steps:\\n');\n if (hasRemote) {\n process.stdout.write(' 1. Review changes on GitHub\\n');\n process.stdout.write(' 2. Continue development or create more commits\\n');\n } else {\n process.stdout.write(' 1. Test your changes\\n');\n process.stdout.write(' 2. Create PR with: gh pr create\\n');\n }\n process.stdout.write(` 3. Delete old backup when safe: git branch -D ${backupBranch}\\n\\n`);\n process.stdout.write(SEP);\n}\n\nfunction createBackup(currentBranch: string): string {\n process.stdout.write('\\n' + SEP + '💾 Creating Incremental Backup\\n' + SEP + '\\n');\n let n = 1;\n while (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${currentBranch}Backup${n}`]).status === 0) {\n n += 1;\n }\n const backupBranch = `${currentBranch}Backup${n}`;\n process.stdout.write(`Creating backup: ${backupBranch}\\n`);\n spawnSync('git', ['checkout', '-b', backupBranch], { stdio: 'inherit' });\n spawnSync('git', ['checkout', currentBranch], { stdio: 'inherit' });\n process.stdout.write(`✅ Backup created: ${backupBranch}\\n\\n`);\n return backupBranch;\n}\n\nasync function finalizeBranch(currentBranch: string, squashBranch: string, backupBranch: string, prNumber: string, mergeDir: string): Promise<void> {\n process.stdout.write('\\n' + SEP + '🗑️ Cleaning Up Old Branch\\n' + SEP + '\\n');\n process.stdout.write(`Deleting local branch: ${currentBranch} (backed up as ${backupBranch})\\n`);\n spawnSync('git', ['branch', '-D', currentBranch], { stdio: 'inherit' });\n process.stdout.write('\\n');\n\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;\n\n if (remoteExists) {\n process.stdout.write(SEP + (prNumber ? `🔍 Updating Existing PR #${prNumber}\\n` : '🔍 Updating Remote Branch (no PR found)\\n') + SEP + '\\n');\n if (prNumber) {\n process.stdout.write(`✅ Updating PR #${prNumber} with squashed changes\\n`);\n } else {\n process.stdout.write('⚠️ Remote branch exists but no PR found (PR check may have failed)\\n Syncing remote branch anyway...\\n');\n }\n process.stdout.write(`\\nForce pushing ${squashBranch} to origin/${currentBranch}...\\n`);\n spawnSync('git', ['push', '-u', '--force-with-lease', 'origin', `${squashBranch}:${currentBranch}`], { stdio: 'inherit' });\n spawnSync('git', ['checkout', squashBranch], { stdio: 'inherit' });\n spawnSync('git', ['branch', '-m', currentBranch], { stdio: 'inherit' });\n } else {\n process.stdout.write(SEP + '📝 No Remote Branch to Update\\n' + SEP + '\\n');\n spawnSync('git', ['checkout', squashBranch], { stdio: 'inherit' });\n spawnSync('git', ['branch', '-m', currentBranch], { stdio: 'inherit' });\n process.stdout.write(`ℹ️ No remote branch found for ${currentBranch} (local only)\\n\\n`);\n }\n\n printFinalSummary(currentBranch, backupBranch, prNumber, mergeDir, remoteExists);\n}\n\nexport async function main(): Promise<void> {\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const featureName = getFeatureName();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const mergeDir = path.join(repoRoot, 'webpiecesTmp', `merge-${featureName}`);\n fs.mkdirSync(mergeDir, { recursive: true });\n\n process.stdout.write('\\n' + SEP + '🔄 Squash-Merge Workflow\\n' + SEP + '\\n');\n process.stdout.write('Gathering merge context...\\n');\n await gatherInfo();\n\n const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8')) as HashPoints;\n\n process.stdout.write('\\nChecking for existing PR...\\n');\n const prResult = spawnSync('gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'], { encoding: 'utf8' });\n const prNumber = prResult.status === 0 ? (prResult.stdout ?? '').trim() : '';\n process.stdout.write(prNumber ? `✅ Found existing PR #${prNumber} (will be updated after merge)\\n\\n` : 'ℹ️ No existing PR found (you can create one later with gh pr create)\\n\\n');\n\n const backupBranch = createBackup(currentBranch);\n\n process.stdout.write(SEP + '🔄 Creating Temporary Squash Branch\\n' + SEP + '\\n');\n const squashBranch = `${currentBranch}Squash`;\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {\n process.stdout.write(`⚠️ Found existing ${squashBranch} from previous run\\n`);\n const answer = await askQuestion(rl, 'Delete and start fresh? (y/n) ');\n process.stdout.write('\\n');\n if (answer.toLowerCase() === 'y') {\n spawnSync('git', ['branch', '-D', squashBranch], { stdio: 'inherit' });\n } else {\n process.stdout.write('❌ Aborting. Please clean up manually.\\n');\n rl.close();\n process.exit(1);\n }\n }\n\n process.stdout.write('Updating local main branch...\\n');\n spawnSync('git', ['checkout', 'main'], { stdio: 'inherit' });\n spawnSync('git', ['pull', 'origin', 'main'], { stdio: 'inherit' });\n process.stdout.write(`Creating new branch: ${squashBranch} from main...\\n\\n`);\n spawnSync('git', ['checkout', '-b', squashBranch], { stdio: 'inherit' });\n\n process.stdout.write(SEP + `🔀 Squash Merging ${currentBranch}\\n` + SEP + '\\n');\n const mergeResult = spawnSync('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });\n\n if (mergeResult.status === 0) {\n process.stdout.write('\\n✅ Squash merge successful (no conflicts)\\n\\n');\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (nothingStaged) {\n process.stdout.write('ℹ️ Branch already up-to-date with main (nothing to merge)\\n');\n } else {\n spawnSync('git', ['commit', '-m', `Squash merge of ${currentBranch}`], { stdio: 'inherit' });\n }\n } else {\n await handleConflicts(currentBranch, mergeDir, hashes, rl, repoRoot);\n }\n\n rl.close();\n await finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber, mergeDir);\n await cleanTmp();\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ const tslib_1 = require("tslib");
5
+ const child_process_1 = require("child_process");
6
+ const fs = tslib_1.__importStar(require("fs"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const CUTOFF_DAYS = 30;
9
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
10
+ async function main() {
11
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
12
+ const tmpBase = path.join(repoRoot, 'webpiecesTmp');
13
+ if (!fs.existsSync(tmpBase)) {
14
+ return;
15
+ }
16
+ process.stdout.write('\n');
17
+ process.stdout.write(SEP);
18
+ process.stdout.write('🧹 Cleaning Old Temporary Directories\n');
19
+ process.stdout.write(SEP);
20
+ process.stdout.write('\n');
21
+ process.stdout.write(`Location: ${tmpBase}\n`);
22
+ process.stdout.write(`Retention: ${CUTOFF_DAYS} days\n`);
23
+ process.stdout.write('\n');
24
+ const cutoffMs = CUTOFF_DAYS * 24 * 60 * 60 * 1000;
25
+ const now = Date.now();
26
+ let deletedCount = 0;
27
+ const entries = fs.readdirSync(tmpBase);
28
+ for (const entry of entries) {
29
+ const fullPath = path.join(tmpBase, entry);
30
+ const stat = fs.statSync(fullPath);
31
+ if (!stat.isDirectory())
32
+ continue;
33
+ if (now - stat.mtimeMs < cutoffMs)
34
+ continue;
35
+ process.stdout.write(` 🗑️ Deleting: ${entry}\n`);
36
+ fs.rmSync(fullPath, { recursive: true, force: true });
37
+ deletedCount += 1;
38
+ }
39
+ if (deletedCount === 0) {
40
+ process.stdout.write(` ✅ No directories older than ${CUTOFF_DAYS} days found\n`);
41
+ }
42
+ else {
43
+ process.stdout.write('\n');
44
+ process.stdout.write(` ✅ Deleted ${deletedCount} old director${deletedCount === 1 ? 'y' : 'ies'}\n`);
45
+ }
46
+ process.stdout.write('\n');
47
+ process.stdout.write(SEP);
48
+ process.stdout.write('\n');
49
+ }
50
+ if (require.main === module) {
51
+ main().catch((err) => {
52
+ const message = err instanceof Error ? err.message : String(err);
53
+ process.stderr.write(message + '\n');
54
+ process.exit(1);
55
+ });
56
+ }
57
+ //# sourceMappingURL=cleanTmp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanTmp.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/scripts/workflow/cleanTmp.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nconst CUTOFF_DAYS = 30;\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const tmpBase = path.join(repoRoot, 'webpiecesTmp');\n\n if (!fs.existsSync(tmpBase)) {\n return;\n }\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('🧹 Cleaning Old Temporary Directories\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write(`Location: ${tmpBase}\\n`);\n process.stdout.write(`Retention: ${CUTOFF_DAYS} days\\n`);\n process.stdout.write('\\n');\n\n const cutoffMs = CUTOFF_DAYS * 24 * 60 * 60 * 1000;\n const now = Date.now();\n let deletedCount = 0;\n\n const entries = fs.readdirSync(tmpBase);\n for (const entry of entries) {\n const fullPath = path.join(tmpBase, entry);\n const stat = fs.statSync(fullPath);\n if (!stat.isDirectory()) continue;\n if (now - stat.mtimeMs < cutoffMs) continue;\n\n process.stdout.write(` 🗑️ Deleting: ${entry}\\n`);\n fs.rmSync(fullPath, { recursive: true, force: true });\n deletedCount += 1;\n }\n\n if (deletedCount === 0) {\n process.stdout.write(` ✅ No directories older than ${CUTOFF_DAYS} days found\\n`);\n } else {\n process.stdout.write('\\n');\n process.stdout.write(` ✅ Deleted ${deletedCount} old director${deletedCount === 1 ? 'y' : 'ies'}\\n`);\n }\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function findForkPoint(workflow: string): Promise<void>;
2
+ export declare function main(): Promise<void>;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findForkPoint = findForkPoint;
4
+ exports.main = main;
5
+ const tslib_1 = require("tslib");
6
+ const child_process_1 = require("child_process");
7
+ const fs = tslib_1.__importStar(require("fs"));
8
+ const path = tslib_1.__importStar(require("path"));
9
+ const git_readAiBranchName_1 = require("./git-readAiBranchName");
10
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
11
+ function printMergeFromMainError(commit, parent, featureName, currentBranch) {
12
+ process.stderr.write('\n');
13
+ process.stderr.write(SEP);
14
+ process.stderr.write('❌ This branch merged main without git-updateFromMain.sh\n');
15
+ process.stderr.write(SEP);
16
+ process.stderr.write('\n');
17
+ process.stderr.write(`Merge commit detected: ${commit}\n`);
18
+ process.stderr.write(`Parent from main: ${parent}\n`);
19
+ process.stderr.write('\n');
20
+ process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\n');
21
+ process.stderr.write('\n');
22
+ process.stderr.write('1. Switch to main branch:\n');
23
+ process.stderr.write(' git checkout main\n');
24
+ process.stderr.write('\n');
25
+ process.stderr.write('2. Pull latest changes:\n');
26
+ process.stderr.write(' git pull\n');
27
+ process.stderr.write('\n');
28
+ process.stderr.write('3. Create new branch with a new name:\n');
29
+ process.stderr.write(` git checkout -b ${featureName}-v2\n`);
30
+ process.stderr.write('\n');
31
+ process.stderr.write('4. Squash merge your old branch:\n');
32
+ process.stderr.write(` git merge --squash ${currentBranch}\n`);
33
+ process.stderr.write('\n');
34
+ process.stderr.write('5. Commit the squashed changes:\n');
35
+ process.stderr.write(` git add -A && git commit -m "Squashed from ${currentBranch}"\n`);
36
+ process.stderr.write('\n');
37
+ process.stderr.write('6. If you have an existing PR:\n');
38
+ process.stderr.write(` - Create a NEW PR for ${featureName}-v2\n`);
39
+ process.stderr.write(` - Close the old PR for ${currentBranch}\n`);
40
+ process.stderr.write('\n');
41
+ process.stderr.write(SEP);
42
+ process.stderr.write('\n');
43
+ }
44
+ function checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch) {
45
+ process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\n`);
46
+ for (const commit of mergeCommits) {
47
+ const parentsResult = (0, child_process_1.spawnSync)('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });
48
+ const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);
49
+ for (const parent of parents) {
50
+ const ancestorCheck = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);
51
+ const reverseCheck = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);
52
+ if (ancestorCheck.status === 0 && reverseCheck.status === 0) {
53
+ const errorJson = JSON.stringify({
54
+ error: 'Merge from main detected',
55
+ mergeCommit: commit,
56
+ parentFromMain: parent,
57
+ timestamp: new Date().toISOString(),
58
+ }, null, 2);
59
+ fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\n');
60
+ printMergeFromMainError(commit, parent, featureName, currentBranch);
61
+ process.exit(1);
62
+ }
63
+ }
64
+ }
65
+ process.stderr.write('✅ No improper merges from main detected\n');
66
+ }
67
+ async function findForkPoint(workflow) {
68
+ if (workflow !== 'review' && workflow !== 'merge') {
69
+ process.stderr.write('ERROR: Workflow argument required\n');
70
+ process.stderr.write('Usage: git-findForkPoint <workflow>\n');
71
+ process.stderr.write(" workflow: 'review' or 'merge'\n");
72
+ process.exit(1);
73
+ }
74
+ const featureName = (0, git_readAiBranchName_1.getFeatureName)();
75
+ const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
76
+ const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
77
+ const outputDir = path.join(repoRoot, 'webpiecesTmp', `${workflow}-${featureName}`);
78
+ const prefix = workflow === 'review' ? 'review-' : 'updatemain-';
79
+ fs.mkdirSync(outputDir, { recursive: true });
80
+ (0, child_process_1.spawnSync)('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });
81
+ const featureHead = (0, child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf8' }).trim();
82
+ const originMain = (0, child_process_1.execSync)('git rev-parse origin/main', { encoding: 'utf8' }).trim();
83
+ process.stderr.write('Finding fork point using git merge-base...\n');
84
+ const forkPointResult = (0, child_process_1.spawnSync)('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });
85
+ const forkPoint = (forkPointResult.stdout ?? '').trim();
86
+ if (!forkPoint || forkPointResult.status !== 0) {
87
+ process.stderr.write('ERROR: Could not find common ancestor with origin/main\n');
88
+ process.exit(1);
89
+ }
90
+ process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\n`);
91
+ process.stderr.write('Checking for improper merges from main...\n');
92
+ const mergeCommitsResult = (0, child_process_1.spawnSync)('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });
93
+ const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();
94
+ const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\n') : [];
95
+ if (mergeCommits.length > 0) {
96
+ checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);
97
+ }
98
+ else {
99
+ process.stderr.write('✅ No merge commits found (clean history)\n');
100
+ }
101
+ const hashesJson = JSON.stringify({
102
+ hashForkPoint: forkPoint,
103
+ hashFeatureHead: featureHead,
104
+ hashMainHead: originMain,
105
+ timestamp: new Date().toISOString(),
106
+ }, null, 2);
107
+ fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\n');
108
+ process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\n`);
109
+ }
110
+ async function main() {
111
+ await findForkPoint(process.argv[2] ?? '');
112
+ }
113
+ if (require.main === module) {
114
+ main().catch((err) => {
115
+ const message = err instanceof Error ? err.message : String(err);
116
+ process.stderr.write(message + '\n');
117
+ process.exit(1);
118
+ });
119
+ }
120
+ //# sourceMappingURL=git-findForkPoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-findForkPoint.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/scripts/workflow/git-findForkPoint.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getFeatureName } from './git-readAiBranchName';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction printMergeFromMainError(commit: string, parent: string, featureName: string, currentBranch: string): void {\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('❌ This branch merged main without git-updateFromMain.sh\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write(`Merge commit detected: ${commit}\\n`);\n process.stderr.write(`Parent from main: ${parent}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\\n');\n process.stderr.write('\\n');\n process.stderr.write('1. Switch to main branch:\\n');\n process.stderr.write(' git checkout main\\n');\n process.stderr.write('\\n');\n process.stderr.write('2. Pull latest changes:\\n');\n process.stderr.write(' git pull\\n');\n process.stderr.write('\\n');\n process.stderr.write('3. Create new branch with a new name:\\n');\n process.stderr.write(` git checkout -b ${featureName}-v2\\n`);\n process.stderr.write('\\n');\n process.stderr.write('4. Squash merge your old branch:\\n');\n process.stderr.write(` git merge --squash ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('5. Commit the squashed changes:\\n');\n process.stderr.write(` git add -A && git commit -m \"Squashed from ${currentBranch}\"\\n`);\n process.stderr.write('\\n');\n process.stderr.write('6. If you have an existing PR:\\n');\n process.stderr.write(` - Create a NEW PR for ${featureName}-v2\\n`);\n process.stderr.write(` - Close the old PR for ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n}\n\nfunction checkMergeCommits(mergeCommits: string[], outputDir: string, prefix: string, featureName: string, currentBranch: string): void {\n process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\\n`);\n\n for (const commit of mergeCommits) {\n const parentsResult = spawnSync('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });\n const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);\n\n for (const parent of parents) {\n const ancestorCheck = spawnSync('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);\n const reverseCheck = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);\n\n if (ancestorCheck.status === 0 && reverseCheck.status === 0) {\n const errorJson = JSON.stringify({\n error: 'Merge from main detected',\n mergeCommit: commit,\n parentFromMain: parent,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\\n');\n printMergeFromMainError(commit, parent, featureName, currentBranch);\n process.exit(1);\n }\n }\n }\n process.stderr.write('✅ No improper merges from main detected\\n');\n}\n\nexport async function findForkPoint(workflow: string): Promise<void> {\n if (workflow !== 'review' && workflow !== 'merge') {\n process.stderr.write('ERROR: Workflow argument required\\n');\n process.stderr.write('Usage: git-findForkPoint <workflow>\\n');\n process.stderr.write(\" workflow: 'review' or 'merge'\\n\");\n process.exit(1);\n }\n\n const featureName = getFeatureName();\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n const outputDir = path.join(repoRoot, 'webpiecesTmp', `${workflow}-${featureName}`);\n const prefix = workflow === 'review' ? 'review-' : 'updatemain-';\n fs.mkdirSync(outputDir, { recursive: true });\n\n spawnSync('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });\n\n const featureHead = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();\n const originMain = execSync('git rev-parse origin/main', { encoding: 'utf8' }).trim();\n\n process.stderr.write('Finding fork point using git merge-base...\\n');\n\n const forkPointResult = spawnSync('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });\n const forkPoint = (forkPointResult.stdout ?? '').trim();\n\n if (!forkPoint || forkPointResult.status !== 0) {\n process.stderr.write('ERROR: Could not find common ancestor with origin/main\\n');\n process.exit(1);\n }\n\n process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\\n`);\n process.stderr.write('Checking for improper merges from main...\\n');\n\n const mergeCommitsResult = spawnSync('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });\n const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();\n const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\\n') : [];\n\n if (mergeCommits.length > 0) {\n checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);\n } else {\n process.stderr.write('✅ No merge commits found (clean history)\\n');\n }\n\n const hashesJson = JSON.stringify({\n hashForkPoint: forkPoint,\n hashFeatureHead: featureHead,\n hashMainHead: originMain,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\\n');\n process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\\n`);\n}\n\nexport async function main(): Promise<void> {\n await findForkPoint(process.argv[2] ?? '');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function getFeatureName(): string;
2
+ export declare function main(): Promise<void>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFeatureName = getFeatureName;
4
+ exports.main = main;
5
+ const child_process_1 = require("child_process");
6
+ function getFeatureName() {
7
+ const branch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
8
+ return branch.replace(/\//g, '-').replace(/Squash$/, '');
9
+ }
10
+ async function main() {
11
+ process.stdout.write(getFeatureName() + '\n');
12
+ }
13
+ if (require.main === module) {
14
+ main().catch((err) => {
15
+ const message = err instanceof Error ? err.message : String(err);
16
+ process.stderr.write(message + '\n');
17
+ process.exit(1);
18
+ });
19
+ }
20
+ //# sourceMappingURL=git-readAiBranchName.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-readAiBranchName.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/scripts/workflow/git-readAiBranchName.ts"],"names":[],"mappings":";;AAEA,wCAGC;AAED,oBAEC;AATD,iDAAyC;AAEzC,SAAgB,cAAc;IAC1B,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAEM,KAAK,UAAU,IAAI;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { execSync } from 'child_process';\n\nexport function getFeatureName(): string {\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n return branch.replace(/\\//g, '-').replace(/Squash$/, '');\n}\n\nexport async function main(): Promise<void> {\n process.stdout.write(getFeatureName() + '\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function main(): Promise<void>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ const child_process_1 = require("child_process");
5
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
6
+ async function main() {
7
+ const branch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
8
+ if (branch === 'main') {
9
+ process.stdout.write('✅ On main branch - no validation needed\n');
10
+ return;
11
+ }
12
+ process.stdout.write('Validating branch is up to date with origin/main...\n');
13
+ process.stdout.write(`Current branch: ${branch}\n`);
14
+ process.stdout.write('\n');
15
+ process.stdout.write('Fetching latest from origin/main...\n');
16
+ (0, child_process_1.spawnSync)('git', ['fetch', 'origin', 'main', '--quiet'], { stdio: 'inherit' });
17
+ const isUpToDate = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', 'origin/main', 'HEAD']).status === 0;
18
+ if (isUpToDate) {
19
+ process.stdout.write('✅ Branch is up to date with origin/main\n');
20
+ return;
21
+ }
22
+ const behindResult = (0, child_process_1.spawnSync)('git', ['rev-list', '--count', 'HEAD..origin/main'], { encoding: 'utf8' });
23
+ const commitsBehind = (behindResult.stdout ?? '').trim();
24
+ const recentResult = (0, child_process_1.spawnSync)('git', ['log', '--oneline', 'HEAD..origin/main'], { encoding: 'utf8' });
25
+ const recentLines = (recentResult.stdout ?? '').split('\n').filter((l) => l).slice(0, 5).join('\n');
26
+ process.stdout.write('\n');
27
+ process.stdout.write(SEP);
28
+ process.stdout.write('❌ ERROR: Branch is NOT up to date with origin/main\n');
29
+ process.stdout.write(SEP);
30
+ process.stdout.write('\n');
31
+ process.stdout.write(`Your branch is ${commitsBehind} commit(s) behind origin/main\n`);
32
+ process.stdout.write('\n');
33
+ process.stdout.write('Recent commits in origin/main not in your branch:\n');
34
+ process.stdout.write(recentLines + '\n');
35
+ process.stdout.write('\n');
36
+ process.stdout.write(SEP);
37
+ process.stdout.write('⚠️ CRITICAL: You must update your branch first!\n');
38
+ process.stdout.write(SEP);
39
+ process.stdout.write('\n');
40
+ process.stdout.write('1. Update your branch with latest main:\n');
41
+ process.stdout.write(' ./scripts/git-updateFromMain.sh\n');
42
+ process.stdout.write('\n');
43
+ process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\n');
44
+ process.stdout.write(' - Check for merge conflicts\n');
45
+ process.stdout.write(' - Review how your changes interact with new main code\n');
46
+ process.stdout.write(' - Test that everything still works\n');
47
+ process.stdout.write(' - This is where things often go wrong!\n');
48
+ process.stdout.write('\n');
49
+ process.stdout.write('3. After reviewing, run your command again\n');
50
+ process.stdout.write('\n');
51
+ process.stdout.write(SEP);
52
+ process.stdout.write('Why this matters:\n');
53
+ process.stdout.write(SEP);
54
+ process.stdout.write('\n');
55
+ process.stdout.write('- Your test plan should cover how your changes work with\n');
56
+ process.stdout.write(' the LATEST code from main, not outdated code\n');
57
+ process.stdout.write('- Merging main might introduce conflicts or integration\n');
58
+ process.stdout.write(' issues that need testing\n');
59
+ process.stdout.write('- Your changes might interact unexpectedly with new code\n');
60
+ process.stdout.write(' from main\n');
61
+ process.stdout.write('\n');
62
+ process.stdout.write(SEP);
63
+ process.exit(1);
64
+ }
65
+ if (require.main === module) {
66
+ main().catch((err) => {
67
+ const message = err instanceof Error ? err.message : String(err);
68
+ process.stderr.write(message + '\n');
69
+ process.exit(1);
70
+ });
71
+ }
72
+ //# sourceMappingURL=git-validateUpToDate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-validateUpToDate.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/scripts/workflow/git-validateUpToDate.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n\n if (branch === 'main') {\n process.stdout.write('✅ On main branch - no validation needed\\n');\n return;\n }\n\n process.stdout.write('Validating branch is up to date with origin/main...\\n');\n process.stdout.write(`Current branch: ${branch}\\n`);\n process.stdout.write('\\n');\n\n process.stdout.write('Fetching latest from origin/main...\\n');\n spawnSync('git', ['fetch', 'origin', 'main', '--quiet'], { stdio: 'inherit' });\n\n const isUpToDate = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', 'HEAD']).status === 0;\n\n if (isUpToDate) {\n process.stdout.write('✅ Branch is up to date with origin/main\\n');\n return;\n }\n\n const behindResult = spawnSync('git', ['rev-list', '--count', 'HEAD..origin/main'], { encoding: 'utf8' });\n const commitsBehind = (behindResult.stdout ?? '').trim();\n\n const recentResult = spawnSync('git', ['log', '--oneline', 'HEAD..origin/main'], { encoding: 'utf8' });\n const recentLines = (recentResult.stdout ?? '').split('\\n').filter((l: string) => l).slice(0, 5).join('\\n');\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('❌ ERROR: Branch is NOT up to date with origin/main\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write(`Your branch is ${commitsBehind} commit(s) behind origin/main\\n`);\n process.stdout.write('\\n');\n process.stdout.write('Recent commits in origin/main not in your branch:\\n');\n process.stdout.write(recentLines + '\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('⚠️ CRITICAL: You must update your branch first!\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('1. Update your branch with latest main:\\n');\n process.stdout.write(' ./scripts/git-updateFromMain.sh\\n');\n process.stdout.write('\\n');\n process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\\n');\n process.stdout.write(' - Check for merge conflicts\\n');\n process.stdout.write(' - Review how your changes interact with new main code\\n');\n process.stdout.write(' - Test that everything still works\\n');\n process.stdout.write(' - This is where things often go wrong!\\n');\n process.stdout.write('\\n');\n process.stdout.write('3. After reviewing, run your command again\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('Why this matters:\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write('- Your test plan should cover how your changes work with\\n');\n process.stdout.write(' the LATEST code from main, not outdated code\\n');\n process.stdout.write('- Merging main might introduce conflicts or integration\\n');\n process.stdout.write(' issues that need testing\\n');\n process.stdout.write('- Your changes might interact unexpectedly with new code\\n');\n process.stdout.write(' from main\\n');\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n\n process.exit(1);\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}