@link-assistant/hive-mind 2.8.3 → 2.8.5
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 +16 -0
- package/package.json +3 -3
- package/src/codex-capability-preflight.lib.mjs +31 -2
- package/src/config.lib.mjs +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.8.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9a1cbf4: Fix false positives and false negatives in CI/CD (issue #2082). Release and Helm scripts now fail on non-zero exit codes instead of silently continuing, npm publish verification retries registry propagation without republishing, version bumps retry a rejected push on top of the new remote HEAD, shell test assertions fail the build, every workflow job declares a timeout, and jobs use `!cancelled()` so concurrency cancellation is respected. Releases on main now queue rather than cancel, so a run cannot be interrupted between publishing to npm and pushing the version bump.
|
|
8
|
+
|
|
9
|
+
Linting now also covers the `tests/` tree, which `npm run lint` and `eslint.config.mjs` both excluded — the lint job reported success while never reading the largest source tree in the repository. Enabling it surfaced real defects across 59 files, including `assert.match` regexes with unescaped literal indentation that made assertions pass for the wrong reason.
|
|
10
|
+
|
|
11
|
+
Stops leaking `CLAUDE_CODE_EFFORT_LEVEL` from the parent shell into the Claude process. `getClaudeEnv()` builds the child environment from `process.env` and sanitised an inherited `MAX_THINKING_TOKENS`, but not the effort level, so any path that computed no level passed the parent's value through — giving `haiku` an effort level it does not support, and `--think off` one despite thinking being disabled. Since Claude Code exports this variable, the leak applied whenever hive-mind ran under it. The emitted effort level is now a function of the selected model and think level only.
|
|
12
|
+
|
|
13
|
+
## 2.8.4
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 4373bc8: Stop treating JSON Schema, structured-data values, and package selectors as required Codex capabilities while preserving explicit skill and catalog plugin discovery.
|
|
18
|
+
|
|
3
19
|
## 2.8.3
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/hive-mind",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.5",
|
|
4
4
|
"description": "AI-powered issue solver and hive mind for collaborative problem solving",
|
|
5
5
|
"main": "src/hive.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"test:queue": "node tests/solve-queue.test.mjs",
|
|
22
22
|
"test:limits-display": "node tests/limits-display.test.mjs",
|
|
23
23
|
"test:usage-limit": "node tests/test-usage-limit.mjs",
|
|
24
|
-
"lint": "eslint 'src/**/*.{js,mjs,cjs}' 'scripts/**/*.{js,mjs,cjs}' 'eslint-rules/**/*.{js,mjs,cjs}'",
|
|
25
|
-
"lint:fix": "eslint 'src/**/*.{js,mjs,cjs}' 'scripts/**/*.{js,mjs,cjs}' 'eslint-rules/**/*.{js,mjs,cjs}' --fix",
|
|
24
|
+
"lint": "eslint 'src/**/*.{js,mjs,cjs}' 'scripts/**/*.{js,mjs,cjs}' 'eslint-rules/**/*.{js,mjs,cjs}' 'tests/**/*.{js,mjs,cjs}'",
|
|
25
|
+
"lint:fix": "eslint 'src/**/*.{js,mjs,cjs}' 'scripts/**/*.{js,mjs,cjs}' 'eslint-rules/**/*.{js,mjs,cjs}' 'tests/**/*.{js,mjs,cjs}' --fix",
|
|
26
26
|
"check:duplication": "jscpd .",
|
|
27
27
|
"format": "prettier --write \"**/*.{js,mjs,json,md}\" --ignore-path .prettierignore",
|
|
28
28
|
"format:check": "prettier --check \"**/*.{js,mjs,json,md}\" --ignore-path .prettierignore",
|
|
@@ -21,6 +21,9 @@ const NEGATED_REQUIREMENT = /\b(?:does\s+not\s+require|not\s+required|optional)\
|
|
|
21
21
|
const PLUGIN_SELECTOR = /\b([a-z0-9][a-z0-9-]*@[a-z0-9][a-z0-9-]*(?:-remote)?)\b(?!\.[a-z])/gi;
|
|
22
22
|
const NAMESPACED_SKILL = /\b([a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*)\b/gi;
|
|
23
23
|
const EXPLICIT_BARE_SKILL = /\$([a-z0-9][a-z0-9-]*)|`([a-z0-9][a-z0-9-]*)`\s+(?:agent\s+)?skill/gi;
|
|
24
|
+
const CAPABILITY_PREFIX = /\b(?:depend(?:s|ed)?\s+on|install|invoke|must\s+(?:install|invoke|use)|need(?:ed|s)?(?:\s+to)?(?:\s+(?:install|invoke|use))?|require(?:d|s)?(?:\s+to)?(?:\s+(?:install|invoke|use))?|use)\s+(?:(?:the|an?)\s+)?(?:(?:agent\s+)?skill\s+)?(?:named\s+)?[`$]?$/i;
|
|
25
|
+
const CAPABILITY_SUFFIX = /^`?\s+(?:agent\s+)?(?:skill|capability)\b/i;
|
|
26
|
+
const STRUCTURED_DATA_VALUES = new Set(['array', 'boolean', 'false', 'integer', 'null', 'number', 'object', 'string', 'true']);
|
|
24
27
|
|
|
25
28
|
// Issue #2077: a capability name must contain at least one letter.
|
|
26
29
|
//
|
|
@@ -44,6 +47,21 @@ const PROSE_TOKENS = new Set(['agent', 'caution', 'codex', 'default', 'error', '
|
|
|
44
47
|
|
|
45
48
|
const isCapabilityToken = value => CAPABILITY_TOKEN.test(value) && !PROSE_TOKENS.has(value);
|
|
46
49
|
|
|
50
|
+
const hasExplicitCapabilityContext = (line, match) => {
|
|
51
|
+
const before = line.slice(0, match.index);
|
|
52
|
+
const after = line.slice(match.index + match[0].length);
|
|
53
|
+
if (CAPABILITY_SUFFIX.test(after) || before.endsWith('$')) return true;
|
|
54
|
+
const value = match[1].slice(match[1].indexOf(':') + 1).toLowerCase();
|
|
55
|
+
return !STRUCTURED_DATA_VALUES.has(value) && CAPABILITY_PREFIX.test(before);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const hasExplicitPluginContext = (line, match) => {
|
|
59
|
+
const before = line.slice(0, match.index);
|
|
60
|
+
const after = line.slice(match.index + match[0].length);
|
|
61
|
+
const marketplace = match[1].slice(match[1].indexOf('@') + 1);
|
|
62
|
+
return /(?:^|-)(?:bundled|curated|marketplace|remote)(?:-|$)/iu.test(marketplace) || /\bplugin\s+[`$]?$/iu.test(before) || /^`?\s+plugin\b/iu.test(after);
|
|
63
|
+
};
|
|
64
|
+
|
|
47
65
|
export function isCapabilityName(value) {
|
|
48
66
|
const token = String(value || '').toLowerCase();
|
|
49
67
|
const separator = /[:@]/u.exec(token);
|
|
@@ -90,8 +108,16 @@ export function detectRequiredCodexCapabilities(text) {
|
|
|
90
108
|
const line = rawLine.trim();
|
|
91
109
|
if (!line || !REQUIREMENT_WORDS.test(line) || NEGATED_REQUIREMENT.test(line)) continue;
|
|
92
110
|
|
|
93
|
-
for (const match of line.matchAll(PLUGIN_SELECTOR))
|
|
94
|
-
|
|
111
|
+
for (const match of line.matchAll(PLUGIN_SELECTOR)) {
|
|
112
|
+
const selector = normalizePluginSelector(match[1]);
|
|
113
|
+
if (hasExplicitPluginContext(line, match)) accept(plugins, selector, line);
|
|
114
|
+
else rejected.push({ capability: selector, line });
|
|
115
|
+
}
|
|
116
|
+
for (const match of line.matchAll(NAMESPACED_SKILL)) {
|
|
117
|
+
const skill = match[1].toLowerCase();
|
|
118
|
+
if (hasExplicitCapabilityContext(line, match)) accept(skills, skill, line);
|
|
119
|
+
else rejected.push({ capability: skill, line });
|
|
120
|
+
}
|
|
95
121
|
for (const match of line.matchAll(EXPLICIT_BARE_SKILL)) accept(skills, (match[1] || match[2]).toLowerCase(), line);
|
|
96
122
|
}
|
|
97
123
|
|
|
@@ -310,6 +336,9 @@ async function provisionCodexCapabilities({ owner, repo, issueNumber, projectDir
|
|
|
310
336
|
const baseCatalog = parseJsonCommand(baseCatalogResult, 'Codex plugin catalog discovery');
|
|
311
337
|
const skillDirectories = [path.join(os.homedir(), '.agents', 'skills'), projectDir && path.join(projectDir, '.agents', 'skills')].filter(Boolean);
|
|
312
338
|
const plugins = await resolveRequiredPlugins({ requirements, catalog: baseCatalog, skillDirectories });
|
|
339
|
+
for (const plugin of plugins) {
|
|
340
|
+
await log(` ✅ Verified ${plugin} in the Codex plugin catalog`, { verbose: true });
|
|
341
|
+
}
|
|
313
342
|
if (plugins.length === 0) {
|
|
314
343
|
await log(' ✅ Required Agent Skills are already available from standard skill directories');
|
|
315
344
|
return { required: true, plugins, skills: requirements.skills, codexHome: null, baseCodexHome };
|
package/src/config.lib.mjs
CHANGED
|
@@ -627,6 +627,16 @@ export const getClaudeEnv = (options = {}) => {
|
|
|
627
627
|
env.MAX_THINKING_TOKENS = String(options.thinkingBudget ?? 0);
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
+
// Remove any inherited CLAUDE_CODE_EFFORT_LEVEL from process.env, mirroring the
|
|
631
|
+
// MAX_THINKING_TOKENS sanitisation above (Issue #2082). Without this, an effort
|
|
632
|
+
// level exported by the parent shell survives into the child whenever the logic
|
|
633
|
+
// below does not compute one — e.g. a model that supports no effort levels at all
|
|
634
|
+
// (haiku), or --think off. hive-mind's own agents run under Claude Code, which
|
|
635
|
+
// exports this variable, so the leak fired in exactly the common case: `haiku
|
|
636
|
+
// --think high` inherited effort=max from the parent. The value below must be a
|
|
637
|
+
// function of the selected model and think level, never of the ambient shell.
|
|
638
|
+
delete env.CLAUDE_CODE_EFFORT_LEVEL;
|
|
639
|
+
|
|
630
640
|
// Set CLAUDE_CODE_EFFORT_LEVEL for models that support it (Issue #1238, Issue #1620)
|
|
631
641
|
if (options.model && supportsEffortLevel(options.model)) {
|
|
632
642
|
const effortOptions = {
|