@link-assistant/hive-mind 2.10.2 → 2.10.3

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,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 2.10.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 3cfd6c2: Show cost and token/context budget facts in automated working-session summaries.
8
+
3
9
  ## 2.10.2
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "2.10.2",
3
+ "version": "2.10.3",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -1068,6 +1068,10 @@ No further AI sessions will be started automatically for this run. Please review
1068
1068
  prNumber,
1069
1069
  issueNumber,
1070
1070
  success: true,
1071
+ publicPricingEstimate: toolResult.publicPricingEstimate,
1072
+ anthropicTotalCostUSD: latestAnthropicCost,
1073
+ pricingInfo: toolResult.pricingInfo,
1074
+ budgetStatsData: autoMergeBudgetStatsData,
1071
1075
  });
1072
1076
  } catch (summaryError) {
1073
1077
  reportError(summaryError, {
package/src/solve.mjs CHANGED
@@ -1228,13 +1228,8 @@ try {
1228
1228
 
1229
1229
  // Issue #2048: commit+push dev log BEFORE any PR readiness signal so its CI gates readiness (was last, breaking CI post-signal; PR #2046, docs/case-studies/issue-2048). Idempotent: trailing call is a no-op. prettier-ignore
1230
1230
  await finalizeDevelopmentLog();
1231
- // Issue #1263 / #1728: Working session summary attachment.
1232
- // Routed through the shared maybeAttachWorkingSessionSummary helper so that
1233
- // top-level solve, auto-restart-until-mergeable, and watch-mode iterations
1234
- // all use identical attach logic. The helper internally honours
1235
- // --attach-solution-summary (always attach) and --auto-attach-solution-summary
1236
- // (attach only if no AI comment was posted during the session).
1237
- await maybeAttachWorkingSessionSummary({
1231
+ // Issue #1263 / #1728 / #2115: shared summary attachment and usage display.
1232
+ const { budgetStatsData: workingSessionBudgetStatsData = null } = await maybeAttachWorkingSessionSummary({
1238
1233
  argv,
1239
1234
  resultSummary,
1240
1235
  workStartTime,
@@ -1243,10 +1238,14 @@ try {
1243
1238
  prNumber,
1244
1239
  issueNumber,
1245
1240
  success,
1241
+ publicPricingEstimate,
1242
+ anthropicTotalCostUSD,
1243
+ pricingInfo,
1244
+ sessionUsage: { sessionId, tempDir, resultModelUsage, streamTokenUsage, subAgentCalls },
1246
1245
  });
1247
1246
 
1248
1247
  // Search for newly created pull requests and comments
1249
- const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution, sessionType, resultModelUsage, streamTokenUsage, subAgentCalls);
1248
+ const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution, sessionType, resultModelUsage, streamTokenUsage, subAgentCalls, workingSessionBudgetStatsData);
1250
1249
  const logsAlreadyUploaded = verifyResult?.logUploadSuccess || false;
1251
1250
 
1252
1251
  // Issue #1162: Auto-restart when PR title/description still has placeholder content
@@ -28,6 +28,8 @@ import { safeExit } from './exit-handler.lib.mjs';
28
28
  // Import GitHub-related functions
29
29
  const githubLib = await import('./github.lib.mjs');
30
30
  const { sanitizeLogContent, attachLogToGitHub } = githubLib;
31
+ const { buildCostInfoString } = await import('./github-cost-info.lib.mjs');
32
+ const { buildBudgetStatsString } = await import('./claude.budget-stats.lib.mjs');
31
33
 
32
34
  // Issue #1745: process-wide sanitization counters used to print a one-line
33
35
  // "we masked N secrets" summary at the end of each run.
@@ -663,11 +665,9 @@ export const showSessionSummary = async (sessionId, limitReached, argv, issueUrl
663
665
  }
664
666
  };
665
667
 
666
- // Verify results by searching for new PRs and comments
667
- export const verifyResults = async (owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart = false, sessionId = null, tempDir = null, anthropicTotalCostUSD = null, publicPricingEstimate = null, pricingInfo = null, errorDuringExecution = false, sessionType = 'new', resultModelUsage = null, streamTokenUsage = null, subAgentCalls = null) => {
668
- await log('\nšŸ” Searching for created pull requests or comments...');
669
-
670
- // Issue #1491, #1526: Build budget stats data for GitHub comment (computed once, used in both PR and issue paths)
668
+ // Build token/context data once so every end-of-session publication can use the
669
+ // same observed facts (working-session summary and attached log alike).
670
+ export const buildSessionBudgetStatsData = async ({ argv, sessionId = null, tempDir = null, resultModelUsage = null, streamTokenUsage = null, subAgentCalls = null, pricingInfo = null }) => {
671
671
  let budgetStatsData = null;
672
672
  if (argv.tokensBudgetStats && sessionId && tempDir) {
673
673
  try {
@@ -692,6 +692,26 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
692
692
  if (argv.verbose) await log(` āš ļø Could not build agent budget stats: ${agentBudgetError.message}`, { verbose: true });
693
693
  }
694
694
  }
695
+ return budgetStatsData;
696
+ };
697
+
698
+ // Verify results by searching for new PRs and comments
699
+ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart = false, sessionId = null, tempDir = null, anthropicTotalCostUSD = null, publicPricingEstimate = null, pricingInfo = null, errorDuringExecution = false, sessionType = 'new', resultModelUsage = null, streamTokenUsage = null, subAgentCalls = null, precomputedBudgetStatsData = null) => {
700
+ await log('\nšŸ” Searching for created pull requests or comments...');
701
+
702
+ // Issue #1491, #1526, #2115: reuse data already calculated for the working
703
+ // session summary; retain the fallback for callers that do not precompute it.
704
+ const budgetStatsData =
705
+ precomputedBudgetStatsData ??
706
+ (await buildSessionBudgetStatsData({
707
+ argv,
708
+ sessionId,
709
+ tempDir,
710
+ resultModelUsage,
711
+ streamTokenUsage,
712
+ subAgentCalls,
713
+ pricingInfo,
714
+ }));
695
715
 
696
716
  try {
697
717
  // Get the current user's GitHub username
@@ -1241,7 +1261,15 @@ export const checkForAiCreatedComments = async (sessionStartTime, owner, repo, p
1241
1261
  * @param {string} options.repo - Repository name
1242
1262
  * @returns {Promise<boolean>} - True if comment was posted successfully
1243
1263
  */
1244
- export const attachSolutionSummary = async ({ resultSummary, prNumber, issueNumber, owner, repo }) => {
1264
+ export const buildWorkingSessionSummaryDetails = ({ publicPricingEstimate = null, anthropicTotalCostUSD = null, pricingInfo = null, budgetStatsData = null } = {}) => {
1265
+ const costInfo = buildCostInfoString(publicPricingEstimate, anthropicTotalCostUSD, pricingInfo, {
1266
+ includeTokenUsage: false,
1267
+ });
1268
+ const budgetStats = budgetStatsData ? buildBudgetStatsString(budgetStatsData.tokenUsage, budgetStatsData.subAgentCalls) : '';
1269
+ return `${costInfo}${budgetStats}`.trim();
1270
+ };
1271
+
1272
+ export const attachSolutionSummary = async ({ resultSummary, prNumber, issueNumber, owner, repo, publicPricingEstimate = null, anthropicTotalCostUSD = null, pricingInfo = null, budgetStatsData = null }) => {
1245
1273
  if (!resultSummary || typeof resultSummary !== 'string') {
1246
1274
  await log('āš ļø No working session summary available to attach', { verbose: true });
1247
1275
  return false;
@@ -1256,10 +1284,16 @@ export const attachSolutionSummary = async ({ resultSummary, prNumber, issueNumb
1256
1284
  }
1257
1285
 
1258
1286
  try {
1287
+ const usageDetails = buildWorkingSessionSummaryDetails({
1288
+ publicPricingEstimate,
1289
+ anthropicTotalCostUSD,
1290
+ pricingInfo,
1291
+ budgetStatsData,
1292
+ });
1259
1293
  const comment = `${toolComments.WORKING_SESSION_SUMMARY_AUTOMATION_MARKER}
1260
1294
  ## ${toolComments.WORKING_SESSION_SUMMARY_MARKER}
1261
1295
 
1262
- ${resultSummary}
1296
+ ${resultSummary}${usageDetails ? `\n\n${usageDetails}` : ''}
1263
1297
 
1264
1298
  ---
1265
1299
  *${toolComments.WORKING_SESSION_SUMMARY_AUTOMATED_FOOTER}*`;
@@ -1316,7 +1350,7 @@ ${resultSummary}
1316
1350
  * @param {boolean} [options.success=true] - skip attachment for failed iterations
1317
1351
  * @returns {Promise<{attached: boolean, reason: string}>}
1318
1352
  */
1319
- export const maybeAttachWorkingSessionSummary = async ({ argv, resultSummary, workStartTime, owner, repo, prNumber, issueNumber, success = true }) => {
1353
+ export const maybeAttachWorkingSessionSummary = async ({ argv, resultSummary, workStartTime, owner, repo, prNumber, issueNumber, success = true, publicPricingEstimate = null, anthropicTotalCostUSD = null, pricingInfo = null, budgetStatsData = null, sessionUsage = null }) => {
1320
1354
  if (!success) {
1321
1355
  return { attached: false, reason: 'iteration_failed' };
1322
1356
  }
@@ -1352,6 +1386,25 @@ export const maybeAttachWorkingSessionSummary = async ({ argv, resultSummary, wo
1352
1386
  return { attached: false, reason: 'no_attach_decision' };
1353
1387
  }
1354
1388
 
1355
- const ok = await attachSolutionSummary({ resultSummary, prNumber, issueNumber, owner, repo });
1356
- return { attached: !!ok, reason: ok ? 'attached' : 'post_failed' };
1389
+ const resolvedBudgetStatsData =
1390
+ budgetStatsData ??
1391
+ (sessionUsage
1392
+ ? await buildSessionBudgetStatsData({
1393
+ argv,
1394
+ pricingInfo,
1395
+ ...sessionUsage,
1396
+ })
1397
+ : null);
1398
+ const ok = await attachSolutionSummary({
1399
+ resultSummary,
1400
+ prNumber,
1401
+ issueNumber,
1402
+ owner,
1403
+ repo,
1404
+ publicPricingEstimate,
1405
+ anthropicTotalCostUSD,
1406
+ pricingInfo,
1407
+ budgetStatsData: resolvedBudgetStatsData,
1408
+ });
1409
+ return { attached: !!ok, reason: ok ? 'attached' : 'post_failed', budgetStatsData: resolvedBudgetStatsData };
1357
1410
  };
@@ -580,6 +580,10 @@ export const watchForFeedback = async params => {
580
580
  prNumber,
581
581
  issueNumber,
582
582
  success: true,
583
+ publicPricingEstimate: toolResult.publicPricingEstimate,
584
+ anthropicTotalCostUSD: latestAnthropicCost,
585
+ pricingInfo: toolResult.pricingInfo,
586
+ budgetStatsData: autoRestartBudgetStatsData,
583
587
  });
584
588
  } catch (summaryError) {
585
589
  reportError(summaryError, {