hungry-ghost-hive 0.41.0 → 0.42.0

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.
Files changed (35) hide show
  1. package/dist/cli/commands/manager/auto-assignment.js +4 -4
  2. package/dist/cli/commands/manager/auto-assignment.js.map +1 -1
  3. package/dist/cli/commands/manager/index.d.ts.map +1 -1
  4. package/dist/cli/commands/manager/index.js +68 -3
  5. package/dist/cli/commands/manager/index.js.map +1 -1
  6. package/dist/cli/commands/manager/restart-cooldown.d.ts +10 -0
  7. package/dist/cli/commands/manager/restart-cooldown.d.ts.map +1 -0
  8. package/dist/cli/commands/manager/restart-cooldown.js +16 -0
  9. package/dist/cli/commands/manager/restart-cooldown.js.map +1 -0
  10. package/dist/cli/commands/manager/restart-cooldown.test.d.ts +2 -0
  11. package/dist/cli/commands/manager/restart-cooldown.test.d.ts.map +1 -0
  12. package/dist/cli/commands/manager/restart-cooldown.test.js +54 -0
  13. package/dist/cli/commands/manager/restart-cooldown.test.js.map +1 -0
  14. package/dist/cli/commands/req.d.ts +6 -0
  15. package/dist/cli/commands/req.d.ts.map +1 -1
  16. package/dist/cli/commands/req.js +1 -1
  17. package/dist/cli/commands/req.js.map +1 -1
  18. package/dist/db/queries/agents.d.ts +1 -0
  19. package/dist/db/queries/agents.d.ts.map +1 -1
  20. package/dist/db/queries/agents.js +4 -0
  21. package/dist/db/queries/agents.js.map +1 -1
  22. package/dist/db/queries/agents.test.js +10 -0
  23. package/dist/db/queries/agents.test.js.map +1 -1
  24. package/dist/tmux/manager.d.ts.map +1 -1
  25. package/dist/tmux/manager.js +15 -8
  26. package/dist/tmux/manager.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/cli/commands/manager/auto-assignment.ts +4 -4
  29. package/src/cli/commands/manager/index.ts +97 -3
  30. package/src/cli/commands/manager/restart-cooldown.test.ts +61 -0
  31. package/src/cli/commands/manager/restart-cooldown.ts +20 -0
  32. package/src/cli/commands/req.ts +1 -1
  33. package/src/db/queries/agents.test.ts +13 -0
  34. package/src/db/queries/agents.ts +5 -0
  35. package/src/tmux/manager.ts +19 -8
@@ -6,15 +6,15 @@ function verboseLog(ctx, message) {
6
6
  return;
7
7
  console.log(chalk.gray(` [verbose] ${message}`));
8
8
  }
