@link-assistant/hive-mind 1.0.0 → 1.0.2

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,36 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 1a96d9f: Fix Claude Usage API rate limiting by increasing cache TTL to 20 minutes
8
+ - The Claude Usage API (`/api/oauth/usage`) was returning null values due to rate limiting when called too frequently
9
+ - Increased default cache TTL from 3 minutes to 20 minutes for Claude Usage API
10
+ - Added configurable environment variable `HIVE_MIND_USAGE_API_CACHE_TTL_MS` (default: 1200000ms = 20 minutes)
11
+ - Added HTTP response status logging for easier debugging
12
+ - Added explicit 429 rate limit error handling
13
+ - Updated documentation in `docs/CONFIGURATION.md`
14
+
15
+ See: https://github.com/link-assistant/hive-mind/issues/1074
16
+
17
+ ## 1.0.1
18
+
19
+ ### Patch Changes
20
+
21
+ - 2a3848d: Add --prompt-architecture-care flag for managing REQUIREMENTS.md and ARCHITECTURE.md files
22
+
23
+ Adds an optional experimental flag `--prompt-architecture-care` that provides guidance for:
24
+ - Managing REQUIREMENTS.md (high-level why/what documentation)
25
+ - Managing ARCHITECTURE.md (high-level how documentation)
26
+ - TODO.md workflow management for task persistence across sessions
27
+
28
+ The flag is disabled by default and works with all tools (claude, agent, opencode, codex).
29
+
30
+ - a18a664: Fix session ID extraction error for --tool agent
31
+ - Fixed JSON parsing logic in agent tool to extract session IDs from NDJSON output
32
+ - Modified session summary to show informational message for agent tool instead of error
33
+
3
34
  ## 1.0.0
4
35
 
