@link-assistant/hive-mind 2.5.5 → 2.5.6
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 +7 -0
- package/package.json +1 -1
- package/src/config.lib.mjs +4 -14
- package/src/env-config.lib.mjs +98 -0
- package/src/queue-config.lib.mjs +8 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.5.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e501237: Warn when malformed or safety-clamped numeric environment settings fall back to a different effective value.
|
|
8
|
+
- 10ddbca: Document same-session live input support and the Codex app-server integration plan for issue #2057.
|
|
9
|
+
|
|
3
10
|
## 2.5.5
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/package.json
CHANGED
package/src/config.lib.mjs
CHANGED
|
@@ -30,23 +30,13 @@ const getenv = typeof getenvModule === 'function' ? getenvModule : getenvModule.
|
|
|
30
30
|
// Use semver package for version comparison (see issue #1146)
|
|
31
31
|
import semver from 'semver';
|
|
32
32
|
import { buildClaudeQuietEnv } from './claude-quiet-config.lib.mjs';
|
|
33
|
+
import { clampEnvValue, parseIntegerEnv, parseNumberEnv } from './env-config.lib.mjs';
|
|
33
34
|
|
|
34
35
|
// Import lino for parsing Links Notation format
|
|
35
36
|
const { lino } = await import('./lino.lib.mjs');
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const value = getenv(envVar, defaultValue.toString());
|
|
40
|
-
const parsed = parseInt(value);
|
|
41
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Helper function to safely parse floats with fallback
|
|
45
|
-
const parseFloatWithDefault = (envVar, defaultValue) => {
|
|
46
|
-
const value = getenv(envVar, defaultValue.toString());
|
|
47
|
-
const parsed = parseFloat(value);
|
|
48
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
49
|
-
};
|
|
38
|
+
const parseIntWithDefault = (envVar, defaultValue) => parseIntegerEnv(envVar, defaultValue);
|
|
39
|
+
const parseFloatWithDefault = (envVar, defaultValue) => parseNumberEnv(envVar, defaultValue);
|
|
50
40
|
|
|
51
41
|
// Timeout configurations (in milliseconds)
|
|
52
42
|
export const timeouts = {
|
|
@@ -737,7 +727,7 @@ export const cacheTtl = {
|
|
|
737
727
|
usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS', 13 * 60 * 1000), // 13 minutes
|
|
738
728
|
// System metrics cache TTL (RAM, CPU, disk). Issue #2015 caps this at
|
|
739
729
|
// 1 minute so queue decisions do not use stale host pressure data.
|
|
740
|
-
system:
|
|
730
|
+
system: clampEnvValue('HIVE_MIND_SYSTEM_CACHE_TTL_MS', parseIntWithDefault('HIVE_MIND_SYSTEM_CACHE_TTL_MS', 60 * 1000), { maximum: 60 * 1000 }), // max 1 minute
|
|
741
731
|
};
|
|
742
732
|
|
|
743
733
|
// File and path configurations
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse numeric environment configuration without silently accepting malformed
|
|
3
|
+
* suffixes or discarding explicit operator input.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const emittedWarnings = new Set();
|
|
7
|
+
|
|
8
|
+
function warnOnce(key, message) {
|
|
9
|
+
if (emittedWarnings.has(key)) return;
|
|
10
|
+
emittedWarnings.add(key);
|
|
11
|
+
console.warn(message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readExplicitEnv(envVar) {
|
|
15
|
+
const rawValue = process.env[envVar];
|
|
16
|
+
return rawValue === undefined ? null : rawValue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function warnInvalid(envVar, rawValue, type, defaultValue, scope) {
|
|
20
|
+
warnOnce(`invalid:${envVar}`, `[${scope}] ${envVar}=${JSON.stringify(rawValue)} is not a valid ${type}; using default ${defaultValue}.`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read a base-10 integer environment variable.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} envVar
|
|
27
|
+
* @param {number} defaultValue
|
|
28
|
+
* @param {{scope?: string}} [options]
|
|
29
|
+
* @returns {number}
|
|
30
|
+
*/
|
|
31
|
+
export function parseIntegerEnv(envVar, defaultValue, { scope = 'config' } = {}) {
|
|
32
|
+
const rawValue = readExplicitEnv(envVar);
|
|
33
|
+
if (rawValue === null) return defaultValue;
|
|
34
|
+
|
|
35
|
+
const normalized = rawValue.trim();
|
|
36
|
+
if (!/^[+-]?\d+$/.test(normalized)) {
|
|
37
|
+
warnInvalid(envVar, rawValue, 'integer', defaultValue, scope);
|
|
38
|
+
return defaultValue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const parsed = Number(normalized);
|
|
42
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
43
|
+
warnInvalid(envVar, rawValue, 'integer', defaultValue, scope);
|
|
44
|
+
return defaultValue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return parsed;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Read a finite decimal environment variable.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} envVar
|
|
54
|
+
* @param {number} defaultValue
|
|
55
|
+
* @param {{scope?: string}} [options]
|
|
56
|
+
* @returns {number}
|
|
57
|
+
*/
|
|
58
|
+
export function parseNumberEnv(envVar, defaultValue, { scope = 'config' } = {}) {
|
|
59
|
+
const rawValue = readExplicitEnv(envVar);
|
|
60
|
+
if (rawValue === null) return defaultValue;
|
|
61
|
+
|
|
62
|
+
const normalized = rawValue.trim();
|
|
63
|
+
const isDecimal = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(normalized);
|
|
64
|
+
const parsed = Number(normalized);
|
|
65
|
+
if (!isDecimal || !Number.isFinite(parsed)) {
|
|
66
|
+
warnInvalid(envVar, rawValue, 'number', defaultValue, scope);
|
|
67
|
+
return defaultValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Apply a safety bound and explain when it changes an explicitly configured
|
|
75
|
+
* environment value.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} envVar
|
|
78
|
+
* @param {number} value
|
|
79
|
+
* @param {{minimum?: number, maximum?: number, scope?: string, hint?: string}} options
|
|
80
|
+
* @returns {number}
|
|
81
|
+
*/
|
|
82
|
+
export function clampEnvValue(envVar, value, { minimum, maximum, scope = 'config', hint = '' }) {
|
|
83
|
+
if (minimum !== undefined && value < minimum) {
|
|
84
|
+
if (readExplicitEnv(envVar) !== null) {
|
|
85
|
+
warnOnce(`minimum:${envVar}`, `[${scope}] ${envVar}=${value} is below the minimum (${minimum}); using ${minimum}.${hint ? ` ${hint}` : ''}`);
|
|
86
|
+
}
|
|
87
|
+
return minimum;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (maximum !== undefined && value > maximum) {
|
|
91
|
+
if (readExplicitEnv(envVar) !== null) {
|
|
92
|
+
warnOnce(`maximum:${envVar}`, `[${scope}] ${envVar}=${value} exceeds the maximum (${maximum}); using ${maximum}.${hint ? ` ${hint}` : ''}`);
|
|
93
|
+
}
|
|
94
|
+
return maximum;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return value;
|
|
98
|
+
}
|
package/src/queue-config.lib.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { ensureUseM } from './use-m-bootstrap.lib.mjs';
|
|
3
|
+
import { clampEnvValue, parseIntegerEnv, parseNumberEnv } from './env-config.lib.mjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Queue Configuration Module
|
|
@@ -178,19 +179,8 @@ export function parseQueueConfig(linoConfig) {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
const value = getenv(envVar, defaultValue.toString());
|
|
184
|
-
const parsed = parseFloat(value);
|
|
185
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
// Helper function to safely parse integers with fallback
|
|
189
|
-
const parseIntWithDefault = (envVar, defaultValue) => {
|
|
190
|
-
const value = getenv(envVar, defaultValue.toString());
|
|
191
|
-
const parsed = parseInt(value);
|
|
192
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
193
|
-
};
|
|
182
|
+
const parseFloatWithDefault = (envVar, defaultValue) => parseNumberEnv(envVar, defaultValue, { scope: 'queue-config' });
|
|
183
|
+
const parseIntWithDefault = (envVar, defaultValue) => parseIntegerEnv(envVar, defaultValue, { scope: 'queue-config' });
|
|
194
184
|
|
|
195
185
|
const DEFAULT_MINIMUM_START_INTERVAL_MS = 10 * 60 * 1000;
|
|
196
186
|
const minimumStartIntervalMs = parseIntWithDefault('HIVE_MIND_MIN_START_INTERVAL_FLOOR_MS', DEFAULT_MINIMUM_START_INTERVAL_MS);
|
|
@@ -279,7 +269,11 @@ export const QUEUE_CONFIG = {
|
|
|
279
269
|
// can kill the next batch before host metrics have time to settle.
|
|
280
270
|
// Issue #2053: operators can explicitly lower the safety floor on hosts where
|
|
281
271
|
// resource metrics settle sooner. The default remains 10 minutes.
|
|
282
|
-
MIN_START_INTERVAL_MS:
|
|
272
|
+
MIN_START_INTERVAL_MS: clampEnvValue('HIVE_MIND_MIN_START_INTERVAL_MS', parseIntWithDefault('HIVE_MIND_MIN_START_INTERVAL_MS', DEFAULT_MINIMUM_START_INTERVAL_MS), {
|
|
273
|
+
minimum: minimumStartIntervalMs,
|
|
274
|
+
scope: 'queue-config',
|
|
275
|
+
hint: 'Set HIVE_MIND_MIN_START_INTERVAL_FLOOR_MS to lower the minimum.',
|
|
276
|
+
}),
|
|
283
277
|
CONSUMER_POLL_INTERVAL_MS: parseIntWithDefault('HIVE_MIND_CONSUMER_POLL_INTERVAL_MS', 60000), // 1 minute between queue checks
|
|
284
278
|
MESSAGE_UPDATE_INTERVAL_MS: parseIntWithDefault('HIVE_MIND_MESSAGE_UPDATE_INTERVAL_MS', 60000), // 1 minute between status message updates
|
|
285
279
|
|