@link-assistant/hive-mind 1.11.2 → 1.11.4

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,31 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.11.4
4
+
5
+ ### Patch Changes
6
+
7
+ - b8318dd: fix: support opencode/gpt-5-nano and gpt-5-nano for --tool agent (Issue #1185)
8
+
9
+ Fixed AGENT_MODELS mapping to correctly support free OpenCode Zen models:
10
+ - `gpt-5-nano` short alias now correctly maps to `opencode/gpt-5-nano` (previously incorrectly mapped to `openai/gpt-5-nano`)
11
+ - `opencode/gpt-5-nano` full model ID is now recognized as valid
12
+ - Updated `mapModelToId` function in agent.lib.mjs to use correct provider prefix
13
+ - Fixed regex filter in `getAvailableModelNames` to include `gpt-5-nano` in available models display
14
+ - Added comprehensive test suite with 18 tests for agent model validation
15
+ - Added case study documentation with root cause analysis
16
+
17
+ ## 1.11.3
18
+
19
+ ### Patch Changes
20
+
21
+ - 9f24356: Fix 'ready' label not being created by /merge command
22
+
23
+ Two bugs prevented the /merge command from creating the 'ready' label:
24
+ 1. `checkReadyLabelExists()` incorrectly treated GitHub API's 404 JSON error response as the label existing. The function now properly checks for "Not Found" message in the response.
25
+ 2. `createReadyLabel()` used bash-specific heredoc syntax (`<<<`) which fails in `/bin/sh`. Now uses `gh api -f` flags for shell compatibility.
26
+
27
+ Fixes #1177
28
+
3
29
  ## 1.11.2
4
30
 
5
31
  ### Patch Changes
package/README.md CHANGED
@@ -644,6 +644,10 @@ grep -E '\(cd /tmp/gh-issue-solver-[0-9]+ && claude --resume [0-9a-f-]{36}\)' hi
644
644
  - `gh auth login` - GitHub CLI authentication
645
645
  - `claude-profiles` - Claude authentication profile migration to server
646
646
 
647
+ **OpenRouter Integration:**
648
+
649
+ Use OpenRouter to access 500+ AI models from 60+ providers with a single API key. See [docs/OPENROUTER.md](./docs/OPENROUTER.md) for setup instructions covering both Claude Code CLI and @link-assistant/agent.
650
+
647
651
  **Environment Variables & Advanced Options:**
648
652
 
649
653
  For comprehensive configuration including environment variables, timeouts, retry limits, Telegram bot settings, YouTrack integration, and all CLI options, see [docs/CONFIGURATION.md](./docs/CONFIGURATION.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.11.2",
3
+ "version": "1.11.4",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
package/src/agent.lib.mjs CHANGED
@@ -150,14 +150,15 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
150
150
  };
151
151
 
152
152
  // Model mapping to translate aliases to full model IDs for Agent
153
- // Agent uses OpenCode's JSON interface and models
153
+ // Agent uses OpenCode Zen's JSON interface and models
154
+ // Issue #1185: Free models use opencode/ prefix (not openai/)
154
155
  export const mapModelToId = model => {
155
156
  const modelMap = {
156
157
  grok: 'opencode/grok-code',
157
158
  'grok-code': 'opencode/grok-code',
158
159
  'grok-code-fast-1': 'opencode/grok-code',
159
160
  'big-pickle': 'opencode/big-pickle',
160
- 'gpt-5-nano': 'openai/gpt-5-nano',
161
+ 'gpt-5-nano': 'opencode/gpt-5-nano',
161
162
  sonnet: 'anthropic/claude-3-5-sonnet',
162
163
  haiku: 'anthropic/claude-3-5-haiku',
163
164
  opus: 'anthropic/claude-3-opus',
@@ -38,10 +38,25 @@ export async function checkReadyLabelExists(owner, repo, verbose = false) {
38
38
  const { stdout } = await exec(`gh api repos/${owner}/${repo}/labels/${READY_LABEL.name} 2>/dev/null || echo ""`);
39
39
  if (stdout.trim()) {
40
40
  const label = JSON.parse(stdout.trim());
41
+ // Check if the response is an error (404 Not Found returns JSON with "message" field)
42
+ if (label.message === 'Not Found' || label.status === '404') {
43
+ if (verbose) {
44
+ console.log(`[VERBOSE] /merge: 'ready' label does not exist in ${owner}/${repo}`);
45
+ }
46
+ return { exists: false, label: null };
47
+ }
48
+ // Valid label has a 'name' field
49
+ if (label.name) {
50
+ if (verbose) {
51
+ console.log(`[VERBOSE] /merge: 'ready' label exists in ${owner}/${repo}`);
52
+ }
53
+ return { exists: true, label };
54
+ }
55
+ // Unknown response format, treat as not found
41
56
  if (verbose) {
42
- console.log(`[VERBOSE] /merge: 'ready' label exists in ${owner}/${repo}`);
57
+ console.log(`[VERBOSE] /merge: Unexpected response format when checking label in ${owner}/${repo}`);
43
58
  }
44
- return { exists: true, label };
59
+ return { exists: false, label: null };
45
60
  }
46
61
  if (verbose) {
47
62
  console.log(`[VERBOSE] /merge: 'ready' label does not exist in ${owner}/${repo}`);
@@ -64,13 +79,8 @@ export async function checkReadyLabelExists(owner, repo, verbose = false) {
64
79
  */
65
80
  export async function createReadyLabel(owner, repo, verbose = false) {
66
81
  try {
67
- const labelData = JSON.stringify({
68
- name: READY_LABEL.name,
69
- description: READY_LABEL.description,
70
- color: READY_LABEL.color,
71
- });
72
-
73
- const { stdout } = await exec(`gh api repos/${owner}/${repo}/labels -X POST -H "Accept: application/vnd.github+json" --input - <<< '${labelData}'`);
82
+ // Use gh api with -f flags to pass fields directly (avoids shell heredoc compatibility issues)
83
+ const { stdout } = await exec(`gh api repos/${owner}/${repo}/labels -X POST -H "Accept: application/vnd.github+json" -f name="${READY_LABEL.name}" -f description="${READY_LABEL.description}" -f color="${READY_LABEL.color}"`);
74
84
  const label = JSON.parse(stdout.trim());
75
85
 
76
86
  if (verbose) {
@@ -66,21 +66,22 @@ export const CODEX_MODELS = {
66
66
  };
67
67
 
68
68
  export const AGENT_MODELS = {
69
- // Free models (via OpenCode)
69
+ // Free models (via OpenCode Zen)
70
+ // Issue #1185: Model IDs must use opencode/ prefix for OpenCode Zen models
70
71
  grok: 'opencode/grok-code',
71
72
  'grok-code': 'opencode/grok-code',
72
73
  'grok-code-fast-1': 'opencode/grok-code',
73
74
  'big-pickle': 'opencode/big-pickle',
74
- 'gpt-5-nano': 'openai/gpt-5-nano',
75
+ 'gpt-5-nano': 'opencode/gpt-5-nano',
75
76
  // Premium models (requires OpenCode Zen subscription)
76
77
  sonnet: 'anthropic/claude-3-5-sonnet',
77
78
  haiku: 'anthropic/claude-3-5-haiku',
78
79
  opus: 'anthropic/claude-3-opus',
79
80
  'gemini-3-pro': 'google/gemini-3-pro',
80
- // Full model IDs
81
+ // Full model IDs with provider prefix
81
82
  'opencode/grok-code': 'opencode/grok-code',
82
83
  'opencode/big-pickle': 'opencode/big-pickle',
83
- 'openai/gpt-5-nano': 'openai/gpt-5-nano',
84
+ 'opencode/gpt-5-nano': 'opencode/gpt-5-nano',
84
85
  'anthropic/claude-3-5-sonnet': 'anthropic/claude-3-5-sonnet',
85
86
  'anthropic/claude-3-5-haiku': 'anthropic/claude-3-5-haiku',
86
87
  'anthropic/claude-3-opus': 'anthropic/claude-3-opus',
@@ -118,11 +119,12 @@ export const getAvailableModelNames = tool => {
118
119
  // Keep short aliases only - exclude:
119
120
  // - Full model IDs with slashes (e.g., 'openai/gpt-4')
120
121
  // - Long claude-prefixed model IDs (e.g., 'claude-sonnet-4-5-20250929')
121
- // - Full gpt- prefixed IDs with version numbers (e.g., 'gpt-4', 'gpt-4o')
122
- // But keep short names like 'o3', 'o3-mini', 'gpt5', etc.
122
+ // - Full gpt- prefixed IDs that are ONLY version numbers (e.g., 'gpt-4', 'gpt-4o', 'gpt-5')
123
+ // But keep descriptive aliases like 'gpt-5-nano', 'gpt-5-codex', 'o3', 'o3-mini', 'gpt5', etc.
124
+ // Issue #1185: Updated regex to not filter out gpt-5-nano (a valid short alias)
123
125
  if (key.includes('/')) return false;
124
126
  if (key.match(/^claude-.*-\d{8}$/)) return false; // Full claude model IDs with date
125
- if (key.match(/^gpt-\d+/)) return false; // Full gpt-N model IDs
127
+ if (key.match(/^gpt-\d+[a-z]?$/)) return false; // Full gpt-N or gpt-No model IDs only (e.g., gpt-4, gpt-4o, gpt-5)
126
128
  return true;
127
129
  });
128
130
  return [...new Set(aliases)];