5
36
  ### Major Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
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
@@ -405,7 +405,26 @@ export const executeAgentCommand = async params => {
405
405
  for await (const chunk of execCommand.stream()) {
406
406
  if (chunk.type === 'stdout') {
407
407
  const output = chunk.data.toString();
408
- await log(output);
408
+ // Split output into individual lines for NDJSON parsing
409
+ // Agent outputs NDJSON (newline-delimited JSON) format where each line is a separate JSON object
410
+ // This allows us to parse each event independently and extract structured data like session IDs
411
+ const lines = output.split('\n');
412
+ for (const line of lines) {
413
+ if (!line.trim()) continue;
414
+ try {
415
+ const data = JSON.parse(line);
416
+ // Output formatted JSON
417
+ await log(JSON.stringify(data, null, 2));
418
+ // Capture session ID from the first message
419
+ if (!sessionId && data.sessionID) {
420
+ sessionId = data.sessionID;
421
+ await log(`📌 Session ID: ${sessionId}`);
422
+ }
423
+ } catch {
424
+ // Not JSON - log as plain text
425
+ await log(line);
426
+ }
427
+ }
409
428
  lastMessage = output;
410
429
  fullOutput += output; // Collect for both pricing calculation and error detection
411
430
  }
@@ -3,6 +3,8 @@
3
3
  * Handles building prompts for Agent commands
4
4
  */
5
5
 
6
+ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
+
6
8
  /**
7
9
  * Build the user prompt for Agent
8
10
  * @param {Object} params - Parameters for building the user prompt
@@ -183,7 +185,7 @@ GitHub CLI command patterns.
183
185
  - When adding PR comment, use gh pr comment NUMBER --body "text" --repo OWNER/REPO.
184
186
  - When adding issue comment, use gh issue comment NUMBER --body "text" --repo OWNER/REPO.
185
187
  - When viewing PR details, use gh pr view NUMBER --repo OWNER/REPO.
186
- - When filtering with jq, use gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.`;
188
+ - When filtering with jq, use gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.${getArchitectureCareSubPrompt(argv)}`;
187
189
  };
188
190
 
189
191
  // Export all functions as default object too
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Architecture care sub-prompt module
3
+ * Provides guidance for managing REQUIREMENTS.md, ARCHITECTURE.md, and TODO.md files
4
+ *
5
+ * This is an experimental feature enabled via --prompt-architecture-care flag
6
+ */
7
+
8
+ /**
9
+ * Build the architecture care sub-prompt content
10
+ * @returns {string} The formatted sub-prompt for architecture documentation care
11
+ */
12
+ export const buildArchitectureCareSubPrompt = () => {
13
+ return `
14
+ Architecture and Requirements Documentation Care.
15
+ - REQUIREMENTS.md is a file that gives high level description on why/what it is for and so on relative to the entire repository.
16
+ - ARCHITECTURE.md is a file that gives high level description on how it was implemented so far.
17
+ - When any issue or comment changes how we see REQUIREMENTS.md or ARCHITECTURE.md, these files should be updated accordingly.
18
+ - When REQUIREMENTS.md or ARCHITECTURE.md files get too large, consider creating additional README.md, REQUIREMENTS.md, and ARCHITECTURE.md files in separate folders.
19
+ - When creating nested documentation files, make sure the root files have references to inner level documentation.
20
+ - When working with documentation, each README.md, REQUIREMENTS.md, and ARCHITECTURE.md scope should be related to the entire folder where such file exists.
21
+ - When you make changes that affect the high-level purpose, goals, or requirements of the project, update REQUIREMENTS.md.
22
+ - When you make changes that affect the implementation, architecture, or design patterns of the project, update ARCHITECTURE.md.
23
+ - When reviewing your changes before committing, check if REQUIREMENTS.md or ARCHITECTURE.md need updates based on the scope of your changes.
24
+
25
+ TODO.md Workflow Management.
26
+ - At the start of each working session, check if TODO.md exists in the repository root.
27
+ - When TODO.md exists, read it first and continue finishing all items listed in it before starting any new work.
28
+ - When all items in TODO.md are completed, delete the TODO.md file to indicate work is done.
29
+ - When you cannot finish all tasks in the current working session, create or update TODO.md with all remaining tasks that need to be completed.
30
+ - When creating TODO.md, use a clear markdown checklist format with each item as a separate line.
31
+ - When updating TODO.md during a session, remove completed items and add any newly discovered tasks that couldn't be finished.
32
+ - TODO.md serves as a persistent task list across working sessions, ensuring continuity and nothing is forgotten between sessions.
33
+ - When starting work on a repository, the priority is: (1) Check TODO.md, (2) Complete TODO.md items, (3) Work on current issue/task, (4) Update TODO.md if needed before ending session.`;
34
+ };
35
+
36
+ /**
37
+ * Get the architecture care sub-prompt if enabled
38
+ * @param {Object} argv - Command line arguments
39
+ * @returns {string} The sub-prompt content or empty string if disabled
40
+ */
41
+ export const getArchitectureCareSubPrompt = argv => {
42
+ if (argv && argv.promptArchitectureCare) {
43
+ return buildArchitectureCareSubPrompt();
44
+ }
45
+ return '';
46
+ };
47
+
48
+ // Export all functions as default object too
49
+ export default {
50
+ buildArchitectureCareSubPrompt,
51
+ getArchitectureCareSubPrompt,
52
+ };
@@ -3,6 +3,8 @@
3
3
  * Handles building prompts for Claude commands
4
4
  */
5
5
 
6
+ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
+
6
8
  /**
7
9
  * Build the user prompt for Claude
8
10
  * @param {Object} params - Parameters for building the user prompt
@@ -241,7 +243,7 @@ Plan sub-agent usage.
241
243
  - When using the Plan sub-agent, you can add it as the first item in your todo list.
242
244
  - When you delegate planning, use the Task tool with subagent_type="Plan" before starting implementation work.`
243
245
  : ''
244
- }`;
246
+ }${getArchitectureCareSubPrompt(argv)}`;
245
247
  };
246
248
 
247
249
  // Export all functions as default object too
@@ -3,6 +3,8 @@
3
3
  * Handles building prompts for Codex CLI commands
4
4
  */
5
5
 
6
+ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
+
6
8
  /**
7
9
  * Build the user prompt for Codex
8
10
  * @param {Object} params - Parameters for building the user prompt
@@ -191,7 +193,7 @@ GitHub CLI command patterns.
191
193
  - When adding PR comment, use gh pr comment NUMBER --body "text" --repo OWNER/REPO.
192
194
  - When adding issue comment, use gh issue comment NUMBER --body "text" --repo OWNER/REPO.
193
195
  - When viewing PR details, use gh pr view NUMBER --repo OWNER/REPO.
194
- - When filtering with jq, use gh api repos/\${owner}/\${repo}/pulls/\${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.`;
196
+ - When filtering with jq, use gh api repos/\${owner}/\${repo}/pulls/\${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.${getArchitectureCareSubPrompt(argv)}`;
195
197
  };
196
198
 
197
199
  // Export all functions as default object too
@@ -78,6 +78,19 @@ export const retryLimits = {
78
78
  initial503RetryDelayMs: parseIntWithDefault('HIVE_MIND_INITIAL_503_RETRY_DELAY_MS', 5 * 60 * 1000), // 5 minutes
79
79
  };
80
80
 
81
+ // Cache TTL configurations (in milliseconds)
82
+ // The Usage API (Claude limits) has stricter rate limiting than regular APIs
83
+ // See: https://github.com/link-assistant/hive-mind/issues/1074
84
+ export const cacheTtl = {
85
+ // General API cache TTL (GitHub API, etc.)
86
+ api: parseIntWithDefault('HIVE_MIND_API_CACHE_TTL_MS', 3 * 60 * 1000), // 3 minutes
87
+ // Claude Usage API cache TTL - must be at least 20 minutes to avoid rate limiting
88
+ // The API returns null values when called too frequently
89
+ usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS', 20 * 60 * 1000), // 20 minutes
90
+ // System metrics cache TTL (RAM, CPU, disk)
91
+ system: parseIntWithDefault('HIVE_MIND_SYSTEM_CACHE_TTL_MS', 2 * 60 * 1000), // 2 minutes
92
+ };
93
+
81
94
  // File and path configurations
82
95
  export const filePaths = {
83
96
  tempDir: getenv('HIVE_MIND_TEMP_DIR', '/tmp'),
@@ -177,6 +190,7 @@ export function getAllConfigurations() {
177
190
  githubLimits,
178
191
  systemLimits,
179
192
  retryLimits,
193
+ cacheTtl,
180
194
  filePaths,
181
195
  textProcessing,
182
196
  display,
@@ -281,6 +281,11 @@ export const createYargsConfig = yargsInstance => {
281
281
  description: 'Include prompt to check related/sibling pull requests when studying related work. Enabled by default, use --no-prompt-check-sibling-pull-requests to disable.',
282
282
  default: true,
283
283
  })
284
+ .option('prompt-architecture-care', {
285
+ type: 'boolean',
286
+ description: '[EXPERIMENTAL] Include guidance for managing REQUIREMENTS.md and ARCHITECTURE.md files. When enabled, agents will update these documentation files when changes affect requirements or architecture.',
287
+ default: false,
288
+ })
284
289
  .parserConfiguration({
285
290
  'boolean-negation': true,
286
291
  'strip-dashed': false,
@@ -10,6 +10,9 @@ import { homedir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
  import { promisify } from 'node:util';
12
12
 
13
+ // Import cache TTL configuration
14
+ import { cacheTtl } from './config.lib.mjs';
15
+
13
16
  const execAsync = promisify(exec);
14
17
 
15
18
  /**
@@ -532,6 +535,11 @@ export async function getClaudeUsageLimits(verbose = false, credentialsPath = DE
532
535
  },
533
536
  });
534
537
 
538
+ // Log HTTP response status for debugging (always, not just on error)
539
+ if (verbose) {
540
+ console.log(`[VERBOSE] /limits API HTTP status: ${response.status} ${response.statusText}`);
541
+ }
542
+
535
543
  if (!response.ok) {
536
544
  const errorText = await response.text();
537
545
  if (verbose) {
@@ -546,6 +554,15 @@ export async function getClaudeUsageLimits(verbose = false, credentialsPath = DE
546
554
  };
547
555
  }
548
556
 
557
+ // Check for rate limiting (429 Too Many Requests)
558
+ if (response.status === 429) {
559
+ const retryAfter = response.headers.get('retry-after');
560
+ return {
561
+ success: false,
562
+ error: `Rate limited by Claude Usage API. ${retryAfter ? `Retry after: ${retryAfter}s` : 'Try again later.'}`,
563
+ };
564
+ }
565
+
549
566
  return {
550
567
  success: false,
551
568
  error: `Failed to fetch usage from API: ${response.status} ${response.statusText}`,
@@ -786,10 +803,21 @@ export function formatUsageMessage(usage, diskSpace = null, githubRateLimit = nu
786
803
 
787
804
  /**
788
805
  * Cache TTL constants (in milliseconds)
806
+ * Values are loaded from config.lib.mjs which supports environment variable overrides.
807
+ *
808
+ * IMPORTANT: The Claude Usage API has stricter rate limiting than regular APIs.
809
+ * Calling it more frequently than every 20 minutes may result in null values being returned.
810
+ * See: https://github.com/link-assistant/hive-mind/issues/1074
811
+ *
812
+ * Configurable via environment variables:
813
+ * - HIVE_MIND_API_CACHE_TTL_MS: General API cache TTL (default: 180000 = 3 minutes)
814
+ * - HIVE_MIND_USAGE_API_CACHE_TTL_MS: Claude Usage API cache TTL (default: 1200000 = 20 minutes)
815
+ * - HIVE_MIND_SYSTEM_CACHE_TTL_MS: System metrics cache TTL (default: 120000 = 2 minutes)
789
816
  */
790
817
  export const CACHE_TTL = {
791
- API: 180000, // 3 minutes for API calls (Claude, GitHub)
792
- SYSTEM: 120000, // 2 minutes for system metrics (RAM, CPU, disk)
818
+ API: cacheTtl.api, // 3 minutes for regular API calls (GitHub)
819
+ USAGE_API: cacheTtl.usageApi, // 20 minutes for Claude Usage API (rate limited)
820
+ SYSTEM: cacheTtl.system, // 2 minutes for system metrics (RAM, CPU, disk)
793
821
  };
794
822
 
795
823
  /**
@@ -852,13 +880,17 @@ export function resetLimitCache() {
852
880
 
853
881
  export async function getCachedClaudeLimits(verbose = false) {
854
882
  const cache = getLimitCache();
855
- const cached = cache.get('claude', CACHE_TTL.API);
883
+ // Use USAGE_API TTL (20 minutes) for Claude limits to avoid rate limiting
884
+ // The Claude Usage API returns null values when called too frequently
885
+ // See: https://github.com/link-assistant/hive-mind/issues/1074
886
+ const cached = cache.get('claude', CACHE_TTL.USAGE_API);
856
887
  if (cached) {
857
- if (verbose) console.log('[VERBOSE] /limits-cache: Using cached Claude limits');
888
+ if (verbose) console.log('[VERBOSE] /limits-cache: Using cached Claude limits (TTL: ' + Math.round(CACHE_TTL.USAGE_API / 60000) + ' minutes)');
858
889
  return cached;
859
890
  }
891
+ if (verbose) console.log('[VERBOSE] /limits-cache: Cache miss for Claude limits, fetching from API...');
860
892
  const result = await getClaudeUsageLimits(verbose);
861
- if (result.success) cache.set('claude', result, CACHE_TTL.API);
893
+ if (result.success) cache.set('claude', result, CACHE_TTL.USAGE_API);
862
894
  return result;
863
895
  }
864
896
 
@@ -3,6 +3,8 @@
3
3
  * Handles building prompts for OpenCode commands
4
4
  */
5
5
 
6
+ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
+
6
8
  /**
7
9
  * Build the user prompt for OpenCode
8
10
  * @param {Object} params - Parameters for building the user prompt
@@ -182,7 +184,7 @@ GitHub CLI command patterns.
182
184
  - When adding PR comment, use gh pr comment NUMBER --body "text" --repo OWNER/REPO.
183
185
  - When adding issue comment, use gh issue comment NUMBER --body "text" --repo OWNER/REPO.
184
186
  - When viewing PR details, use gh pr view NUMBER --repo OWNER/REPO.
185
- - When filtering with jq, use gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.`;
187
+ - When filtering with jq, use gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.${getArchitectureCareSubPrompt(argv)}`;
186
188
  };
187
189
 
188
190
  // Export all functions as default object too
@@ -278,6 +278,11 @@ export const createYargsConfig = yargsInstance => {
278
278
  description: 'Enable automatic issue creation for spotted bugs/errors not related to main task. Issues will include reproducible examples, workarounds, and fix suggestions. Works for both current and third-party repositories. Only supported for --tool claude.',
279
279
  default: false,
280
280
  })
281
+ .option('prompt-architecture-care', {
282
+ type: 'boolean',
283
+ description: '[EXPERIMENTAL] Include guidance for managing REQUIREMENTS.md and ARCHITECTURE.md files. When enabled, agents will update these documentation files when changes affect requirements or architecture.',
284
+ default: false,
285
+ })
281
286
  .option('prompt-case-studies', {
282
287
  type: 'boolean',
283
288
  description: 'Create comprehensive case study documentation for the issue including logs, analysis, timeline, root cause investigation, and proposed solutions. Organizes findings into ./docs/case-studies/issue-{id}/ directory. Only supported for --tool claude.',
@@ -354,7 +354,6 @@ export const showSessionSummary = async (sessionId, limitReached, argv, issueUrl
354
354
  if (sessionId) {
355
355
  await log(`✅ Session ID: ${sessionId}`);
356
356
  // Always use absolute path for log file display
357
- const path = await use('path');
358
357
  const absoluteLogPath = path.resolve(getLogFile());
359
358
  await log(`✅ Complete log file: ${absoluteLogPath}`);
360
359
 
@@ -402,7 +401,12 @@ export const showSessionSummary = async (sessionId, limitReached, argv, issueUrl
402
401
 
403
402
  // Don't show log preview, it's too technical
404
403
  } else {
405
- await log('❌ No session ID extracted');
404
+ // For agent tool, session IDs may not be meaningful for resuming, so don't show as error
405
+ if (argv.tool !== 'agent') {
406
+ await log('❌ No session ID extracted');
407
+ } else {
408
+ await log('â„šī¸ Agent tool completed (session IDs not used for resuming)');
409
+ }
406
410
  // Always use absolute path for log file display
407
411
  const logFilePath = path.resolve(getLogFile());
408
412
  await log(`📁 Log file available: ${logFilePath}`);