@link-assistant/hive-mind 1.2.8 â 1.2.10
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/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/solve.branch.lib.mjs +9 -9
- package/src/solve.config.lib.mjs +5 -0
- package/src/solve.mjs +24 -0
- package/src/solve.repository.lib.mjs +35 -0
- package/src/solve.watch.lib.mjs +33 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.2.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7ba1476: Auto-cleanup .playwright-mcp/ folder to prevent false auto-restart triggers
|
|
8
|
+
- Add auto-cleanup of .playwright-mcp/ folder before checking uncommitted changes
|
|
9
|
+
- Add --playwright-mcp-auto-cleanup option (enabled by default)
|
|
10
|
+
- Use --no-playwright-mcp-auto-cleanup to disable cleanup for debugging
|
|
11
|
+
- Add comprehensive case study documentation for issue #1124
|
|
12
|
+
|
|
13
|
+
## 1.2.9
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- b5e047a: Fix branch checkout error showing null/null instead of actual repository URL
|
|
18
|
+
- Pass owner/repo/prNumber to branch error handlers for accurate error messages
|
|
19
|
+
- Add upstream remote fallback when PR branch not found in origin (handles bot PRs)
|
|
20
|
+
- Add case study documentation for issue #1120
|
|
21
|
+
|
|
3
22
|
## 1.2.8
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/package.json
CHANGED
package/src/solve.branch.lib.mjs
CHANGED
|
@@ -100,7 +100,7 @@ export function detectBranchFormat(branchName) {
|
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export async function createOrCheckoutBranch({ isContinueMode, prBranch, issueNumber, tempDir, defaultBranch, argv, log, formatAligned, $, crypto }) {
|
|
103
|
+
export async function createOrCheckoutBranch({ isContinueMode, prBranch, issueNumber, tempDir, defaultBranch, argv, log, formatAligned, $, crypto, owner, repo, prNumber }) {
|
|
104
104
|
// Create a branch for the issue or checkout existing PR branch
|
|
105
105
|
let branchName;
|
|
106
106
|
let checkoutResult;
|
|
@@ -136,11 +136,11 @@ export async function createOrCheckoutBranch({ isContinueMode, prBranch, issueNu
|
|
|
136
136
|
const { handleBranchCheckoutError } = branchErrors;
|
|
137
137
|
await handleBranchCheckoutError({
|
|
138
138
|
branchName,
|
|
139
|
-
prNumber
|
|
139
|
+
prNumber,
|
|
140
140
|
errorOutput,
|
|
141
141
|
issueUrl: argv['issue-url'] || argv._[0],
|
|
142
|
-
owner
|
|
143
|
-
repo
|
|
142
|
+
owner,
|
|
143
|
+
repo,
|
|
144
144
|
tempDir,
|
|
145
145
|
argv,
|
|
146
146
|
formatAligned,
|
|
@@ -154,8 +154,8 @@ export async function createOrCheckoutBranch({ isContinueMode, prBranch, issueNu
|
|
|
154
154
|
branchName,
|
|
155
155
|
errorOutput,
|
|
156
156
|
tempDir,
|
|
157
|
-
owner
|
|
158
|
-
repo
|
|
157
|
+
owner,
|
|
158
|
+
repo,
|
|
159
159
|
formatAligned,
|
|
160
160
|
log,
|
|
161
161
|
});
|
|
@@ -193,9 +193,9 @@ export async function createOrCheckoutBranch({ isContinueMode, prBranch, issueNu
|
|
|
193
193
|
isContinueMode,
|
|
194
194
|
branchName,
|
|
195
195
|
actualBranch,
|
|
196
|
-
prNumber
|
|
197
|
-
owner
|
|
198
|
-
repo
|
|
196
|
+
prNumber,
|
|
197
|
+
owner,
|
|
198
|
+
repo,
|
|
199
199
|
tempDir,
|
|
200
200
|
formatAligned,
|
|
201
201
|
log,
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -311,6 +311,11 @@ export const createYargsConfig = yargsInstance => {
|
|
|
311
311
|
description: 'Include prompt to check related/sibling pull requests when studying related work. Enabled by default, use --no-prompt-check-sibling-pull-requests to disable.',
|
|
312
312
|
default: true,
|
|
313
313
|
})
|
|
314
|
+
.option('playwright-mcp-auto-cleanup', {
|
|
315
|
+
type: 'boolean',
|
|
316
|
+
description: 'Automatically remove .playwright-mcp/ folder before checking for uncommitted changes. This prevents browser automation artifacts from triggering auto-restart. Use --no-playwright-mcp-auto-cleanup to keep the folder for debugging.',
|
|
317
|
+
default: true,
|
|
318
|
+
})
|
|
314
319
|
.parserConfiguration({
|
|
315
320
|
'boolean-negation': true,
|
|
316
321
|
})
|
package/src/solve.mjs
CHANGED
|
@@ -553,6 +553,9 @@ try {
|
|
|
553
553
|
formatAligned,
|
|
554
554
|
$,
|
|
555
555
|
crypto,
|
|
556
|
+
owner,
|
|
557
|
+
repo,
|
|
558
|
+
prNumber,
|
|
556
559
|
});
|
|
557
560
|
|
|
558
561
|
// Auto-merge default branch to pull request branch if enabled
|
|
@@ -1113,6 +1116,27 @@ try {
|
|
|
1113
1116
|
await safeExit(1, `${argv.tool.toUpperCase()} execution failed`);
|
|
1114
1117
|
}
|
|
1115
1118
|
|
|
1119
|
+
// Clean up .playwright-mcp/ folder before checking for uncommitted changes
|
|
1120
|
+
// This prevents browser automation artifacts from triggering auto-restart (Issue #1124)
|
|
1121
|
+
if (argv.playwrightMcpAutoCleanup !== false) {
|
|
1122
|
+
const playwrightMcpDir = path.join(tempDir, '.playwright-mcp');
|
|
1123
|
+
try {
|
|
1124
|
+
const playwrightMcpExists = await fs
|
|
1125
|
+
.stat(playwrightMcpDir)
|
|
1126
|
+
.then(() => true)
|
|
1127
|
+
.catch(() => false);
|
|
1128
|
+
if (playwrightMcpExists) {
|
|
1129
|
+
await fs.rm(playwrightMcpDir, { recursive: true, force: true });
|
|
1130
|
+
await log('đ§š Cleaned up .playwright-mcp/ folder (browser automation artifacts)', { verbose: true });
|
|
1131
|
+
}
|
|
1132
|
+
} catch (cleanupError) {
|
|
1133
|
+
// Non-critical error, just log and continue
|
|
1134
|
+
await log(`â ī¸ Could not clean up .playwright-mcp/ folder: ${cleanupError.message}`, { verbose: true });
|
|
1135
|
+
}
|
|
1136
|
+
} else {
|
|
1137
|
+
await log('âšī¸ Playwright MCP auto-cleanup disabled via --no-playwright-mcp-auto-cleanup', { verbose: true });
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1116
1140
|
// Check for uncommitted changes
|
|
1117
1141
|
// When limit is reached, force auto-commit of any uncommitted changes to preserve work
|
|
1118
1142
|
const shouldAutoCommit = argv['auto-commit-uncommitted-changes'] || limitReached;
|
|
@@ -1208,6 +1208,41 @@ export const checkoutPrBranch = async (tempDir, branchName, prForkRemote, prFork
|
|
|
1208
1208
|
} else {
|
|
1209
1209
|
// Branch doesn't exist locally, try to checkout from remote
|
|
1210
1210
|
checkoutResult = await $({ cwd: tempDir })`git checkout -b ${branchName} ${remoteName}/${branchName}`;
|
|
1211
|
+
|
|
1212
|
+
// If checkout from origin failed, try upstream remote as fallback
|
|
1213
|
+
// This handles the case where we're in fork mode but the PR branch exists in upstream
|
|
1214
|
+
// (e.g., a bot created PR in the upstream repo, not a fork PR)
|
|
1215
|
+
if (checkoutResult.code !== 0 && remoteName === 'origin') {
|
|
1216
|
+
await log(`${formatAligned('đ', 'Branch not in origin:', 'Checking upstream remote...')}`);
|
|
1217
|
+
|
|
1218
|
+
// Check if upstream remote exists
|
|
1219
|
+
const upstreamCheckResult = await $({ cwd: tempDir })`git remote get-url upstream 2>/dev/null`;
|
|
1220
|
+
if (upstreamCheckResult.code === 0) {
|
|
1221
|
+
// Fetch from upstream to ensure we have the latest branches
|
|
1222
|
+
await log(`${formatAligned('đĨ', 'Fetching from upstream:', 'Looking for PR branch...')}`);
|
|
1223
|
+
const fetchUpstreamResult = await $({ cwd: tempDir })`git fetch upstream`;
|
|
1224
|
+
|
|
1225
|
+
if (fetchUpstreamResult.code === 0) {
|
|
1226
|
+
// Check if branch exists in upstream
|
|
1227
|
+
const upstreamBranchCheckResult = await $({ cwd: tempDir })`git show-ref --verify --quiet refs/remotes/upstream/${branchName}`;
|
|
1228
|
+
|
|
1229
|
+
if (upstreamBranchCheckResult.code === 0) {
|
|
1230
|
+
await log(`${formatAligned('â
', 'Found branch in upstream:', `upstream/${branchName}`)}`);
|
|
1231
|
+
// Try to checkout from upstream instead
|
|
1232
|
+
checkoutResult = await $({ cwd: tempDir })`git checkout -b ${branchName} upstream/${branchName}`;
|
|
1233
|
+
|
|
1234
|
+
if (checkoutResult.code === 0) {
|
|
1235
|
+
await log(`${formatAligned('âšī¸', 'Note:', 'PR branch was in upstream repository, not your fork')}`);
|
|
1236
|
+
await log(`${formatAligned('', '', 'This can happen when a bot creates a PR directly in the main repository')}`);
|
|
1237
|
+
}
|
|
1238
|
+
} else {
|
|
1239
|
+
await log(`${formatAligned('â ī¸', 'Branch not found:', `Not in origin or upstream remotes`)}`, { level: 'warning' });
|
|
1240
|
+
}
|
|
1241
|
+
} else {
|
|
1242
|
+
await log(`${formatAligned('â ī¸', 'Warning:', 'Failed to fetch from upstream')}`, { level: 'warning' });
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1211
1246
|
}
|
|
1212
1247
|
|
|
1213
1248
|
return checkoutResult;
|
package/src/solve.watch.lib.mjs
CHANGED
|
@@ -15,6 +15,10 @@ const use = globalThis.use;
|
|
|
15
15
|
// Use command-stream for consistent $ behavior across runtimes
|
|
16
16
|
const { $ } = await use('command-stream');
|
|
17
17
|
|
|
18
|
+
// Import path and fs for cleanup operations
|
|
19
|
+
const path = (await use('path')).default;
|
|
20
|
+
const fs = (await use('fs')).promises;
|
|
21
|
+
|
|
18
22
|
// Import shared library functions
|
|
19
23
|
const lib = await import('./lib.mjs');
|
|
20
24
|
const { log, cleanErrorMessage, formatAligned } = lib;
|
|
@@ -50,10 +54,36 @@ const checkPRMerged = async (owner, repo, prNumber) => {
|
|
|
50
54
|
return false;
|
|
51
55
|
};
|
|
52
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Clean up .playwright-mcp/ folder to prevent browser automation artifacts
|
|
59
|
+
* from triggering auto-restart (Issue #1124)
|
|
60
|
+
*/
|
|
61
|
+
const cleanupPlaywrightMcpFolder = async (tempDir, argv) => {
|
|
62
|
+
if (argv.playwrightMcpAutoCleanup !== false) {
|
|
63
|
+
const playwrightMcpDir = path.join(tempDir, '.playwright-mcp');
|
|
64
|
+
try {
|
|
65
|
+
const playwrightMcpExists = await fs
|
|
66
|
+
.stat(playwrightMcpDir)
|
|
67
|
+
.then(() => true)
|
|
68
|
+
.catch(() => false);
|
|
69
|
+
if (playwrightMcpExists) {
|
|
70
|
+
await fs.rm(playwrightMcpDir, { recursive: true, force: true });
|
|
71
|
+
await log('đ§š Cleaned up .playwright-mcp/ folder (browser automation artifacts)', { verbose: true });
|
|
72
|
+
}
|
|
73
|
+
} catch (cleanupError) {
|
|
74
|
+
// Non-critical error, just log and continue
|
|
75
|
+
await log(`â ī¸ Could not clean up .playwright-mcp/ folder: ${cleanupError.message}`, { verbose: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
53
80
|
/**
|
|
54
81
|
* Check if there are uncommitted changes in the repository
|
|
55
82
|
*/
|
|
56
|
-
const checkForUncommittedChanges = async (tempDir,
|
|
83
|
+
const checkForUncommittedChanges = async (tempDir, $, argv = {}) => {
|
|
84
|
+
// First, clean up .playwright-mcp/ folder to prevent false positives (Issue #1124)
|
|
85
|
+
await cleanupPlaywrightMcpFolder(tempDir, argv);
|
|
86
|
+
|
|
57
87
|
try {
|
|
58
88
|
const gitStatusResult = await $({ cwd: tempDir })`git status --porcelain 2>&1`;
|
|
59
89
|
if (gitStatusResult.code === 0) {
|
|
@@ -130,7 +160,7 @@ export const watchForFeedback = async params => {
|
|
|
130
160
|
|
|
131
161
|
// In temporary watch mode, check if all changes have been committed
|
|
132
162
|
if (isTemporaryWatch && !firstIterationInTemporaryMode) {
|
|
133
|
-
const hasUncommitted = await checkForUncommittedChanges(tempDir,
|
|
163
|
+
const hasUncommitted = await checkForUncommittedChanges(tempDir, $, argv);
|
|
134
164
|
if (!hasUncommitted) {
|
|
135
165
|
await log('');
|
|
136
166
|
await log(formatAligned('â
', 'CHANGES COMMITTED!', 'Exiting auto-restart mode'));
|
|
@@ -185,7 +215,7 @@ export const watchForFeedback = async params => {
|
|
|
185
215
|
// In temporary watch mode, also check for uncommitted changes as a restart trigger
|
|
186
216
|
let hasUncommittedInTempMode = false;
|
|
187
217
|
if (isTemporaryWatch && !firstIterationInTemporaryMode) {
|
|
188
|
-
hasUncommittedInTempMode = await checkForUncommittedChanges(tempDir,
|
|
218
|
+
hasUncommittedInTempMode = await checkForUncommittedChanges(tempDir, $, argv);
|
|
189
219
|
}
|
|
190
220
|
|
|
191
221
|
const shouldRestart = hasFeedback || firstIterationInTemporaryMode || hasUncommittedInTempMode;
|