@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 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",
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)) accept(plugins, normalizePluginSelector(match[1]), line);
94
- for (const match of line.matchAll(NAMESPACED_SKILL)) accept(skills, match[1].toLowerCase(), line);
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 };
@@ -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 = {