@link-assistant/hive-mind 2.0.26 → 2.0.28
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 +12 -0
- package/package.json +1 -1
- package/src/agent.prompts.lib.mjs +6 -0
- package/src/bidirectional-interactive.lib.mjs +15 -0
- package/src/claude.lib.mjs +60 -64
- package/src/claude.prompts.lib.mjs +6 -0
- package/src/codex.lib.mjs +44 -1
- package/src/codex.prompts.lib.mjs +6 -0
- package/src/gemini.prompts.lib.mjs +6 -0
- package/src/locales/en.lino +5 -5
- package/src/locales/hi.lino +5 -5
- package/src/locales/ru.lino +5 -5
- package/src/locales/zh.lino +5 -5
- package/src/opencode.prompts.lib.mjs +6 -1
- package/src/queue-config.lib.mjs +1 -1
- package/src/qwen.prompts.lib.mjs +6 -1
- package/src/session-monitor.lib.mjs +1 -1
- package/src/solve-option-contract.prompts.lib.mjs +19 -0
- package/src/solve.auto-merge.lib.mjs +13 -0
- package/src/solve.auto-pr.lib.mjs +1 -1
- package/src/solve.finalize.lib.mjs +21 -0
- package/src/solve.mjs +11 -19
- package/src/solve.pr-base-command-intervention.lib.mjs +62 -0
- package/src/solve.pr-base-guard.lib.mjs +266 -0
- package/src/solve.restart-shared.lib.mjs +2 -0
- package/src/telegram-bot.mjs +1 -2
- package/src/telegram-solve-queue-command.lib.mjs +12 -17
- package/src/telegram-solve-queue.helpers.lib.mjs +5 -5
- package/src/telegram-solve-queue.lib.mjs +2 -2
package/src/locales/en.lino
CHANGED
|
@@ -355,7 +355,7 @@ en
|
|
|
355
355
|
queue
|
|
356
356
|
only
|
|
357
357
|
in
|
|
358
|
-
groups "❌ The /
|
|
358
|
+
groups "❌ The /queue command only works in group chats. Please add this bot to a group and make it an admin."
|
|
359
359
|
disabled "❌ The solve command is disabled on this bot instance."
|
|
360
360
|
rejected """
|
|
361
361
|
❌ Solve command rejected.
|
|
@@ -413,7 +413,7 @@ en
|
|
|
413
413
|
URL: {{url}}
|
|
414
414
|
Status: {{status}}
|
|
415
415
|
|
|
416
|
-
💡 Use /
|
|
416
|
+
💡 Use /queue to check the queue status.
|
|
417
417
|
"""
|
|
418
418
|
session
|
|
419
419
|
running """
|
|
@@ -422,7 +422,7 @@ en
|
|
|
422
422
|
URL: {{url}}
|
|
423
423
|
Session: `{{session}}`
|
|
424
424
|
|
|
425
|
-
💡 Wait for the current session to complete, or use /
|
|
425
|
+
💡 Wait for the current session to complete, or use /stop to cancel it.
|
|
426
426
|
"""
|
|
427
427
|
issues
|
|
428
428
|
list
|
|
@@ -515,7 +515,7 @@ en
|
|
|
515
515
|
detail "Tool aliases imply `--tool <tool>`: `/codex <github-url>` equals `/solve <github-url> --tool codex`"
|
|
516
516
|
reply "Or reply to a message with a GitHub link: `/solve`"
|
|
517
517
|
disabled "*/solve* (aliases: */do*, */continue*, */claude*, */codex*, */opencode*, */agent*, */gemini*, */qwen*) - ❌ Disabled"
|
|
518
|
-
queue "`/
|
|
518
|
+
queue "`/queue` - Show solve queue status"
|
|
519
519
|
locked
|
|
520
520
|
options "🔒 Locked options: `{{options}}`"
|
|
521
521
|
task
|
|
@@ -553,7 +553,7 @@ en
|
|
|
553
553
|
isolation
|
|
554
554
|
mode "🔒 *Isolation Mode:* `{{isolationBackend}}` (experimental)"
|
|
555
555
|
group
|
|
556
|
-
note "⚠️ *Note:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /
|
|
556
|
+
note "⚠️ *Note:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /queue, /limits, /version, /accept\\_invites, /merge, /stop and /start commands only work in group chats. /terminal\\_watch, /watch, /subscribe and /unsubscribe work in private and group chats."
|
|
557
557
|
common
|
|
558
558
|
options "🔧 *Common Options:*"
|
|
559
559
|
model
|
package/src/locales/hi.lino
CHANGED
|
@@ -355,7 +355,7 @@ hi
|
|
|
355
355
|
queue
|
|
356
356
|
only
|
|
357
357
|
in
|
|
358
|
-
groups "❌ /
|
|
358
|
+
groups "❌ /queue कमांड केवल समूह चैट में काम करती है। कृपया बॉट को समूह में जोड़ें और व्यवस्थापक बनाएँ।"
|
|
359
359
|
disabled "❌ इस बॉट इंस्टेंस पर solve कमांड अक्षम है।"
|
|
360
360
|
rejected """
|
|
361
361
|
❌ Solve कमांड अस्वीकृत।
|
|
@@ -413,7 +413,7 @@ hi
|
|
|
413
413
|
URL: {{url}}
|
|
414
414
|
स्थिति: {{status}}
|
|
415
415
|
|
|
416
|
-
💡 कतार स्थिति देखने के लिए /
|
|
416
|
+
💡 कतार स्थिति देखने के लिए /queue का उपयोग करें।
|
|
417
417
|
"""
|
|
418
418
|
session
|
|
419
419
|
running """
|
|
@@ -422,7 +422,7 @@ hi
|
|
|
422
422
|
URL: {{url}}
|
|
423
423
|
सत्र: `{{session}}`
|
|
424
424
|
|
|
425
|
-
💡 वर्तमान सत्र के पूरा होने की प्रतीक्षा करें, या रद्द करने के लिए /
|
|
425
|
+
💡 वर्तमान सत्र के पूरा होने की प्रतीक्षा करें, या रद्द करने के लिए /stop का उपयोग करें।
|
|
426
426
|
"""
|
|
427
427
|
issues
|
|
428
428
|
list
|
|
@@ -515,7 +515,7 @@ hi
|
|
|
515
515
|
detail "Tool aliases `--tool <tool>` लगाते हैं: `/codex <github-url>` का अर्थ `/solve <github-url> --tool codex` है"
|
|
516
516
|
reply "या GitHub लिंक वाले संदेश का उत्तर दें: `/solve`"
|
|
517
517
|
disabled "*/solve* (aliases: */do*, */continue*, */claude*, */codex*, */opencode*, */agent*, */gemini*, */qwen*) - ❌ अक्षम"
|
|
518
|
-
queue "`/
|
|
518
|
+
queue "`/queue` - solve queue status दिखाएँ"
|
|
519
519
|
locked
|
|
520
520
|
options "🔒 लॉक किए गए विकल्प: `{{options}}`"
|
|
521
521
|
task
|
|
@@ -553,7 +553,7 @@ hi
|
|
|
553
553
|
isolation
|
|
554
554
|
mode "🔒 *Isolation Mode:* `{{isolationBackend}}` (experimental)"
|
|
555
555
|
group
|
|
556
|
-
note "⚠️ *नोट:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /
|
|
556
|
+
note "⚠️ *नोट:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /queue, /limits, /version, /accept\\_invites, /merge, /stop और /start commands केवल group chats में काम करती हैं। /terminal\\_watch, /watch, /subscribe और /unsubscribe private और group chats में काम करती हैं।"
|
|
557
557
|
common
|
|
558
558
|
options "🔧 *Common Options:*"
|
|
559
559
|
model
|
package/src/locales/ru.lino
CHANGED
|
@@ -355,7 +355,7 @@ ru
|
|
|
355
355
|
queue
|
|
356
356
|
only
|
|
357
357
|
in
|
|
358
|
-
groups "❌ Команда /
|
|
358
|
+
groups "❌ Команда /queue работает только в групповых чатах. Добавьте бота в группу и сделайте его администратором."
|
|
359
359
|
disabled "❌ Команда solve отключена в этом экземпляре бота."
|
|
360
360
|
rejected """
|
|
361
361
|
❌ Команда solve отклонена.
|
|
@@ -413,7 +413,7 @@ ru
|
|
|
413
413
|
URL: {{url}}
|
|
414
414
|
Статус: {{status}}
|
|
415
415
|
|
|
416
|
-
💡 Используйте /
|
|
416
|
+
💡 Используйте /queue для проверки очереди.
|
|
417
417
|
"""
|
|
418
418
|
session
|
|
419
419
|
running """
|
|
@@ -422,7 +422,7 @@ ru
|
|
|
422
422
|
URL: {{url}}
|
|
423
423
|
Сеанс: `{{session}}`
|
|
424
424
|
|
|
425
|
-
💡 Дождитесь завершения текущего сеанса или используйте /
|
|
425
|
+
💡 Дождитесь завершения текущего сеанса или используйте /stop для отмены.
|
|
426
426
|
"""
|
|
427
427
|
issues
|
|
428
428
|
list
|
|
@@ -515,7 +515,7 @@ ru
|
|
|
515
515
|
detail "Алиасы инструментов добавляют `--tool <tool>`: `/codex <github-url>` равно `/solve <github-url> --tool codex`"
|
|
516
516
|
reply "Или ответьте на сообщение со ссылкой GitHub: `/solve`"
|
|
517
517
|
disabled "*/solve* (алиасы: */do*, */continue*, */claude*, */codex*, */opencode*, */agent*, */gemini*, */qwen*) - ❌ Отключено"
|
|
518
|
-
queue "`/
|
|
518
|
+
queue "`/queue` - Показать состояние очереди solve"
|
|
519
519
|
locked
|
|
520
520
|
options "🔒 Заблокированные опции: `{{options}}`"
|
|
521
521
|
task
|
|
@@ -553,7 +553,7 @@ ru
|
|
|
553
553
|
isolation
|
|
554
554
|
mode "🔒 *Режим изоляции:* `{{isolationBackend}}` (экспериментально)"
|
|
555
555
|
group
|
|
556
|
-
note "⚠️ *Замечание:* команды /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /
|
|
556
|
+
note "⚠️ *Замечание:* команды /solve, /do, /continue, /claude, /codex, /opencode, /agent, /gemini, /qwen, /task, /split, /hive, /queue, /limits, /version, /accept\\_invites, /merge, /stop и /start работают только в групповых чатах. /terminal\\_watch, /watch, /subscribe и /unsubscribe работают в личных и групповых чатах."
|
|
557
557
|
common
|
|
558
558
|
options "🔧 *Общие опции:*"
|
|
559
559
|
model
|
package/src/locales/zh.lino
CHANGED
|
@@ -355,7 +355,7 @@ zh
|
|
|
355
355
|
queue
|
|
356
356
|
only
|
|
357
357
|
in
|
|
358
|
-
groups "❌ /
|
|
358
|
+
groups "❌ /queue 命令仅在群聊中有效。请将本机器人加入群组并设为管理员。"
|
|
359
359
|
disabled "❌ 此机器人实例已禁用 solve 命令。"
|
|
360
360
|
rejected """
|
|
361
361
|
❌ Solve 命令被拒绝。
|
|
@@ -413,7 +413,7 @@ zh
|
|
|
413
413
|
URL:{{url}}
|
|
414
414
|
状态:{{status}}
|
|
415
415
|
|
|
416
|
-
💡 使用 /
|
|
416
|
+
💡 使用 /queue 查看队列状态。
|
|
417
417
|
"""
|
|
418
418
|
session
|
|
419
419
|
running """
|
|
@@ -422,7 +422,7 @@ zh
|
|
|
422
422
|
URL:{{url}}
|
|
423
423
|
会话:`{{session}}`
|
|
424
424
|
|
|
425
|
-
💡 等待当前会话完成,或使用 /
|
|
425
|
+
💡 等待当前会话完成,或使用 /stop 取消。
|
|
426
426
|
"""
|
|
427
427
|
issues
|
|
428
428
|
list
|
|
@@ -515,7 +515,7 @@ zh
|
|
|
515
515
|
detail "工具别名会添加 `--tool <tool>`:`/codex <github-url>` 等同于 `/solve <github-url> --tool codex`"
|
|
516
516
|
reply "也可以回复包含 GitHub 链接的消息:`/solve`"
|
|
517
517
|
disabled "*/solve*(别名:*/do*、*/continue*、*/claude*、*/codex*、*/opencode*、*/agent*、*/gemini*、*/qwen*)- ❌ 已禁用"
|
|
518
|
-
queue "`/
|
|
518
|
+
queue "`/queue` - 显示 solve 队列状态"
|
|
519
519
|
locked
|
|
520
520
|
options "🔒 锁定选项:`{{options}}`"
|
|
521
521
|
task
|
|
@@ -553,7 +553,7 @@ zh
|
|
|
553
553
|
isolation
|
|
554
554
|
mode "🔒 *隔离模式:* `{{isolationBackend}}`(实验性)"
|
|
555
555
|
group
|
|
556
|
-
note "⚠️ *注意:* /solve、/do、/continue、/claude、/codex、/opencode、/agent、/gemini、/qwen、/task、/split、/hive、/
|
|
556
|
+
note "⚠️ *注意:* /solve、/do、/continue、/claude、/codex、/opencode、/agent、/gemini、/qwen、/task、/split、/hive、/queue、/limits、/version、/accept\\_invites、/merge、/stop 和 /start 仅在群聊中有效。/terminal\\_watch、/watch、/subscribe 和 /unsubscribe 在私聊和群聊中有效。"
|
|
557
557
|
common
|
|
558
558
|
options "🔧 *常用选项:*"
|
|
559
559
|
model
|
|
@@ -7,6 +7,7 @@ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mj
|
|
|
7
7
|
import { getExperimentsExamplesSubPrompt } from './experiments-examples.prompts.lib.mjs';
|
|
8
8
|
import { getThinkingPromptInstruction } from './thinking-prompt.lib.mjs';
|
|
9
9
|
import { buildWorkLanguageDirective } from './work-language.prompts.lib.mjs';
|
|
10
|
+
import { buildRequestedBaseBranchDirective } from './solve-option-contract.prompts.lib.mjs';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Build the user prompt for OpenCode
|
|
@@ -50,6 +51,11 @@ export const buildUserPrompt = params => {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
const requestedBaseBranchDirective = buildRequestedBaseBranchDirective(argv);
|
|
55
|
+
if (requestedBaseBranchDirective) {
|
|
56
|
+
promptLines.push(requestedBaseBranchDirective);
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
// Add blank line
|
|
54
60
|
promptLines.push('');
|
|
55
61
|
|
|
@@ -119,7 +125,6 @@ CI investigation with workspace tmp directory.
|
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
return `You are an AI issue solver using OpenCode.
|
|
122
|
-
|
|
123
128
|
General guidelines.
|
|
124
129
|
- When you execute commands and the output becomes large, save the logs to files for easier review.
|
|
125
130
|
- When running commands, avoid setting a timeout yourself. Let them run as long as needed.
|
package/src/queue-config.lib.mjs
CHANGED
|
@@ -282,7 +282,7 @@ export const QUEUE_CONFIG = {
|
|
|
282
282
|
|
|
283
283
|
// Display
|
|
284
284
|
// Maximum number of items shown per section (pending/processing/completed/failed)
|
|
285
|
-
// in the /
|
|
285
|
+
// in the /queue detailed status before collapsing into a
|
|
286
286
|
// "... and N more" line. Keeps the Telegram message under the 4096-char cap.
|
|
287
287
|
// See: https://github.com/link-assistant/hive-mind/issues/1837
|
|
288
288
|
MAX_DISPLAY_ITEMS_PER_QUEUE: parseIntWithDefault('HIVE_MIND_MAX_DISPLAY_ITEMS_PER_QUEUE', 5),
|
package/src/qwen.prompts.lib.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mj
|
|
|
7
7
|
import { getExperimentsExamplesSubPrompt } from './experiments-examples.prompts.lib.mjs';
|
|
8
8
|
import { getThinkingPromptInstruction } from './thinking-prompt.lib.mjs';
|
|
9
9
|
import { buildWorkLanguageDirective } from './work-language.prompts.lib.mjs';
|
|
10
|
+
import { buildRequestedBaseBranchDirective } from './solve-option-contract.prompts.lib.mjs';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Build the user prompt for Qwen Code
|
|
@@ -44,6 +45,11 @@ export const buildUserPrompt = params => {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
const requestedBaseBranchDirective = buildRequestedBaseBranchDirective(argv);
|
|
49
|
+
if (requestedBaseBranchDirective) {
|
|
50
|
+
promptLines.push(requestedBaseBranchDirective);
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
promptLines.push('');
|
|
48
54
|
|
|
49
55
|
if (isContinueMode && feedbackLines && feedbackLines.length > 0) {
|
|
@@ -105,7 +111,6 @@ CI investigation with workspace tmp directory.
|
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
return `You are an AI issue solver using Qwen Code.
|
|
108
|
-
|
|
109
114
|
General guidelines.
|
|
110
115
|
- When you execute commands and the output becomes large, save the logs to files for easier review.
|
|
111
116
|
- When running commands, avoid setting a timeout yourself. Let them run as long as needed.
|
|
@@ -1274,7 +1274,7 @@ export async function getRunningTrackedIsolationSessions(verbose = false, option
|
|
|
1274
1274
|
|
|
1275
1275
|
/**
|
|
1276
1276
|
* Return the currently-executing tracked sessions with the details needed to
|
|
1277
|
-
* render them as a clickable list in `/
|
|
1277
|
+
* render them as a clickable list in `/queue`: the issue/PR
|
|
1278
1278
|
* `url`, the `tool`, the start time, and (for isolation sessions) the backend
|
|
1279
1279
|
* status. Both isolation and non-isolation screen sessions are included so the
|
|
1280
1280
|
* list matches what is actually executing — the queue's own in-memory
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt snippets for user-requested solve options.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function normalizeBranchName(value) {
|
|
6
|
+
return String(value || '').trim();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function buildRequestedBaseBranchDirective(argv = {}) {
|
|
10
|
+
const baseBranch = normalizeBranchName(argv?.baseBranch);
|
|
11
|
+
if (!baseBranch) {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `Requested by user --base-branch: ${baseBranch}
|
|
16
|
+
The user expects the pull request base branch to remain ${baseBranch}.`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const buildLockedSolveOptionsDirective = buildRequestedBaseBranchDirective;
|
|
@@ -81,6 +81,7 @@ const { maybeAttachWorkingSessionSummary, ensurePullRequestIssueLink } = results
|
|
|
81
81
|
// Issue #1574: Interruptible sleep so CTRL+C is never blocked by a lingering timer
|
|
82
82
|
const { interruptibleSleep } = await import('./interruptible-sleep.lib.mjs');
|
|
83
83
|
const { formatAutoIterationLimit, hasReachedAutoIterationLimit, normalizeAutoIterationLimit, shouldSyncBeforeRestart } = await import('./auto-iteration-limits.lib.mjs');
|
|
84
|
+
const { ensurePullRequestBaseBranch } = await import('./solve.pr-base-guard.lib.mjs');
|
|
84
85
|
|
|
85
86
|
// Issue #1895: explicitly close linked issues after merging a PR into a
|
|
86
87
|
// non-default branch, where GitHub does not auto-close them.
|
|
@@ -1352,6 +1353,18 @@ export const startAutoRestartUntilMergeable = async params => {
|
|
|
1352
1353
|
return null;
|
|
1353
1354
|
}
|
|
1354
1355
|
|
|
1356
|
+
await ensurePullRequestBaseBranch({
|
|
1357
|
+
owner,
|
|
1358
|
+
repo,
|
|
1359
|
+
prNumber,
|
|
1360
|
+
argv,
|
|
1361
|
+
log,
|
|
1362
|
+
formatAligned,
|
|
1363
|
+
$,
|
|
1364
|
+
onMismatch: isAutoMerge ? 'throw' : 'restore',
|
|
1365
|
+
operation: isAutoMerge ? 'auto-merge' : 'auto-restart-until-mergeable',
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1355
1368
|
// Issue #1226: Check if running in fork mode — auto-merge cannot work without write access
|
|
1356
1369
|
if (argv.fork && isAutoMerge) {
|
|
1357
1370
|
await log('');
|
|
@@ -890,7 +890,7 @@ _Details will be added as the solution draft is developed..._
|
|
|
890
890
|
|
|
891
891
|
if (argv.verbose) {
|
|
892
892
|
await log(` PR Title: [WIP] ${issueTitle}`, { verbose: true });
|
|
893
|
-
await log(` Base branch: ${
|
|
893
|
+
await log(` Base branch: ${targetBranch}`, { verbose: true });
|
|
894
894
|
await log(` Head branch: ${branchName}`, { verbose: true });
|
|
895
895
|
if (currentUser) {
|
|
896
896
|
await log(` Assignee: ${currentUser}`, { verbose: true });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export async function finalizeSolveProcess({ tempDir, argv, limitReached, path, getLogFile, log, closeSentry, logActiveHandles, cleanupTempDirectory, safeExit }) {
|
|
2
|
+
await cleanupTempDirectory(tempDir, argv, limitReached);
|
|
3
|
+
|
|
4
|
+
// Show final log file reference so users always know where to find the complete log
|
|
5
|
+
if (getLogFile()) {
|
|
6
|
+
const finalLogPath = path.resolve(getLogFile());
|
|
7
|
+
await log(`\n📁 Complete log file: ${finalLogPath}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Issue #1346: Flush Sentry events before exit.
|
|
11
|
+
// closeSentry() uses a hard Promise.race deadline so it cannot block indefinitely.
|
|
12
|
+
await closeSentry();
|
|
13
|
+
|
|
14
|
+
// Issue #1431: Log active handles before draining.
|
|
15
|
+
// Always logged to file and console so future hangs are immediately visible in logs.
|
|
16
|
+
// drainHandles() inside safeExit() will unref/close these before process.exit().
|
|
17
|
+
await logActiveHandles(msg => log(msg));
|
|
18
|
+
|
|
19
|
+
// Issue #1431: safeExit() unrefs handles so the event loop exits naturally, then calls process.exit(0)
|
|
20
|
+
await safeExit(0, 'Process completed');
|
|
21
|
+
}
|
package/src/solve.mjs
CHANGED
|
@@ -47,6 +47,7 @@ const { startAutoRestartUntilMergeable } = await import('./solve.auto-merge.lib.
|
|
|
47
47
|
const { runAutoEnsureRequirements } = await import('./solve.auto-ensure.lib.mjs');
|
|
48
48
|
const { runKeepWorkingUntilDone } = await import('./solve.keep-working.lib.mjs');
|
|
49
49
|
const { runEscalation } = await import('./solve.escalate.lib.mjs');
|
|
50
|
+
const { finalizeSolveProcess } = await import('./solve.finalize.lib.mjs');
|
|
50
51
|
const exitHandler = await import('./exit-handler.lib.mjs');
|
|
51
52
|
const { initializeExitHandler, installGlobalExitHandlers, safeExit, logActiveHandles } = exitHandler;
|
|
52
53
|
const { createInterruptWrapper } = await import('./solve.interrupt.lib.mjs');
|
|
@@ -54,6 +55,7 @@ const { createInterruptWrapper } = await import('./solve.interrupt.lib.mjs');
|
|
|
54
55
|
const { configureWorkingSession, beginWorkingSession, endWorkingSession } = await import('./working-session.lib.mjs');
|
|
55
56
|
const getResourceSnapshot = memoryCheck.getResourceSnapshot;
|
|
56
57
|
const { handleAutoPrCreation } = await import('./solve.auto-pr.lib.mjs');
|
|
58
|
+
const { ensurePullRequestBaseBranch } = await import('./solve.pr-base-guard.lib.mjs');
|
|
57
59
|
const { setupRepositoryAndClone, verifyDefaultBranchAndStatus } = await import('./solve.repo-setup.lib.mjs');
|
|
58
60
|
const { recordAfterCloneSize, recordAfterAgentSize } = await import('./solve.disk-diagnostics.lib.mjs');
|
|
59
61
|
const { createOrCheckoutBranch } = await import('./solve.branch.lib.mjs');
|
|
@@ -617,6 +619,10 @@ try {
|
|
|
617
619
|
await handleNoPrAvailableError({ isContinueMode, tempDir, issueNumber, issueUrl, owner, repo, log, formatAligned });
|
|
618
620
|
}
|
|
619
621
|
|
|
622
|
+
const enforceRequestedBaseBranch = () => ensurePullRequestBaseBranch({ owner, repo, prNumber, argv, log, formatAligned, $ });
|
|
623
|
+
|
|
624
|
+
await enforceRequestedBaseBranch();
|
|
625
|
+
|
|
620
626
|
if (isContinueMode) {
|
|
621
627
|
await log(`\n${formatAligned('🔄', 'Continue mode:', 'ACTIVE')}`);
|
|
622
628
|
await log(formatAligned('', 'Using existing PR:', `#${prNumber}`, 2));
|
|
@@ -1203,6 +1209,8 @@ try {
|
|
|
1203
1209
|
await safeExit(0, 'Auto-continue child process will handle post-processing');
|
|
1204
1210
|
}
|
|
1205
1211
|
|
|
1212
|
+
await enforceRequestedBaseBranch();
|
|
1213
|
+
|
|
1206
1214
|
// Issue #1263 / #1728: Working session summary attachment.
|
|
1207
1215
|
// Routed through the shared maybeAttachWorkingSessionSummary helper so that
|
|
1208
1216
|
// top-level solve, auto-restart-until-mergeable, and watch-mode iterations
|
|
@@ -1329,6 +1337,8 @@ try {
|
|
|
1329
1337
|
}
|
|
1330
1338
|
}
|
|
1331
1339
|
|
|
1340
|
+
await enforceRequestedBaseBranch();
|
|
1341
|
+
|
|
1332
1342
|
// Track whether logs were successfully attached (used by endWorkSession)
|
|
1333
1343
|
let logsAttached = false;
|
|
1334
1344
|
|
|
@@ -1475,23 +1485,5 @@ try {
|
|
|
1475
1485
|
$,
|
|
1476
1486
|
});
|
|
1477
1487
|
} finally {
|
|
1478
|
-
await
|
|
1479
|
-
|
|
1480
|
-
// Show final log file reference so users always know where to find the complete log
|
|
1481
|
-
if (getLogFile()) {
|
|
1482
|
-
const finalLogPath = path.resolve(getLogFile());
|
|
1483
|
-
await log(`\n📁 Complete log file: ${finalLogPath}`);
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
// Issue #1346: Flush Sentry events before exit.
|
|
1487
|
-
// closeSentry() uses a hard Promise.race deadline so it cannot block indefinitely.
|
|
1488
|
-
await closeSentry();
|
|
1489
|
-
|
|
1490
|
-
// Issue #1431: Log active handles before draining.
|
|
1491
|
-
// Always logged to file and console so future hangs are immediately visible in logs.
|
|
1492
|
-
// drainHandles() inside safeExit() will unref/close these before process.exit().
|
|
1493
|
-
await logActiveHandles(msg => log(msg));
|
|
1494
|
-
|
|
1495
|
-
// Issue #1431: safeExit() unrefs handles so the event loop exits naturally, then calls process.exit(0)
|
|
1496
|
-
await safeExit(0, 'Process completed');
|
|
1488
|
+
await finalizeSolveProcess({ tempDir, argv, limitReached, path, getLogFile, log, closeSentry, logActiveHandles, cleanupTempDirectory, safeExit });
|
|
1497
1489
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { buildPullRequestBaseBranchInterventionMessage, detectForbiddenPullRequestBaseChangeCommand, extractToolCommandTextsFromStreamEvent } from './solve.pr-base-guard.lib.mjs';
|
|
2
|
+
|
|
3
|
+
export function createPullRequestBaseBranchCommandIntervention({ expectedBaseBranch, prNumber, log = async () => {}, toolLabel = 'AI tool', sendInput = null, stopSession = null } = {}) {
|
|
4
|
+
const observedCommands = new Set();
|
|
5
|
+
let intervention = null;
|
|
6
|
+
let sent = false;
|
|
7
|
+
|
|
8
|
+
const handleCommand = async command => {
|
|
9
|
+
if (!expectedBaseBranch || intervention || sent || !command || observedCommands.has(command)) return;
|
|
10
|
+
observedCommands.add(command);
|
|
11
|
+
|
|
12
|
+
const violation = detectForbiddenPullRequestBaseChangeCommand(command, {
|
|
13
|
+
expectedBaseBranch,
|
|
14
|
+
prNumber,
|
|
15
|
+
});
|
|
16
|
+
if (!violation) return;
|
|
17
|
+
|
|
18
|
+
const message = buildPullRequestBaseBranchInterventionMessage(violation);
|
|
19
|
+
await log(`\n⚠️ Forbidden PR base retarget command observed from ${toolLabel}: ${command}`, { level: 'warning' });
|
|
20
|
+
|
|
21
|
+
if (sendInput) {
|
|
22
|
+
try {
|
|
23
|
+
sent = await sendInput(message);
|
|
24
|
+
} catch (sendError) {
|
|
25
|
+
await log(` Could not send requested base-branch correction to ${toolLabel} input: ${sendError.message}`, { level: 'warning' });
|
|
26
|
+
}
|
|
27
|
+
if (sent) {
|
|
28
|
+
await log(` Sent requested base-branch correction to ${toolLabel} input.`, { level: 'warning' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
intervention = { violation, message };
|
|
34
|
+
await log(` ${message}`, { level: 'warning' });
|
|
35
|
+
if (stopSession) {
|
|
36
|
+
try {
|
|
37
|
+
const stopped = await stopSession();
|
|
38
|
+
if (stopped) {
|
|
39
|
+
await log(` Stopped ${toolLabel} session to resume with requested base-branch correction.`, { level: 'warning' });
|
|
40
|
+
}
|
|
41
|
+
} catch (stopError) {
|
|
42
|
+
await log(` Could not stop ${toolLabel} process for immediate correction: ${stopError.message}`, { level: 'warning' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleCommands = async commands => {
|
|
48
|
+
for (const command of commands) {
|
|
49
|
+
await handleCommand(command);
|
|
50
|
+
if (intervention || sent) return;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
handleCommand,
|
|
56
|
+
handleCommands,
|
|
57
|
+
handleCommandExecutions: async commandExecutions => handleCommands((commandExecutions || []).map(commandExecution => commandExecution?.command).filter(Boolean)),
|
|
58
|
+
handleStreamEvent: async event => handleCommands(extractToolCommandTextsFromStreamEvent(event)),
|
|
59
|
+
getIntervention: () => intervention,
|
|
60
|
+
wasSent: () => sent,
|
|
61
|
+
};
|
|
62
|
+
}
|