@link-assistant/hive-mind 1.11.3 → 1.11.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,27 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.11.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 7d3387c: Fix duplicate Solution Draft Log comments on GitHub PRs
8
+
9
+ When a Claude session ends with uncommitted changes and --attach-logs is enabled, the solution draft log was being uploaded twice - once by verifyResults() during normal completion, and again after temporary watch mode completes. This fix tracks whether logs were already uploaded and skips the duplicate upload.
10
+
11
+ ## 1.11.4
12
+
13
+ ### Patch Changes
14
+
15
+ - b8318dd: fix: support opencode/gpt-5-nano and gpt-5-nano for --tool agent (Issue #1185)
16
+
17
+ Fixed AGENT_MODELS mapping to correctly support free OpenCode Zen models:
18
+ - `gpt-5-nano` short alias now correctly maps to `opencode/gpt-5-nano` (previously incorrectly mapped to `openai/gpt-5-nano`)
19
+ - `opencode/gpt-5-nano` full model ID is now recognized as valid
20
+ - Updated `mapModelToId` function in agent.lib.mjs to use correct provider prefix
21
+ - Fixed regex filter in `getAvailableModelNames` to include `gpt-5-nano` in available models display
22
+ - Added comprehensive test suite with 18 tests for agent model validation
23
+ - Added case study documentation with root cause analysis
24
+
3
25
  ## 1.11.3
4
26
 
5
27
  ### 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.3",
3
+ "version": "1.11.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",
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',
@@ -194,7 +194,7 @@ export const cacheTtl = {
194
194
  api: parseIntWithDefault('HIVE_MIND_API_CACHE_TTL_MS', 3 * 60 * 1000), // 3 minutes
195
195
  // Claude Usage API cache TTL - must be at least 20 minutes to avoid rate limiting
196
196
  // The API returns null values when called too frequently
197
- usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS', 20 * 60 * 1000), // 20 minutes
197
+ usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS', 10 * 60 * 1000), // 10 minutes
198
198
  // System metrics cache TTL (RAM, CPU, disk)
199
199
  system: parseIntWithDefault('HIVE_MIND_SYSTEM_CACHE_TTL_MS', 2 * 60 * 1000), // 2 minutes
200
200
  };
@@ -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)];
package/src/solve.mjs CHANGED
@@ -1159,7 +1159,9 @@ try {
1159
1159
  // Pass shouldRestart to prevent early exit when auto-restart is needed
1160
1160
  // Include agent tool pricing data when available (publicPricingEstimate, pricingInfo)
1161
1161
  // Issue #1088: Pass errorDuringExecution for "Finished with errors" state
1162
- await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution);
1162
+ // Issue #1154: Track if logs were already uploaded to prevent duplicates
1163
+ const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution);
1164
+ const logsAlreadyUploaded = verifyResult?.logUploadSuccess || false;
1163
1165
 
1164
1166
  // Start watch mode if enabled OR if we need to handle uncommitted changes
1165
1167
  if (argv.verbose) {
@@ -1246,7 +1248,8 @@ try {
1246
1248
  }
1247
1249
 
1248
1250
  // Attach updated logs to PR after auto-restart completes
1249
- if (shouldAttachLogs && prNumber) {
1251
+ // Issue #1154: Skip if logs were already uploaded by verifyResults() to prevent duplicates
1252
+ if (shouldAttachLogs && prNumber && !logsAlreadyUploaded) {
1250
1253
  await log('📎 Uploading working session logs to Pull Request...');
1251
1254
  try {
1252
1255
  const logUploadSuccess = await attachLogToGitHub({
@@ -1273,6 +1276,9 @@ try {
1273
1276
  } catch (uploadError) {
1274
1277
  await log(`⚠️ Error uploading logs: ${uploadError.message}`, { level: 'warning' });
1275
1278
  }
1279
+ } else if (logsAlreadyUploaded) {
1280
+ await log('ℹ️ Logs already uploaded by verifyResults, skipping duplicate upload', { verbose: true });
1281
+ logsAttached = true;
1276
1282
  }
1277
1283
  }
1278
1284
 
@@ -564,7 +564,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
564
564
  if (!argv.watch && !shouldRestart) {
565
565
  await safeExit(0, 'Process completed successfully');
566
566
  }
567
- return; // Return normally for watch mode or auto-restart
567
+ // Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
568
+ return { logUploadSuccess }; // Return for watch mode or auto-restart
568
569
  } else {
569
570
  await log(` ℹ️ Found pull request #${pr.number} but it appears to be from a different session`);
570
571
  }
@@ -627,7 +628,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
627
628
  if (!argv.watch && !shouldRestart) {
628
629
  await safeExit(0, 'Process completed successfully');
629
630
  }
630
- return; // Return normally for watch mode or auto-restart
631
+ // Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
632
+ return { logUploadSuccess: true }; // Return for watch mode or auto-restart
631
633
  } else if (allComments.length > 0) {
632
634
  await log(` ℹ️ Issue has ${allComments.length} existing comment(s)`);
633
635
  } else {
@@ -645,7 +647,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
645
647
  if (!argv.watch) {
646
648
  await safeExit(0, 'Process completed successfully');
647
649
  }
648
- return; // Return normally for watch mode
650
+ // Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
651
+ return { logUploadSuccess: false }; // Return for watch mode
649
652
  } catch (searchError) {
650
653
  reportError(searchError, {
651
654
  context: 'verify_pr_creation',
@@ -661,7 +664,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
661
664
  if (!argv.watch) {
662
665
  await safeExit(0, 'Process completed successfully');
663
666
  }
664
- return; // Return normally for watch mode
667
+ // Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
668
+ return { logUploadSuccess: false }; // Return for watch mode
665
669
  }
666
670
  };
667
671
 
@@ -41,9 +41,9 @@ export const QUEUE_CONFIG = {
41
41
 
42
42
  // API limit thresholds (usage ratios: 0.0 - 1.0)
43
43
  // All thresholds use >= comparison (inclusive)
44
- CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.85, // One-at-a-time if 5-hour limit >= 85%
45
- CLAUDE_WEEKLY_THRESHOLD: 0.98, // One-at-a-time if weekly limit >= 98%
46
- GITHUB_API_THRESHOLD: 0.8, // Enqueue if GitHub >= 80% with parallel claude
44
+ CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.75, // One-at-a-time if 5-hour limit >= 75%
45
+ CLAUDE_WEEKLY_THRESHOLD: 0.97, // One-at-a-time if weekly limit >= 97%
46
+ GITHUB_API_THRESHOLD: 0.75, // Enqueue if GitHub >= 75% with parallel claude
47
47
 
48
48
  // Timing
49
49
  // MIN_START_INTERVAL_MS: Time to allow solve command to start actual claude process