9
- async function getPlannedUnassignedStoryCount(ctx) {
9
+ async function getAssignableUnassignedStoryCount(ctx) {
10
10
  return ctx.withDb(async (db) => {
11
- const rows = queryAll(db.db, "SELECT COUNT(*) as count FROM stories WHERE status = 'planned' AND assigned_agent_id IS NULL");
11
+ const rows = queryAll(db.db, "SELECT COUNT(*) as count FROM stories WHERE status IN ('planned', 'qa_failed') AND assigned_agent_id IS NULL");
12
12
  return rows[0]?.count || 0;
13
13
  });
14
14
  }
15
15
  export async function autoAssignPlannedStories(ctx) {
16
- const plannedUnassigned = await getPlannedUnassignedStoryCount(ctx);
17
- verboseLog(ctx, `autoAssignPlannedStories: plannedUnassigned=${plannedUnassigned}`);
16
+ const plannedUnassigned = await getAssignableUnassignedStoryCount(ctx);
17
+ verboseLog(ctx, `autoAssignPlannedStories: assignableUnassigned=${plannedUnassigned}`);
18
18
  if (plannedUnassigned === 0) {
19
19
  return;
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auto-assignment.js","sourceRoot":"","sources":["../../../../src/cli/commands/manager/auto-assignment.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,SAAS,UAAU,CAAC,GAAyC,EAAE,OAAe;IAC5E,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO;IACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,8BAA8B,CAAC,GAAwB;IACpE,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;QAC3B,MAAM,IAAI,GAAG,QAAQ,CACnB,EAAE,CAAC,EAAE,EACL,8FAA8F,CAC/F,CAAC;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,GAAwB;IACrE,MAAM,iBAAiB,GAAG,MAAM,8BAA8B,CAAC,GAAG,CAAC,CAAC;IACpE,UAAU,CAAC,GAAG,EAAE,+CAA+C,iBAAiB,EAAE,CAAC,CAAC;IAEpF,IAAI,iBAAiB,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE;QAChE,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;QAC/B,MAAM,SAAS,CAAC,eAAe,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,EAAE,CAAC;QAC/C,EAAE,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,UAAU,CACR,GAAG,EACH,sCAAsC,gBAAgB,CAAC,QAAQ,YAAY,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,CAC5G,CAAC;IACF,GAAG,CAAC,QAAQ,CAAC,mBAAmB,IAAI,gBAAgB,CAAC,QAAQ,CAAC;IAE9D,IAAI,gBAAgB,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,gBAAgB,CAAC,QAAQ,qBAAqB,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,iCAAiC,gBAAgB,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,CACzF,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,EAAE,CAAC;YAC1C,UAAU,CAAC,GAAG,EAAE,mCAAmC,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"auto-assignment.js","sourceRoot":"","sources":["../../../../src/cli/commands/manager/auto-assignment.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,SAAS,UAAU,CAAC,GAAyC,EAAE,OAAe;IAC5E,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO;IACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,iCAAiC,CAAC,GAAwB;IACvE,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;QAC3B,MAAM,IAAI,GAAG,QAAQ,CACnB,EAAE,CAAC,EAAE,EACL,8GAA8G,CAC/G,CAAC;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,GAAwB;IACrE,MAAM,iBAAiB,GAAG,MAAM,iCAAiC,CAAC,GAAG,CAAC,CAAC;IACvE,UAAU,CAAC,GAAG,EAAE,kDAAkD,iBAAiB,EAAE,CAAC,CAAC;IAEvF,IAAI,iBAAiB,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE;QAChE,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;QAC/B,MAAM,SAAS,CAAC,eAAe,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,EAAE,CAAC;QAC/C,EAAE,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,UAAU,CACR,GAAG,EACH,sCAAsC,gBAAgB,CAAC,QAAQ,YAAY,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,CAC5G,CAAC;IACF,GAAG,CAAC,QAAQ,CAAC,mBAAmB,IAAI,gBAAgB,CAAC,QAAQ,CAAC;IAE9D,IAAI,gBAAgB,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,gBAAgB,CAAC,QAAQ,qBAAqB,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,iCAAiC,gBAAgB,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,CACzF,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,EAAE,CAAC;YAC1C,UAAU,CAAC,GAAG,EAAE,mCAAmC,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4CpC,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AA8C/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAqCtD,UAAU,uBAAuB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kCAAkC;IAC1C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,UAAU,6BAA6B;IACrC,KAAK,EAAE,UAAU,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,WAAW,CA0BtF;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,kCAAkC,GAC3C,OAAO,CAOT;AAED,wBAAgB,yCAAyC,CACvD,QAAQ,EAAE,6BAA6B,GACtC,OAAO,CAMT;AAqWD,eAAO,MAAM,cAAc,SAE1B,CAAC;AAyoDF;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+K1F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8CpC,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAgD/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAqCtD,UAAU,uBAAuB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,kCAAkC;IAC1C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,UAAU,6BAA6B;IACrC,KAAK,EAAE,UAAU,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,WAAW,CA0BtF;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,kCAAkC,GAC3C,OAAO,CAOT;AAED,wBAAgB,yCAAyC,CACvD,QAAQ,EAAE,6BAA6B,GACtC,OAAO,CAMT;AAsWD,eAAO,MAAM,cAAc,SAE1B,CAAC;AA4qDF;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+K1F"}
@@ -15,7 +15,9 @@ import { createEscalation, getActiveEscalationsForAgent, getPendingEscalations,
15
15
  import { createLog } from '../../../db/queries/logs.js';
16
16
  import { getAllPendingMessages, markMessagesRead, } from '../../../db/queries/messages.js';
17
17
  import { backfillGithubPrNumbers, createPullRequest, getMergeQueue, getOpenPullRequestsByStory, getPullRequestsByStatus, updatePullRequest, } from '../../../db/queries/pull-requests.js';
18
+ import { getRequirementsByStatus } from '../../../db/queries/requirements.js';
18
19
  import { getStoriesByStatus, getStoryById, updateStory } from '../../../db/queries/stories.js';
20
+ import { getAllTeams } from '../../../db/queries/teams.js';
19
21
  import { getPullRequestComments, getPullRequestReviews } from '../../../git/github.js';
20
22
  import { Scheduler } from '../../../orchestrator/scheduler.js';
21
23
  import { AgentState } from '../../../state-detectors/types.js';
@@ -25,6 +27,7 @@ import { findHiveRoot as findHiveRootFromDir, getHivePaths } from '../../../util
25
27
  import { fetchOpenGitHubPRs, getExistingPRIdentifiers, ghRepoSlug, } from '../../../utils/pr-sync.js';
26
28
  import { extractStoryIdFromBranch } from '../../../utils/story-id.js';
27
29
  import { withHiveContext, withHiveRoot } from '../../../utils/with-hive-context.js';
30
+ import { generateTechLeadPrompt } from '../req.js';
28
31
  import { agentStates, createManagerNudgeEnvelope, detectAgentState, enforceBypassMode, forwardMessages, getAgentSafetyMode, handlePermissionPrompt, handlePlanApproval, nudgeAgent, submitManagerNudgeWithVerification, updateAgentStateTracking, } from './agent-monitoring.js';
29
32
  import { autoAssignPlannedStories } from './auto-assignment.js';
30
33
  import { assessCompletionFromOutput } from './done-intelligence.js';
@@ -34,6 +37,7 @@ import { checkFeatureTestResult } from './feature-test-result.js';
34
37
  import { handleStalledPlanningHandoff } from './handoff-recovery.js';
35
38
  import { cleanupAgentsReferencingMergedStory } from './merged-story-cleanup.js';
36
39
  import { shouldAutoResolveOrphanedManagerEscalation } from './orphaned-escalations.js';
40
+ import { isTechLeadRestartOnCooldown } from './restart-cooldown.js';
37
41
  import { findSessionForAgent } from './session-resolution.js';
38
42
  import { spinDownIdleAgents, spinDownMergedAgents } from './spin-down.js';
39
43
  import { findStaleSessionEscalations } from './stale-escalations.js';
@@ -84,6 +88,7 @@ export function shouldDeferStuckReminderUntilStaticWindow(snapshot) {
84
88
  const screenStaticBySession = new Map();
85
89
  const classifierTimeoutInterventionsBySession = new Map();
86
90
  const aiDoneFalseInterventionsBySession = new Map();
91
+ const techLeadLastRestartByAgentId = new Map();
87
92
  function verboseLog(verbose, message) {
88
93
  if (!verbose)
89
94
  return;
@@ -1163,8 +1168,26 @@ async function recoverStaleReviewingPRs(ctx) {
1163
1168
  const parsed = JSON.parse(result.stdout);
1164
1169
  const state = parsed.state?.toUpperCase();
1165
1170
  const url = parsed.url || null;
1166
- if (state === 'OPEN')
1171
+ if (state === 'OPEN') {
1172
+ // PR is still open on GitHub but stale in 'reviewing' — the QA agent
1173
+ // may have missed the original nudge. Re-nudge if QA agent is idle.
1174
+ if (candidate.reviewedBy) {
1175
+ const qaAgent = ctx.agentsBySessionName.get(candidate.reviewedBy);
1176
+ if (qaAgent && qaAgent.status === 'idle') {
1177
+ const githubLine = candidate.repoSlug
1178
+ ? `\n# GitHub: https://github.com/${candidate.repoSlug}/pull/${candidate.githubPrNumber}`
1179
+ : '';
1180
+ await sendManagerNudge(ctx, candidate.reviewedBy, `# [REMINDER] You are assigned PR review ${candidate.id} (${candidate.storyId || 'no-story'}).${githubLine}
1181
+ # This PR has been waiting for review. Execute now:
1182
+ # hive pr show ${candidate.id}
1183
+ # hive pr approve ${candidate.id}
1184
+ # or reject:
1185
+ # hive pr reject ${candidate.id} -r "reason"`);
1186
+ verboseLogCtx(ctx, `recoverStaleReviewingPRs: re-nudged idle QA ${candidate.reviewedBy} for stale pr=${candidate.id}`);
1187
+ }
1188
+ }
1167
1189
  continue;
1190
+ }
1168
1191
  if (state === 'MERGED') {
1169
1192
  mergedResults.push({
1170
1193
  candidate,
@@ -1415,9 +1438,16 @@ async function scanAgentSessions(ctx) {
1415
1438
  for (const session of ctx.hiveSessions) {
1416
1439
  if (session.name === 'hive-manager')
1417
1440
  continue;
1418
- activeSessionNames.add(session.name);
1419
1441
  const agent = ctx.agentsBySessionName.get(session.name);
1420
- const agentCliTool = (agent?.cli_tool || 'claude');
1442
+ // Skip sessions not registered in our DB (cross-project sessions).
1443
+ // This prevents escalation noise from sessions belonging to other
1444
+ // teams/projects sharing the same tmux server.
1445
+ if (!agent) {
1446
+ verboseLogCtx(ctx, `Skipping ${session.name}: no agent registered in DB (cross-project)`);
1447
+ continue;
1448
+ }
1449
+ activeSessionNames.add(session.name);
1450
+ const agentCliTool = (agent.cli_tool || 'claude');
1421
1451
  const safetyMode = getAgentSafetyMode(ctx.config, agent);
1422
1452
  verboseLogCtx(ctx, `Agent check: ${session.name} (cli=${agentCliTool}, safety=${safetyMode}, story=${agent?.current_story_id || '-'})`);
1423
1453
  // Forward unread messages (tmux I/O, no lock needed)
@@ -2285,6 +2315,11 @@ async function restartStaleTechLead(ctx) {
2285
2315
  verboseLogCtx(ctx, `restartStaleTechLead: techLead=${techLead.id} skip=not_stale remainingMs=${maxAgeMs - ageMs}`);
2286
2316
  continue;
2287
2317
  }
2318
+ const cooldown = isTechLeadRestartOnCooldown(techLeadLastRestartByAgentId.get(techLead.id), now, maxAgeHours);
2319
+ if (cooldown.onCooldown) {
2320
+ verboseLogCtx(ctx, `restartStaleTechLead: techLead=${techLead.id} skip=cooldown cooldownHours=${cooldown.cooldownHours} remainingMs=${cooldown.remainingMs}`);
2321
+ continue;
2322
+ }
2288
2323
  const output = await captureTmuxPane(techLead.tmuxSession, TMUX_CAPTURE_LINES_SHORT);
2289
2324
  const stateResult = detectAgentState(output, techLead.cliTool);
2290
2325
  verboseLogCtx(ctx, `restartStaleTechLead: techLead=${techLead.id} state=${stateResult.state} waiting=${stateResult.isWaiting} needsHuman=${stateResult.needsHuman}`);
@@ -2311,10 +2346,38 @@ async function restartStaleTechLead(ctx) {
2311
2346
  const model = resolveRuntimeModelForCli(agentConfig.model, cliTool);
2312
2347
  const runtimeBuilder = getCliRuntimeBuilder(cliTool);
2313
2348
  const commandArgs = runtimeBuilder.buildSpawnCommand(model, safetyMode);
2349
+ // Look up active requirement and teams to provide context to the restarted tech lead
2350
+ const initialPrompt = await ctx.withDb(async (db) => {
2351
+ const planningReqs = getRequirementsByStatus(db.db, 'planning');
2352
+ const inProgressReqs = getRequirementsByStatus(db.db, 'in_progress');
2353
+ const activeReq = planningReqs[0] ?? inProgressReqs[0] ?? null;
2354
+ const teams = getAllTeams(db.db);
2355
+ if (activeReq) {
2356
+ return generateTechLeadPrompt(activeReq.id, activeReq.title, activeReq.description, teams, activeReq.godmode === 1, activeReq.target_branch || 'main');
2357
+ }
2358
+ return `You are the Tech Lead of Hive, an AI development team orchestrator.
2359
+
2360
+ You have been restarted to refresh your context. No active requirement is currently being planned.
2361
+
2362
+ ## Next Steps
2363
+
2364
+ 1. Check the current status of the Hive workspace:
2365
+ \`\`\`bash
2366
+ hive status
2367
+ \`\`\`
2368
+
2369
+ 2. Check your inbox for messages from developers:
2370
+ \`\`\`bash
2371
+ hive msg inbox hive-tech-lead
2372
+ \`\`\`
2373
+
2374
+ 3. If there are pending requirements, begin planning them. If all work is complete, monitor for new requirements.`;
2375
+ });
2314
2376
  await spawnTmuxSession({
2315
2377
  sessionName: techLead.tmuxSession,
2316
2378
  workDir: ctx.root,
2317
2379
  commandArgs,
2380
+ initialPrompt,
2318
2381
  });
2319
2382
  // DB writes under brief lock
2320
2383
  await ctx.withDb(async (db) => {
@@ -2333,9 +2396,11 @@ async function restartStaleTechLead(ctx) {
2333
2396
  });
2334
2397
  updateAgent(db.db, techLead.id, {
2335
2398
  status: 'working',
2399
+ createdAt: new Date().toISOString(),
2336
2400
  });
2337
2401
  db.save();
2338
2402
  });
2403
+ techLeadLastRestartByAgentId.set(techLead.id, now);
2339
2404
  console.log(chalk.green(` Tech lead ${techLead.id} restarted for context freshness (age: ${ageHours.toFixed(1)}h)`));
2340
2405
  }
2341
2406
  }