@link-assistant/hive-mind 2.0.21 → 2.0.22
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 +6 -0
- package/package.json +1 -1
- package/src/config.lib.mjs +1 -1
- package/src/hive.mjs +1 -1
- package/src/memory-check.mjs +3 -3
- package/src/queue-config.lib.mjs +6 -8
- package/src/solve.config.lib.mjs +2 -2
- package/src/solve.mjs +1 -1
- package/src/solve.validation.lib.mjs +2 -2
- package/src/task.config.lib.mjs +1 -1
- package/src/task.mjs +1 -1
- package/src/telegram-bot.mjs +1 -1
- package/src/telegram-solve-queue.lib.mjs +2 -1
- package/src/telegram-start-stop-command.lib.mjs +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.0.22
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4d65c05: Make disk admission safer by default: the disk usage queue gate now waits at 80%, the absolute free-space default is 10240 MB, and isolation defaults to Docker.
|
|
8
|
+
|
|
3
9
|
## 2.0.21
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
package/src/config.lib.mjs
CHANGED
|
@@ -111,7 +111,7 @@ export const githubLimits = {
|
|
|
111
111
|
|
|
112
112
|
// Memory and disk configurations
|
|
113
113
|
export const systemLimits = {
|
|
114
|
-
minDiskSpaceMb: parseIntWithDefault('HIVE_MIND_MIN_DISK_SPACE_MB',
|
|
114
|
+
minDiskSpaceMb: parseIntWithDefault('HIVE_MIND_MIN_DISK_SPACE_MB', 10240),
|
|
115
115
|
defaultPageSizeKb: parseIntWithDefault('HIVE_MIND_DEFAULT_PAGE_SIZE_KB', 16),
|
|
116
116
|
};
|
|
117
117
|
|
package/src/hive.mjs
CHANGED
package/src/memory-check.mjs
CHANGED
|
@@ -26,7 +26,7 @@ const lib = await import('./lib.mjs');
|
|
|
26
26
|
const { log: libLog, setLogFile } = lib;
|
|
27
27
|
|
|
28
28
|
// Function to check available disk space
|
|
29
|
-
export const checkDiskSpace = async (minSpaceMB =
|
|
29
|
+
export const checkDiskSpace = async (minSpaceMB = 10240, options = {}) => {
|
|
30
30
|
const log = options.log || libLog;
|
|
31
31
|
|
|
32
32
|
try {
|
|
@@ -289,7 +289,7 @@ export const getResourceSnapshot = async () => {
|
|
|
289
289
|
|
|
290
290
|
// Combined system check function
|
|
291
291
|
export const checkSystem = async (requirements = {}, options = {}) => {
|
|
292
|
-
const { minMemoryMB = 256, minDiskSpaceMB =
|
|
292
|
+
const { minMemoryMB = 256, minDiskSpaceMB = 10240, exitOnFailure = false } = requirements;
|
|
293
293
|
|
|
294
294
|
// Note: log is passed through options to checkDiskSpace and checkRAM
|
|
295
295
|
const results = {
|
|
@@ -334,7 +334,7 @@ const createMemoryCheckYargsConfig = yargsInstance =>
|
|
|
334
334
|
alias: 'd',
|
|
335
335
|
type: 'number',
|
|
336
336
|
description: 'Minimum required disk space in MB',
|
|
337
|
-
default:
|
|
337
|
+
default: 10240,
|
|
338
338
|
})
|
|
339
339
|
.option('exit-on-failure', {
|
|
340
340
|
alias: 'e',
|
package/src/queue-config.lib.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import { ensureUseM } from './use-m-bootstrap.lib.mjs';
|
|
|
22
22
|
*
|
|
23
23
|
* @see https://github.com/link-assistant/hive-mind/issues/1242
|
|
24
24
|
* @see https://github.com/link-assistant/hive-mind/issues/1253
|
|
25
|
+
* @see https://github.com/link-assistant/hive-mind/issues/1981
|
|
25
26
|
*/
|
|
26
27
|
|
|
27
28
|
// Use use-m to dynamically import modules
|
|
@@ -236,9 +237,8 @@ function getThresholdConfig(linoKey, envVarThreshold, envVarStrategy, defaultThr
|
|
|
236
237
|
* - 'enqueue': Block and wait in queue
|
|
237
238
|
* - 'dequeue-one-at-a-time': Allow one command, block subsequent
|
|
238
239
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* To restore old behavior: HIVE_MIND_DISK_STRATEGY=dequeue-one-at-a-time
|
|
240
|
+
* Issue #1981: disk now defaults to the normal wait/enqueue path at 80% used.
|
|
241
|
+
* Operators can still choose immediate rejection with HIVE_MIND_DISK_STRATEGY=reject.
|
|
242
242
|
*/
|
|
243
243
|
export const QUEUE_CONFIG = {
|
|
244
244
|
// Threshold configurations with value and strategy
|
|
@@ -246,10 +246,8 @@ export const QUEUE_CONFIG = {
|
|
|
246
246
|
thresholds: {
|
|
247
247
|
ram: getThresholdConfig('ram', 'HIVE_MIND_RAM_THRESHOLD', 'HIVE_MIND_RAM_STRATEGY', 0.65, 'enqueue'),
|
|
248
248
|
cpu: getThresholdConfig('cpu', 'HIVE_MIND_CPU_THRESHOLD', 'HIVE_MIND_CPU_STRATEGY', 0.65, 'enqueue'),
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
// See: https://github.com/link-assistant/hive-mind/issues/1253
|
|
252
|
-
disk: getThresholdConfig('disk', 'HIVE_MIND_DISK_THRESHOLD', 'HIVE_MIND_DISK_STRATEGY', 0.9, 'reject'),
|
|
249
|
+
// Issue #1981: wait instead of immediately rejecting when disk crosses 80%.
|
|
250
|
+
disk: getThresholdConfig('disk', 'HIVE_MIND_DISK_THRESHOLD', 'HIVE_MIND_DISK_STRATEGY', 0.8, 'enqueue'),
|
|
253
251
|
claude5Hour: getThresholdConfig('claude5Hour', 'HIVE_MIND_CLAUDE_5_HOUR_SESSION_THRESHOLD', 'HIVE_MIND_CLAUDE_5_HOUR_SESSION_STRATEGY', 0.65, 'dequeue-one-at-a-time'),
|
|
254
252
|
claudeWeekly: getThresholdConfig('claudeWeekly', 'HIVE_MIND_CLAUDE_WEEKLY_THRESHOLD', 'HIVE_MIND_CLAUDE_WEEKLY_STRATEGY', 0.97, 'dequeue-one-at-a-time'),
|
|
255
253
|
codex5Hour: getThresholdConfig('codex5Hour', 'HIVE_MIND_CODEX_5_HOUR_SESSION_THRESHOLD', 'HIVE_MIND_CODEX_5_HOUR_SESSION_STRATEGY', 0.65, 'dequeue-one-at-a-time'),
|
|
@@ -265,7 +263,7 @@ export const QUEUE_CONFIG = {
|
|
|
265
263
|
// These are derived from thresholds.{metric}.value
|
|
266
264
|
RAM_THRESHOLD: getThresholdConfig('ram', 'HIVE_MIND_RAM_THRESHOLD', 'HIVE_MIND_RAM_STRATEGY', 0.65, 'enqueue').value,
|
|
267
265
|
CPU_THRESHOLD: getThresholdConfig('cpu', 'HIVE_MIND_CPU_THRESHOLD', 'HIVE_MIND_CPU_STRATEGY', 0.65, 'enqueue').value,
|
|
268
|
-
DISK_THRESHOLD: getThresholdConfig('disk', 'HIVE_MIND_DISK_THRESHOLD', 'HIVE_MIND_DISK_STRATEGY', 0.
|
|
266
|
+
DISK_THRESHOLD: getThresholdConfig('disk', 'HIVE_MIND_DISK_THRESHOLD', 'HIVE_MIND_DISK_STRATEGY', 0.8, 'enqueue').value,
|
|
269
267
|
CLAUDE_5_HOUR_SESSION_THRESHOLD: getThresholdConfig('claude5Hour', 'HIVE_MIND_CLAUDE_5_HOUR_SESSION_THRESHOLD', 'HIVE_MIND_CLAUDE_5_HOUR_SESSION_STRATEGY', 0.65, 'dequeue-one-at-a-time').value,
|
|
270
268
|
CLAUDE_WEEKLY_THRESHOLD: getThresholdConfig('claudeWeekly', 'HIVE_MIND_CLAUDE_WEEKLY_THRESHOLD', 'HIVE_MIND_CLAUDE_WEEKLY_STRATEGY', 0.97, 'dequeue-one-at-a-time').value,
|
|
271
269
|
CODEX_5_HOUR_SESSION_THRESHOLD: getThresholdConfig('codex5Hour', 'HIVE_MIND_CODEX_5_HOUR_SESSION_THRESHOLD', 'HIVE_MIND_CODEX_5_HOUR_SESSION_STRATEGY', 0.65, 'dequeue-one-at-a-time').value,
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -289,8 +289,8 @@ export const SOLVE_OPTION_DEFINITIONS = {
|
|
|
289
289
|
},
|
|
290
290
|
'min-disk-space': {
|
|
291
291
|
type: 'number',
|
|
292
|
-
description: 'Minimum required disk space in MB (default:
|
|
293
|
-
default:
|
|
292
|
+
description: 'Minimum required disk space in MB (default: 10240)',
|
|
293
|
+
default: 10240,
|
|
294
294
|
},
|
|
295
295
|
'log-dir': {
|
|
296
296
|
type: 'string',
|
package/src/solve.mjs
CHANGED
|
@@ -248,7 +248,7 @@ if (argv.planModel) {
|
|
|
248
248
|
const skipToolConnectionCheck = argv.dryRun || argv.skipToolConnectionCheck || argv.toolConnectionCheck === false;
|
|
249
249
|
const { cascadePlaywrightMcpDisable, ensureSolvePlaywrightMcpReady } = await import('./playwright-mcp.lib.mjs');
|
|
250
250
|
await cascadePlaywrightMcpDisable(argv, log);
|
|
251
|
-
if (!(await performSystemChecks(argv.minDiskSpace ||
|
|
251
|
+
if (!(await performSystemChecks(argv.minDiskSpace || 10240, skipToolConnectionCheck, argv.model, argv))) {
|
|
252
252
|
await safeExit(1, 'System checks failed');
|
|
253
253
|
}
|
|
254
254
|
// Playwright MCP preflight is local/free and stays independent from paid tool connection checks.
|
|
@@ -54,7 +54,7 @@ const { parseResetTime: parseResetTimeToDate } = usageLimitLib;
|
|
|
54
54
|
const { validateClaudeConnection } = claudeLib;
|
|
55
55
|
|
|
56
56
|
// Wrapper function for disk space check using imported module
|
|
57
|
-
const checkDiskSpace = async (minSpaceMB =
|
|
57
|
+
const checkDiskSpace = async (minSpaceMB = 10240) => {
|
|
58
58
|
const result = await memoryCheck.checkDiskSpace(minSpaceMB, { log });
|
|
59
59
|
return result.success;
|
|
60
60
|
};
|
|
@@ -216,7 +216,7 @@ export const validateContinueOnlyOnFeedback = async (argv, isPrUrl, isIssueUrl)
|
|
|
216
216
|
// Perform all system checks (disk space, memory, tool connection, GitHub permissions)
|
|
217
217
|
// Note: skipToolConnection only skips the connection check, not model validation
|
|
218
218
|
// Model validation should be done separately before calling this function
|
|
219
|
-
export const performSystemChecks = async (minDiskSpace =
|
|
219
|
+
export const performSystemChecks = async (minDiskSpace = 10240, skipToolConnection = false, model = 'sonnet', argv = {}) => {
|
|
220
220
|
// Check disk space before proceeding
|
|
221
221
|
const hasEnoughSpace = await checkDiskSpace(minDiskSpace);
|
|
222
222
|
if (!hasEnoughSpace) {
|
package/src/task.config.lib.mjs
CHANGED
package/src/task.mjs
CHANGED
|
@@ -35,7 +35,7 @@ if (earlyArgs.length === 0 || earlyArgs.includes('--help') || earlyArgs.includes
|
|
|
35
35
|
console.log(' --split-count Number of issues to split into [default: 2]');
|
|
36
36
|
console.log(' --tool AI tool for agent-commander read-only mode (claude, codex, opencode, agent, qwen, gemini) [default: claude]');
|
|
37
37
|
console.log(' --model, -m Model to use');
|
|
38
|
-
console.log(' --isolation agent-commander isolation mode [default:
|
|
38
|
+
console.log(' --isolation agent-commander isolation mode [default: docker]');
|
|
39
39
|
console.log(' --dry-run Print split output without creating GitHub issues');
|
|
40
40
|
console.log(' --verbose, -v Enable verbose logging');
|
|
41
41
|
console.log(' --output-format Output format (text or json) [default: text]');
|
package/src/telegram-bot.mjs
CHANGED
|
@@ -102,7 +102,7 @@ const config = yargs(hideBin(process.argv))
|
|
|
102
102
|
.option('autoStartScreenWatchMessage', { type: 'boolean', description: 'Experimental: auto-start separate /terminal_watch messages for public /solve sessions', alias: 'auto-start-screen-watch-message', default: getenv('TELEGRAM_AUTO_START_SCREEN_WATCH_MESSAGE', getenv('TELEGRAM_AUTO_WATCH_MESSAGE', 'false')) === 'true' })
|
|
103
103
|
// Issue #594: bot-owner toggle for --show-limits virtual option in /solve and /hive.
|
|
104
104
|
.option('showLimits', { type: 'boolean', description: 'Experimental: allow /solve and /hive callers to use --show-limits to embed Claude/Codex usage at start, end, and delta in the completion message', alias: 'show-limits', default: getenv('TELEGRAM_SHOW_LIMITS', 'true') !== 'false' })
|
|
105
|
-
.option('isolation', { type: 'string', description: "Isolation backend (screen/tmux/docker). Defaults to '
|
|
105
|
+
.option('isolation', { type: 'string', description: "Isolation backend (screen/tmux/docker). Defaults to 'docker' so Telegram-bot work sessions run in Docker isolation; pass --isolation '' (or set TELEGRAM_ISOLATION='') to disable.", default: getenv('TELEGRAM_ISOLATION', 'docker') })
|
|
106
106
|
.help('h')
|
|
107
107
|
.alias('h', 'help')
|
|
108
108
|
.parserConfiguration({
|
|
@@ -724,10 +724,11 @@ export class SolveQueue {
|
|
|
724
724
|
* Default strategies:
|
|
725
725
|
* - RAM: enqueue
|
|
726
726
|
* - CPU: enqueue
|
|
727
|
-
* - DISK:
|
|
727
|
+
* - DISK: enqueue (waits until disk drops below the threshold)
|
|
728
728
|
*
|
|
729
729
|
* See: https://github.com/link-assistant/hive-mind/issues/1155
|
|
730
730
|
* See: https://github.com/link-assistant/hive-mind/issues/1253
|
|
731
|
+
* See: https://github.com/link-assistant/hive-mind/issues/1981
|
|
731
732
|
*
|
|
732
733
|
* @param {number} totalProcessing - Total processing count (queue + external claude processes)
|
|
733
734
|
* @returns {Promise<{ok: boolean, reasons: string[], oneAtATime: boolean, rejected: boolean, rejectReason: string|null}>}
|
|
@@ -584,7 +584,7 @@ export function registerStartStopCommands(bot, options) {
|
|
|
584
584
|
// immediately and was dispatched to a detached session) but the session
|
|
585
585
|
// monitor still tracks a running isolated session for this URL, forward
|
|
586
586
|
// CTRL+C to its start-command UUID. This is the common case for tasks
|
|
587
|
-
// that begin executing right away with
|
|
587
|
+
// that begin executing right away with an isolation backend.
|
|
588
588
|
const queueHasTask = lookup.action === 'cancel-queued' || lookup.action === 'stop-running';
|
|
589
589
|
if (!queueHasTask && runningSession?.stoppable && runningSession.sessionId) {
|
|
590
590
|
VERBOSE && console.log(`[VERBOSE] /stop: forwarding CTRL+C to tracked session ${runningSession.sessionId} for ${url} (queue action=${lookup.action})`);
|
|
@@ -597,7 +597,7 @@ export function registerStartStopCommands(bot, options) {
|
|
|
597
597
|
// running-but-non-stoppable (non-isolation) session, say so; otherwise
|
|
598
598
|
// fall back to the UUID hint.
|
|
599
599
|
if (runningSession) {
|
|
600
|
-
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time
|
|
600
|
+
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time run it with the default isolation backend or pass \`--isolation docker\` to make this task interruptible via \`/stop\`.`, {
|
|
601
601
|
parse_mode: 'Markdown',
|
|
602
602
|
reply_to_message_id: message.message_id,
|
|
603
603
|
});
|
|
@@ -615,13 +615,13 @@ export function registerStartStopCommands(bot, options) {
|
|
|
615
615
|
// have forwarded CTRL+C above). If it tracked a non-isolation session,
|
|
616
616
|
// explain why it can't be stopped; otherwise report not found.
|
|
617
617
|
if (runningSession) {
|
|
618
|
-
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time
|
|
618
|
+
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time run it with the default isolation backend or pass \`--isolation docker\` to make this task interruptible via \`/stop\`.`, {
|
|
619
619
|
parse_mode: 'Markdown',
|
|
620
620
|
reply_to_message_id: message.message_id,
|
|
621
621
|
});
|
|
622
622
|
return;
|
|
623
623
|
}
|
|
624
|
-
await ctx.reply(`ℹ️ No queued or running task found for ${url}.\n\nIf the task is running with
|
|
624
|
+
await ctx.reply(`ℹ️ No queued or running task found for ${url}.\n\nIf the task is running with an isolation backend, try \`/stop <UUID>\` (the UUID is shown in the bot's session-id message).`, {
|
|
625
625
|
parse_mode: 'Markdown',
|
|
626
626
|
reply_to_message_id: message.message_id,
|
|
627
627
|
});
|
|
@@ -655,7 +655,7 @@ export function registerStartStopCommands(bot, options) {
|
|
|
655
655
|
// running-not-isolated: a started, non-isolated screen session. We
|
|
656
656
|
// could shell out to `screen -X -S <name> stuff $'\003'`, but that's
|
|
657
657
|
// brittle and out of scope for #1780. Tell the user how to recover.
|
|
658
|
-
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time
|
|
658
|
+
await ctx.reply(`⚠️ Found a running task for ${url}, but it was not started with an isolation backend, so \`/stop\` cannot forward CTRL+C to it.\n\nNext time run it with the default isolation backend or pass \`--isolation docker\` to make this task interruptible via \`/stop\`.`, {
|
|
659
659
|
parse_mode: 'Markdown',
|
|
660
660
|
reply_to_message_id: message.message_id,
|
|
661
661
|
});
|