@link-assistant/hive-mind 1.35.9 → 1.35.11

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.
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
7
  import { getExperimentsExamplesSubPrompt } from './experiments-examples.prompts.lib.mjs';
8
+ import { primaryModelNames } from './models/index.mjs';
8
9
 
9
10
  /**
10
11
  * Build the user prompt for Claude
@@ -309,7 +310,7 @@ Agent Commander usage (unified subagent delegation).
309
310
  --tool <name>: Agent to use (claude, opencode, codex, agent)
310
311
  --working-directory <path>: Execution directory (use current directory for context)
311
312
  --prompt <text>: The task to delegate
312
- --model <name>: Model to use (sonnet, opus, haiku, grok, etc.)
313
+ --model <name>: Model to use (${[...new Set(Object.values(primaryModelNames).flat())].slice(0, 5).join(', ')}, etc.)
313
314
  --isolation <mode>: Execution context (none, screen, docker)
314
315
  --detached: Run in background mode
315
316
  - Examples:
@@ -54,6 +54,17 @@ export const timeouts = {
54
54
  // Issue #1280: Timeout (ms) to wait for stream close after result event before force-killing
55
55
  // command-stream's stream() waits for process exit + pipe close; if stdout stays open, it hangs
56
56
  resultStreamCloseMs: parseIntWithDefault('HIVE_MIND_RESULT_STREAM_CLOSE_MS', 30000),
57
+ // Issue #1472/#1475: Timeout (ms) to wait for first stream output from Claude CLI after startup.
58
+ // If no stdout/stderr output is received within this period, the process is considered stuck
59
+ // and will be force-killed. Both affected sessions showed ~4.5h with zero output from Claude CLI.
60
+ // Default: 120000ms (2 minutes) — Claude CLI normally emits system.init within 1-3 seconds.
61
+ streamStartupMs: parseIntWithDefault('HIVE_MIND_STREAM_STARTUP_MS', 120000),
62
+ // Issue #1472: Activity timeout (ms) — if no new stream output is received for this duration
63
+ // after at least one event was received, the process is considered hung mid-session.
64
+ // This catches the case where Claude CLI starts producing output but then stops (e.g., the
65
+ // original Issue #1472 where CLI was stuck for 4.5h with all output arriving only at CTRL+C).
66
+ // Default: 300000ms (5 minutes). Set to 0 to disable. Configurable via environment variable.
67
+ streamActivityMs: parseIntWithDefault('HIVE_MIND_STREAM_ACTIVITY_MS', 300000),
57
68
  };
58
69
 
59
70
  // Auto-continue configurations
@@ -11,7 +11,7 @@ export { isSafeToken, isHexInSafeContext, getGitHubTokensFromFiles, getGitHubTok
11
11
  import { uploadLogWithGhUploadLog } from './log-upload.lib.mjs';
12
12
  import { formatResetTimeWithRelative } from './usage-limit.lib.mjs'; // See: https://github.com/link-assistant/hive-mind/issues/1236
13
13
  // Import model info helpers (Issue #1225)
14
- import { getToolDisplayName, getModelInfoForComment } from './model-info.lib.mjs';
14
+ import { getToolDisplayName, getModelInfoForComment } from './models/index.mjs';
15
15
  // Re-export for use by other modules
16
16
  export { getToolDisplayName };
17
17
 
@@ -4,6 +4,7 @@
4
4
  // This module has no heavy dependencies to allow fast loading for --help
5
5
 
6
6
  import { SOLVE_OPTION_DEFINITIONS } from './solve.config.lib.mjs';
7
+ import { buildModelOptionDescription } from './models/index.mjs';
7
8
 
8
9
  // Hive-only options that are NOT solve options (hive-specific functionality).
9
10
  // These are excluded when auto-registering solve-passthrough options.
@@ -19,7 +20,7 @@ const SOLVE_ONLY_OPTION_NAMES = new Set(['resume', 'working-directory', 'only-pr
19
20
  const HIVE_CUSTOM_SOLVE_OPTIONS = {
20
21
  model: {
21
22
  type: 'string',
22
- description: 'Model to use for solve (opus, sonnet, haiku, haiku-3-5, haiku-3, or any model ID supported by the tool)',
23
+ description: `${buildModelOptionDescription()}, or any model ID supported by the tool`,
23
24
  alias: 'm',
24
25
  default: 'sonnet',
25
26
  },
package/src/hive.mjs CHANGED
@@ -101,7 +101,7 @@ if (isDirectExecution) {
101
101
  const claudeLib = await import('./claude.lib.mjs');
102
102
  const { validateClaudeConnection } = claudeLib;
103
103
  // Import model validation library
104
- const modelValidation = await import('./model-validation.lib.mjs');
104
+ const modelValidation = await import('./models/index.mjs');
105
105
  const { validateAndExitOnInvalidModel } = modelValidation;
106
106
  const githubLib = await import('./github.lib.mjs');
107
107
  const { checkGitHubPermissions, fetchAllIssuesWithPagination, fetchProjectIssues, isRateLimitError, batchCheckPullRequestsForIssues, parseGitHubUrl, batchCheckArchivedRepositories } = githubLib;
@@ -270,6 +270,14 @@ export const createInteractiveHandler = options => {
270
270
  // Track active agent tasks for progress update deduplication
271
271
  // Map of task_id -> { commentId, toolUseId, description, commentIdPromise, resolveCommentId }
272
272
  pendingTasks: new Map(),
273
+ // Issue #1472: Diagnostic counters for tracking comment posting success/failure
274
+ eventsProcessed: 0,
275
+ commentsAttempted: 0,
276
+ commentsPosted: 0,
277
+ commentsFailed: 0,
278
+ editsAttempted: 0,
279
+ editsSucceeded: 0,
280
+ editsFailed: 0,
273
281
  };
274
282
 
275
283
  /**
@@ -299,6 +307,7 @@ export const createInteractiveHandler = options => {
299
307
  return null;
300
308
  }
301
309
 
310
+ state.commentsAttempted++;
302
311
  try {
303
312
  // Post comment via gh api with stdin to avoid shell quoting issues
304
313
  // with complex markdown bodies containing backticks, quotes, etc.
@@ -310,6 +319,7 @@ export const createInteractiveHandler = options => {
310
319
  maxBuffer: 10 * 1024 * 1024, // 10MB
311
320
  });
312
321
  state.lastCommentTime = Date.now();
322
+ state.commentsPosted++;
313
323
 
314
324
  // Extract comment ID from the API response JSON
315
325
  let commentId = null;
@@ -327,9 +337,9 @@ export const createInteractiveHandler = options => {
327
337
  }
328
338
  return commentId;
329
339
  } catch (error) {
330
- if (verbose) {
331
- await log(`⚠️ Interactive mode: Failed to post comment: ${error.message} (body: ${body.length} chars)`, { verbose: true });
332
- }
340
+ state.commentsFailed++;
341
+ // Issue #1472: Always log comment failures (not just verbose) silent failures cause zero-comment bugs
342
+ await log(`⚠️ Interactive mode: Failed to post comment: ${error.message} (body: ${body.length} chars)`);
333
343
  return null;
334
344
  }
335
345
  };
@@ -349,6 +359,7 @@ export const createInteractiveHandler = options => {
349
359
  return false;
350
360
  }
351
361
 
362
+ state.editsAttempted++;
352
363
  try {
353
364
  // Edit comment via gh api with stdin to avoid shell quoting issues
354
365
  // with complex markdown bodies containing backticks, quotes, etc.
@@ -359,14 +370,14 @@ export const createInteractiveHandler = options => {
359
370
  input: jsonPayload,
360
371
  maxBuffer: 10 * 1024 * 1024, // 10MB
361
372
  });
373
+ state.editsSucceeded++;
362
374
  if (verbose) {
363
375
  await log(`✅ Interactive mode: Comment ${commentId} updated (body: ${body.length} chars, payload: ${jsonPayload.length} chars)`, { verbose: true });
364
376
  }
365
377
  return true;
366
378
  } catch (error) {
367
- if (verbose) {
368
- await log(`⚠️ Interactive mode: Failed to edit comment ${commentId}: ${error.message} (body: ${body.length} chars)`, { verbose: true });
369
- }
379
+ state.editsFailed++;
380
+ await log(`⚠️ Interactive mode: Failed to edit comment ${commentId}: ${error.message} (body: ${body.length} chars)`);
370
381
  return false;
371
382
  }
372
383
  };
@@ -1135,6 +1146,7 @@ ${createRawJsonSection(data)}`;
1135
1146
  if (!data || typeof data !== 'object') {
1136
1147
  return;
1137
1148
  }
1149
+ state.eventsProcessed++;
1138
1150
 
1139
1151
  // Handle events without type as unrecognized
1140
1152
  if (!data.type) {