hungry-ghost-hive 0.48.0 → 0.49.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.
- package/dist/agents/base-agent.d.ts +11 -11
- package/dist/agents/base-agent.d.ts.map +1 -1
- package/dist/agents/base-agent.js +25 -25
- package/dist/agents/base-agent.js.map +1 -1
- package/dist/agents/base-agent.test.js +2 -1
- package/dist/agents/base-agent.test.js.map +1 -1
- package/dist/agents/intermediate.d.ts +2 -0
- package/dist/agents/intermediate.d.ts.map +1 -1
- package/dist/agents/intermediate.js +25 -18
- package/dist/agents/intermediate.js.map +1 -1
- package/dist/agents/junior.d.ts +2 -0
- package/dist/agents/junior.d.ts.map +1 -1
- package/dist/agents/junior.js +25 -18
- package/dist/agents/junior.js.map +1 -1
- package/dist/agents/qa.d.ts +2 -0
- package/dist/agents/qa.d.ts.map +1 -1
- package/dist/agents/qa.js +47 -38
- package/dist/agents/qa.js.map +1 -1
- package/dist/agents/senior.d.ts +2 -0
- package/dist/agents/senior.d.ts.map +1 -1
- package/dist/agents/senior.js +40 -27
- package/dist/agents/senior.js.map +1 -1
- package/dist/agents/tech-lead.d.ts +2 -0
- package/dist/agents/tech-lead.d.ts.map +1 -1
- package/dist/agents/tech-lead.js +37 -31
- package/dist/agents/tech-lead.js.map +1 -1
- package/dist/cli/commands/add-repo.js +2 -2
- package/dist/cli/commands/add-repo.js.map +1 -1
- package/dist/cli/commands/add-repo.test.js +1 -1
- package/dist/cli/commands/add-repo.test.js.map +1 -1
- package/dist/cli/commands/agents.d.ts.map +1 -1
- package/dist/cli/commands/agents.js +12 -10
- package/dist/cli/commands/agents.js.map +1 -1
- package/dist/cli/commands/agents.test.js +7 -7
- package/dist/cli/commands/agents.test.js.map +1 -1
- package/dist/cli/commands/approach.js +2 -2
- package/dist/cli/commands/approach.js.map +1 -1
- package/dist/cli/commands/approvals.js +7 -7
- package/dist/cli/commands/approvals.js.map +1 -1
- package/dist/cli/commands/approvals.test.js +8 -8
- package/dist/cli/commands/approvals.test.js.map +1 -1
- package/dist/cli/commands/assign.js +4 -4
- package/dist/cli/commands/assign.js.map +1 -1
- package/dist/cli/commands/assign.test.js +18 -16
- package/dist/cli/commands/assign.test.js.map +1 -1
- package/dist/cli/commands/cleanup.d.ts.map +1 -1
- package/dist/cli/commands/cleanup.js +8 -8
- package/dist/cli/commands/cleanup.js.map +1 -1
- package/dist/cli/commands/cleanup.test.js +5 -1
- package/dist/cli/commands/cleanup.test.js.map +1 -1
- package/dist/cli/commands/escalations.js +9 -7
- package/dist/cli/commands/escalations.js.map +1 -1
- package/dist/cli/commands/escalations.test.js +2 -2
- package/dist/cli/commands/escalations.test.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +48 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +4 -0
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/commands/manager/agent-monitoring.d.ts +2 -2
- package/dist/cli/commands/manager/agent-monitoring.d.ts.map +1 -1
- package/dist/cli/commands/manager/agent-monitoring.js +1 -1
- package/dist/cli/commands/manager/agent-monitoring.js.map +1 -1
- package/dist/cli/commands/manager/auditor-lifecycle.js +3 -3
- package/dist/cli/commands/manager/auditor-lifecycle.js.map +1 -1
- package/dist/cli/commands/manager/auditor-lifecycle.test.js +21 -14
- package/dist/cli/commands/manager/auditor-lifecycle.test.js.map +1 -1
- package/dist/cli/commands/manager/auto-reject-comment-only-reviews.test.js +28 -23
- package/dist/cli/commands/manager/auto-reject-comment-only-reviews.test.js.map +1 -1
- package/dist/cli/commands/manager/escalation-handler.d.ts +2 -2
- package/dist/cli/commands/manager/escalation-handler.d.ts.map +1 -1
- package/dist/cli/commands/manager/escalation-handler.js +11 -10
- package/dist/cli/commands/manager/escalation-handler.js.map +1 -1
- package/dist/cli/commands/manager/escalation-handler.test.js +8 -8
- package/dist/cli/commands/manager/escalation-handler.test.js.map +1 -1
- package/dist/cli/commands/manager/feature-sign-off.js +7 -7
- package/dist/cli/commands/manager/feature-sign-off.js.map +1 -1
- package/dist/cli/commands/manager/feature-sign-off.test.js +40 -31
- package/dist/cli/commands/manager/feature-sign-off.test.js.map +1 -1
- package/dist/cli/commands/manager/feature-test-result.d.ts.map +1 -1
- package/dist/cli/commands/manager/feature-test-result.js +12 -13
- package/dist/cli/commands/manager/feature-test-result.js.map +1 -1
- package/dist/cli/commands/manager/handoff-recovery.d.ts.map +1 -1
- package/dist/cli/commands/manager/handoff-recovery.js +14 -15
- package/dist/cli/commands/manager/handoff-recovery.js.map +1 -1
- package/dist/cli/commands/manager/index.d.ts.map +1 -1
- package/dist/cli/commands/manager/index.js +26 -26
- package/dist/cli/commands/manager/index.js.map +1 -1
- package/dist/cli/commands/manager/index.test.js +3 -3
- package/dist/cli/commands/manager/index.test.js.map +1 -1
- package/dist/cli/commands/manager/merged-story-cleanup.d.ts +2 -2
- package/dist/cli/commands/manager/merged-story-cleanup.d.ts.map +1 -1
- package/dist/cli/commands/manager/merged-story-cleanup.js +6 -7
- package/dist/cli/commands/manager/merged-story-cleanup.js.map +1 -1
- package/dist/cli/commands/manager/merged-story-cleanup.test.js +27 -18
- package/dist/cli/commands/manager/merged-story-cleanup.test.js.map +1 -1
- package/dist/cli/commands/manager/pr-sync-orchestrator.d.ts.map +1 -1
- package/dist/cli/commands/manager/pr-sync-orchestrator.js +46 -38
- package/dist/cli/commands/manager/pr-sync-orchestrator.js.map +1 -1
- package/dist/cli/commands/manager/qa-review-handler.d.ts.map +1 -1
- package/dist/cli/commands/manager/qa-review-handler.js +25 -22
- package/dist/cli/commands/manager/qa-review-handler.js.map +1 -1
- package/dist/cli/commands/manager/spin-down.d.ts.map +1 -1
- package/dist/cli/commands/manager/spin-down.js +23 -19
- package/dist/cli/commands/manager/spin-down.js.map +1 -1
- package/dist/cli/commands/manager/stale-escalations.d.ts +2 -3
- package/dist/cli/commands/manager/stale-escalations.d.ts.map +1 -1
- package/dist/cli/commands/manager/stale-escalations.js.map +1 -1
- package/dist/cli/commands/manager/stuck-story-helpers.js +8 -8
- package/dist/cli/commands/manager/stuck-story-helpers.js.map +1 -1
- package/dist/cli/commands/manager/stuck-story-processor.d.ts +2 -2
- package/dist/cli/commands/manager/stuck-story-processor.d.ts.map +1 -1
- package/dist/cli/commands/manager/stuck-story-processor.js +23 -22
- package/dist/cli/commands/manager/stuck-story-processor.js.map +1 -1
- package/dist/cli/commands/manager/tech-lead-lifecycle.js +6 -6
- package/dist/cli/commands/manager/tech-lead-lifecycle.js.map +1 -1
- package/dist/cli/commands/manager/types.d.ts +2 -3
- package/dist/cli/commands/manager/types.d.ts.map +1 -1
- package/dist/cli/commands/manager/types.js.map +1 -1
- package/dist/cli/commands/msg.test.js +2 -2
- package/dist/cli/commands/msg.test.js.map +1 -1
- package/dist/cli/commands/my-stories.d.ts.map +1 -1
- package/dist/cli/commands/my-stories.js +17 -18
- package/dist/cli/commands/my-stories.js.map +1 -1
- package/dist/cli/commands/my-stories.test.js +2 -2
- package/dist/cli/commands/my-stories.test.js.map +1 -1
- package/dist/cli/commands/nuke.test.js +1 -1
- package/dist/cli/commands/nuke.test.js.map +1 -1
- package/dist/cli/commands/pr.js +32 -32
- package/dist/cli/commands/pr.js.map +1 -1
- package/dist/cli/commands/pr.test.js +10 -6
- package/dist/cli/commands/pr.test.js.map +1 -1
- package/dist/cli/commands/progress.d.ts.map +1 -1
- package/dist/cli/commands/progress.js +4 -5
- package/dist/cli/commands/progress.js.map +1 -1
- package/dist/cli/commands/progress.test.js +1 -1
- package/dist/cli/commands/progress.test.js.map +1 -1
- package/dist/cli/commands/req-headless.test.d.ts +2 -0
- package/dist/cli/commands/req-headless.test.d.ts.map +1 -0
- package/dist/cli/commands/req-headless.test.js +128 -0
- package/dist/cli/commands/req-headless.test.js.map +1 -0
- package/dist/cli/commands/req-spawn.test.js +5 -1
- package/dist/cli/commands/req-spawn.test.js.map +1 -1
- package/dist/cli/commands/req.d.ts.map +1 -1
- package/dist/cli/commands/req.js +13 -14
- package/dist/cli/commands/req.js.map +1 -1
- package/dist/cli/commands/resume.d.ts.map +1 -1
- package/dist/cli/commands/resume.js +7 -8
- package/dist/cli/commands/resume.js.map +1 -1
- package/dist/cli/commands/resume.test.js +1 -1
- package/dist/cli/commands/resume.test.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +42 -40
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/status.test.js +1 -1
- package/dist/cli/commands/status.test.js.map +1 -1
- package/dist/cli/commands/stories.js +9 -9
- package/dist/cli/commands/stories.js.map +1 -1
- package/dist/cli/commands/stories.test.js +2 -2
- package/dist/cli/commands/stories.test.js.map +1 -1
- package/dist/cli/commands/teams.js +11 -11
- package/dist/cli/commands/teams.js.map +1 -1
- package/dist/cli/commands/teams.test.js +2 -2
- package/dist/cli/commands/teams.test.js.map +1 -1
- package/dist/cli/dashboard/index.d.ts +2 -2
- package/dist/cli/dashboard/index.d.ts.map +1 -1
- package/dist/cli/dashboard/index.js +29 -20
- package/dist/cli/dashboard/index.js.map +1 -1
- package/dist/cli/dashboard/index.test.js +34 -32
- package/dist/cli/dashboard/index.test.js.map +1 -1
- package/dist/cli/dashboard/panels/activity.d.ts +3 -3
- package/dist/cli/dashboard/panels/activity.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/activity.js +1 -1
- package/dist/cli/dashboard/panels/activity.js.map +1 -1
- package/dist/cli/dashboard/panels/agents.d.ts +3 -3
- package/dist/cli/dashboard/panels/agents.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/agents.js +2 -2
- package/dist/cli/dashboard/panels/agents.js.map +1 -1
- package/dist/cli/dashboard/panels/escalations.d.ts +3 -3
- package/dist/cli/dashboard/panels/escalations.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/escalations.js +1 -1
- package/dist/cli/dashboard/panels/escalations.js.map +1 -1
- package/dist/cli/dashboard/panels/merge-queue.d.ts +3 -3
- package/dist/cli/dashboard/panels/merge-queue.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/merge-queue.js +1 -1
- package/dist/cli/dashboard/panels/merge-queue.js.map +1 -1
- package/dist/cli/dashboard/panels/pipeline.d.ts +3 -3
- package/dist/cli/dashboard/panels/pipeline.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/pipeline.js +1 -1
- package/dist/cli/dashboard/panels/pipeline.js.map +1 -1
- package/dist/config/schema.d.ts +85 -82
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +1 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/connectors/project-management/operations.d.ts +7 -7
- package/dist/connectors/project-management/operations.d.ts.map +1 -1
- package/dist/connectors/project-management/operations.js +2 -3
- package/dist/connectors/project-management/operations.js.map +1 -1
- package/dist/context-files/index.test.js +1 -0
- package/dist/context-files/index.test.js.map +1 -1
- package/dist/db/client.d.ts +6 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +7 -0
- package/dist/db/client.js.map +1 -1
- package/dist/db/postgres-provider.d.ts +43 -0
- package/dist/db/postgres-provider.d.ts.map +1 -0
- package/dist/db/postgres-provider.integration.test.d.ts +2 -0
- package/dist/db/postgres-provider.integration.test.d.ts.map +1 -0
- package/dist/db/postgres-provider.integration.test.js +399 -0
- package/dist/db/postgres-provider.integration.test.js.map +1 -0
- package/dist/db/postgres-provider.js +315 -0
- package/dist/db/postgres-provider.js.map +1 -0
- package/dist/db/postgres-provider.test.d.ts +2 -0
- package/dist/db/postgres-provider.test.d.ts.map +1 -0
- package/dist/db/postgres-provider.test.js +72 -0
- package/dist/db/postgres-provider.test.js.map +1 -0
- package/dist/db/provider.d.ts +59 -0
- package/dist/db/provider.d.ts.map +1 -0
- package/dist/db/provider.js +121 -0
- package/dist/db/provider.js.map +1 -0
- package/dist/db/provider.test.d.ts +2 -0
- package/dist/db/provider.test.d.ts.map +1 -0
- package/dist/db/provider.test.js +226 -0
- package/dist/db/provider.test.js.map +1 -0
- package/dist/db/queries/agents.d.ts +13 -13
- package/dist/db/queries/agents.d.ts.map +1 -1
- package/dist/db/queries/agents.js +27 -28
- package/dist/db/queries/agents.js.map +1 -1
- package/dist/db/queries/agents.test.js +113 -111
- package/dist/db/queries/agents.test.js.map +1 -1
- package/dist/db/queries/escalations.d.ts +16 -16
- package/dist/db/queries/escalations.d.ts.map +1 -1
- package/dist/db/queries/escalations.js +34 -35
- package/dist/db/queries/escalations.js.map +1 -1
- package/dist/db/queries/escalations.test.js +133 -131
- package/dist/db/queries/escalations.test.js.map +1 -1
- package/dist/db/queries/heartbeat.d.ts +5 -5
- package/dist/db/queries/heartbeat.d.ts.map +1 -1
- package/dist/db/queries/heartbeat.js +7 -23
- package/dist/db/queries/heartbeat.js.map +1 -1
- package/dist/db/queries/heartbeat.test.js +76 -76
- package/dist/db/queries/heartbeat.test.js.map +1 -1
- package/dist/db/queries/integration-sync.d.ts +7 -7
- package/dist/db/queries/integration-sync.d.ts.map +1 -1
- package/dist/db/queries/integration-sync.js +13 -14
- package/dist/db/queries/integration-sync.js.map +1 -1
- package/dist/db/queries/logs.d.ts +10 -10
- package/dist/db/queries/logs.d.ts.map +1 -1
- package/dist/db/queries/logs.js +44 -42
- package/dist/db/queries/logs.js.map +1 -1
- package/dist/db/queries/logs.test.js +149 -146
- package/dist/db/queries/logs.test.js.map +1 -1
- package/dist/db/queries/messages.d.ts +6 -6
- package/dist/db/queries/messages.d.ts.map +1 -1
- package/dist/db/queries/messages.js +12 -11
- package/dist/db/queries/messages.js.map +1 -1
- package/dist/db/queries/messages.test.js +47 -46
- package/dist/db/queries/messages.test.js.map +1 -1
- package/dist/db/queries/pull-requests.d.ts +18 -18
- package/dist/db/queries/pull-requests.d.ts.map +1 -1
- package/dist/db/queries/pull-requests.js +50 -48
- package/dist/db/queries/pull-requests.js.map +1 -1
- package/dist/db/queries/pull-requests.test.js +195 -198
- package/dist/db/queries/pull-requests.test.js.map +1 -1
- package/dist/db/queries/requirements.d.ts +8 -8
- package/dist/db/queries/requirements.d.ts.map +1 -1
- package/dist/db/queries/requirements.js +17 -18
- package/dist/db/queries/requirements.js.map +1 -1
- package/dist/db/queries/requirements.test.js +83 -81
- package/dist/db/queries/requirements.test.js.map +1 -1
- package/dist/db/queries/stories.d.ts +29 -29
- package/dist/db/queries/stories.d.ts.map +1 -1
- package/dist/db/queries/stories.js +58 -64
- package/dist/db/queries/stories.js.map +1 -1
- package/dist/db/queries/stories.test.js +172 -170
- package/dist/db/queries/stories.test.js.map +1 -1
- package/dist/db/queries/teams.d.ts +6 -6
- package/dist/db/queries/teams.d.ts.map +1 -1
- package/dist/db/queries/teams.js +11 -12
- package/dist/db/queries/teams.js.map +1 -1
- package/dist/db/queries/teams.test.js +36 -34
- package/dist/db/queries/teams.test.js.map +1 -1
- package/dist/integrations/jira/repair.test.js +26 -24
- package/dist/integrations/jira/repair.test.js.map +1 -1
- package/dist/integrations/jira/stories.d.ts +3 -3
- package/dist/integrations/jira/stories.d.ts.map +1 -1
- package/dist/integrations/jira/stories.js +12 -12
- package/dist/integrations/jira/stories.js.map +1 -1
- package/dist/integrations/jira/stories.test.js +10 -8
- package/dist/integrations/jira/stories.test.js.map +1 -1
- package/dist/integrations/jira/sync.d.ts +7 -7
- package/dist/integrations/jira/sync.d.ts.map +1 -1
- package/dist/integrations/jira/sync.js +17 -20
- package/dist/integrations/jira/sync.js.map +1 -1
- package/dist/integrations/jira/sync.test.js +63 -62
- package/dist/integrations/jira/sync.test.js.map +1 -1
- package/dist/integrations/jira/transitions.d.ts +3 -3
- package/dist/integrations/jira/transitions.d.ts.map +1 -1
- package/dist/integrations/jira/transitions.js +3 -3
- package/dist/integrations/jira/transitions.js.map +1 -1
- package/dist/orchestrator/agent-selector.d.ts +3 -3
- package/dist/orchestrator/agent-selector.d.ts.map +1 -1
- package/dist/orchestrator/agent-selector.js +5 -6
- package/dist/orchestrator/agent-selector.js.map +1 -1
- package/dist/orchestrator/dependency-resolver.d.ts +4 -4
- package/dist/orchestrator/dependency-resolver.d.ts.map +1 -1
- package/dist/orchestrator/dependency-resolver.js +6 -6
- package/dist/orchestrator/dependency-resolver.js.map +1 -1
- package/dist/orchestrator/feature-branch.d.ts +3 -3
- package/dist/orchestrator/feature-branch.d.ts.map +1 -1
- package/dist/orchestrator/feature-branch.js +9 -10
- package/dist/orchestrator/feature-branch.js.map +1 -1
- package/dist/orchestrator/feature-branch.test.js +80 -78
- package/dist/orchestrator/feature-branch.test.js.map +1 -1
- package/dist/orchestrator/orphan-recovery.d.ts +2 -2
- package/dist/orchestrator/orphan-recovery.d.ts.map +1 -1
- package/dist/orchestrator/orphan-recovery.js +10 -10
- package/dist/orchestrator/orphan-recovery.js.map +1 -1
- package/dist/orchestrator/scheduler.d.ts +4 -4
- package/dist/orchestrator/scheduler.d.ts.map +1 -1
- package/dist/orchestrator/scheduler.js +90 -76
- package/dist/orchestrator/scheduler.js.map +1 -1
- package/dist/orchestrator/scheduler.test.js +496 -374
- package/dist/orchestrator/scheduler.test.js.map +1 -1
- package/dist/utils/auto-merge.d.ts.map +1 -1
- package/dist/utils/auto-merge.js +74 -56
- package/dist/utils/auto-merge.js.map +1 -1
- package/dist/utils/auto-merge.test.js +101 -66
- package/dist/utils/auto-merge.test.js.map +1 -1
- package/dist/utils/cli-helpers.d.ts +5 -5
- package/dist/utils/cli-helpers.d.ts.map +1 -1
- package/dist/utils/cli-helpers.js +8 -9
- package/dist/utils/cli-helpers.js.map +1 -1
- package/dist/utils/cli-helpers.test.js +28 -30
- package/dist/utils/cli-helpers.test.js.map +1 -1
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +12 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/paths.test.js +1 -0
- package/dist/utils/paths.test.js.map +1 -1
- package/dist/utils/pr-sync.d.ts +10 -10
- package/dist/utils/pr-sync.d.ts.map +1 -1
- package/dist/utils/pr-sync.js +20 -21
- package/dist/utils/pr-sync.js.map +1 -1
- package/dist/utils/pr-sync.test.js +52 -50
- package/dist/utils/pr-sync.test.js.map +1 -1
- package/dist/utils/with-hive-context.d.ts.map +1 -1
- package/dist/utils/with-hive-context.js +70 -1
- package/dist/utils/with-hive-context.js.map +1 -1
- package/package.json +3 -1
- package/src/agents/base-agent.test.ts +2 -1
- package/src/agents/base-agent.ts +32 -28
- package/src/agents/intermediate.ts +27 -18
- package/src/agents/junior.ts +27 -18
- package/src/agents/qa.ts +54 -40
- package/src/agents/senior.ts +42 -27
- package/src/agents/tech-lead.ts +42 -32
- package/src/cli/commands/add-repo.test.ts +1 -1
- package/src/cli/commands/add-repo.ts +2 -2
- package/src/cli/commands/agents.test.ts +7 -7
- package/src/cli/commands/agents.ts +12 -10
- package/src/cli/commands/approach.ts +2 -2
- package/src/cli/commands/approvals.test.ts +8 -8
- package/src/cli/commands/approvals.ts +9 -7
- package/src/cli/commands/assign.test.ts +19 -18
- package/src/cli/commands/assign.ts +4 -4
- package/src/cli/commands/cleanup.test.ts +5 -1
- package/src/cli/commands/cleanup.ts +11 -9
- package/src/cli/commands/escalations.test.ts +2 -2
- package/src/cli/commands/escalations.ts +9 -7
- package/src/cli/commands/init.test.ts +5 -0
- package/src/cli/commands/init.ts +53 -5
- package/src/cli/commands/manager/agent-monitoring.ts +3 -3
- package/src/cli/commands/manager/auditor-lifecycle.test.ts +21 -14
- package/src/cli/commands/manager/auditor-lifecycle.ts +3 -3
- package/src/cli/commands/manager/auto-reject-comment-only-reviews.test.ts +28 -23
- package/src/cli/commands/manager/escalation-handler.test.ts +13 -13
- package/src/cli/commands/manager/escalation-handler.ts +19 -12
- package/src/cli/commands/manager/feature-sign-off.test.ts +40 -31
- package/src/cli/commands/manager/feature-sign-off.ts +7 -7
- package/src/cli/commands/manager/feature-test-result.ts +13 -16
- package/src/cli/commands/manager/handoff-recovery.ts +20 -20
- package/src/cli/commands/manager/index.test.ts +4 -4
- package/src/cli/commands/manager/index.ts +58 -59
- package/src/cli/commands/manager/merged-story-cleanup.test.ts +28 -19
- package/src/cli/commands/manager/merged-story-cleanup.ts +11 -14
- package/src/cli/commands/manager/pr-sync-orchestrator.ts +115 -110
- package/src/cli/commands/manager/qa-review-handler.ts +50 -63
- package/src/cli/commands/manager/spin-down.ts +27 -25
- package/src/cli/commands/manager/stale-escalations.ts +2 -3
- package/src/cli/commands/manager/stuck-story-helpers.ts +10 -10
- package/src/cli/commands/manager/stuck-story-processor.ts +56 -62
- package/src/cli/commands/manager/tech-lead-lifecycle.ts +6 -6
- package/src/cli/commands/manager/types.ts +2 -3
- package/src/cli/commands/msg.test.ts +2 -2
- package/src/cli/commands/my-stories.test.ts +4 -2
- package/src/cli/commands/my-stories.ts +22 -27
- package/src/cli/commands/nuke.test.ts +1 -1
- package/src/cli/commands/pr.test.ts +10 -6
- package/src/cli/commands/pr.ts +41 -32
- package/src/cli/commands/progress.test.ts +1 -1
- package/src/cli/commands/progress.ts +11 -6
- package/src/cli/commands/req-headless.test.ts +170 -0
- package/src/cli/commands/req-spawn.test.ts +12 -2
- package/src/cli/commands/req.ts +13 -14
- package/src/cli/commands/resume.test.ts +1 -1
- package/src/cli/commands/resume.ts +7 -8
- package/src/cli/commands/status.test.ts +1 -1
- package/src/cli/commands/status.ts +52 -40
- package/src/cli/commands/stories.test.ts +4 -2
- package/src/cli/commands/stories.ts +11 -11
- package/src/cli/commands/teams.test.ts +2 -2
- package/src/cli/commands/teams.ts +11 -11
- package/src/cli/dashboard/index.test.ts +35 -34
- package/src/cli/dashboard/index.ts +34 -23
- package/src/cli/dashboard/panels/activity.ts +10 -4
- package/src/cli/dashboard/panels/agents.ts +8 -5
- package/src/cli/dashboard/panels/escalations.ts +4 -4
- package/src/cli/dashboard/panels/merge-queue.ts +4 -4
- package/src/cli/dashboard/panels/pipeline.ts +10 -4
- package/src/config/schema.ts +1 -0
- package/src/connectors/project-management/operations.ts +9 -10
- package/src/context-files/index.test.ts +1 -0
- package/src/db/client.ts +17 -0
- package/src/db/pg-migrations/001-full-schema.sql +209 -0
- package/src/db/postgres-provider.integration.test.ts +574 -0
- package/src/db/postgres-provider.test.ts +97 -0
- package/src/db/postgres-provider.ts +364 -0
- package/src/db/provider.test.ts +283 -0
- package/src/db/provider.ts +161 -0
- package/src/db/queries/agents.test.ts +114 -113
- package/src/db/queries/agents.ts +50 -36
- package/src/db/queries/escalations.test.ts +134 -133
- package/src/db/queries/escalations.ts +72 -57
- package/src/db/queries/heartbeat.test.ts +77 -78
- package/src/db/queries/heartbeat.ts +24 -46
- package/src/db/queries/integration-sync.ts +26 -26
- package/src/db/queries/logs.test.ts +151 -148
- package/src/db/queries/logs.ts +78 -53
- package/src/db/queries/messages.test.ts +48 -50
- package/src/db/queries/messages.ts +26 -18
- package/src/db/queries/pull-requests.test.ts +194 -199
- package/src/db/queries/pull-requests.ts +117 -88
- package/src/db/queries/requirements.test.ts +84 -83
- package/src/db/queries/requirements.ts +33 -28
- package/src/db/queries/stories.test.ts +173 -172
- package/src/db/queries/stories.ts +141 -110
- package/src/db/queries/teams.test.ts +37 -36
- package/src/db/queries/teams.ts +22 -14
- package/src/integrations/jira/repair.test.ts +27 -26
- package/src/integrations/jira/stories.test.ts +15 -16
- package/src/integrations/jira/stories.ts +15 -15
- package/src/integrations/jira/sync.test.ts +68 -68
- package/src/integrations/jira/sync.ts +29 -39
- package/src/integrations/jira/transitions.ts +6 -6
- package/src/orchestrator/agent-selector.ts +9 -8
- package/src/orchestrator/dependency-resolver.ts +16 -7
- package/src/orchestrator/feature-branch.test.ts +85 -80
- package/src/orchestrator/feature-branch.ts +13 -14
- package/src/orchestrator/orphan-recovery.ts +14 -13
- package/src/orchestrator/scheduler.test.ts +536 -394
- package/src/orchestrator/scheduler.ts +129 -115
- package/src/utils/auto-merge.test.ts +102 -68
- package/src/utils/auto-merge.ts +161 -168
- package/src/utils/cli-helpers.test.ts +30 -32
- package/src/utils/cli-helpers.ts +15 -11
- package/src/utils/paths.test.ts +1 -0
- package/src/utils/paths.ts +14 -1
- package/src/utils/pr-sync.test.ts +55 -52
- package/src/utils/pr-sync.ts +27 -32
- package/src/utils/with-hive-context.ts +89 -1
|
@@ -3,7 +3,6 @@ import { join } from 'path';
|
|
|
3
3
|
import { getCliRuntimeBuilder, resolveRuntimeModelForCli, validateModelCliCompatibility, } from '../cli-runtimes/index.js';
|
|
4
4
|
import { PMOperationQueue } from '../connectors/project-management/operation-queue.js';
|
|
5
5
|
import { createSubtaskForStory, postCommentOnIssue, syncStatusForStory, } from '../connectors/project-management/operations.js';
|
|
6
|
-
import { queryAll, withTransaction } from '../db/client.js';
|
|
7
6
|
import { createAgent, getAgentById, getAgentsByTeam, updateAgent, } from '../db/queries/agents.js';
|
|
8
7
|
import { createEscalation } from '../db/queries/escalations.js';
|
|
9
8
|
import { createLog } from '../db/queries/logs.js';
|
|
@@ -41,12 +40,12 @@ const DEFAULT_MAX_QA_AGENTS = 5;
|
|
|
41
40
|
/** Default manager check interval in seconds */
|
|
42
41
|
const DEFAULT_MANAGER_INTERVAL_SECONDS = 60;
|
|
43
42
|
export class Scheduler {
|
|
44
|
-
|
|
43
|
+
provider;
|
|
45
44
|
config;
|
|
46
45
|
saveFn;
|
|
47
46
|
pmQueue;
|
|
48
47
|
constructor(db, config) {
|
|
49
|
-
this.
|
|
48
|
+
this.provider = db;
|
|
50
49
|
this.config = config;
|
|
51
50
|
this.saveFn = config.saveFn;
|
|
52
51
|
this.pmQueue = new PMOperationQueue();
|
|
@@ -111,14 +110,14 @@ export class Scheduler {
|
|
|
111
110
|
/**
|
|
112
111
|
* Remove a git worktree for an agent
|
|
113
112
|
*/
|
|
114
|
-
removeAgentWorktree(worktreePath, agentId) {
|
|
113
|
+
async removeAgentWorktree(worktreePath, agentId) {
|
|
115
114
|
if (!worktreePath)
|
|
116
115
|
return;
|
|
117
116
|
const result = removeWorktree(this.config.rootDir, worktreePath, {
|
|
118
117
|
timeout: GIT_WORKTREE_REMOVE_TIMEOUT_MS,
|
|
119
118
|
});
|
|
120
119
|
if (!result.success) {
|
|
121
|
-
createLog(this.
|
|
120
|
+
await createLog(this.provider, {
|
|
122
121
|
agentId,
|
|
123
122
|
eventType: 'WORKTREE_REMOVAL_FAILED',
|
|
124
123
|
status: 'error',
|
|
@@ -134,12 +133,12 @@ export class Scheduler {
|
|
|
134
133
|
* Assign planned stories to available agents
|
|
135
134
|
*/
|
|
136
135
|
async assignStories() {
|
|
137
|
-
const plannedStories = getPlannedStories(this.
|
|
136
|
+
const plannedStories = await getPlannedStories(this.provider);
|
|
138
137
|
const errors = [];
|
|
139
138
|
let assigned = 0;
|
|
140
139
|
let preventedDuplicates = 0;
|
|
141
140
|
// Topological sort stories to respect dependencies
|
|
142
|
-
const sortedStories = topologicalSort(this.
|
|
141
|
+
const sortedStories = await topologicalSort(this.provider, plannedStories);
|
|
143
142
|
if (sortedStories === null) {
|
|
144
143
|
errors.push('Circular dependency detected in planned stories');
|
|
145
144
|
return { assigned, errors, preventedDuplicates };
|
|
@@ -159,15 +158,15 @@ export class Scheduler {
|
|
|
159
158
|
}
|
|
160
159
|
// Process each team
|
|
161
160
|
for (const [teamId, stories] of storiesByTeam) {
|
|
162
|
-
const team = getTeamById(this.
|
|
161
|
+
const team = await getTeamById(this.provider, teamId);
|
|
163
162
|
if (!team)
|
|
164
163
|
continue;
|
|
165
164
|
// Get available agents for this team
|
|
166
165
|
// Include agents that are working but have no current story (effectively idle)
|
|
167
|
-
const agents = getAgentsByTeam(this.
|
|
166
|
+
const agents = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type !== 'qa' &&
|
|
168
167
|
a.type !== 'auditor' &&
|
|
169
168
|
(a.status === 'idle' || (a.status === 'working' && a.current_story_id === null)));
|
|
170
|
-
const activeSeniors = getAgentsByTeam(this.
|
|
169
|
+
const activeSeniors = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type === 'senior' && a.status !== 'terminated');
|
|
171
170
|
const seniorSessionPrefix = generateSessionName('senior', team.name, undefined, join(this.config.rootDir, '.hive'));
|
|
172
171
|
const indexedSeniorSessions = activeSeniors
|
|
173
172
|
.map(senior => {
|
|
@@ -209,12 +208,12 @@ export class Scheduler {
|
|
|
209
208
|
continue;
|
|
210
209
|
}
|
|
211
210
|
// Assign stories based on complexity and capacity policy
|
|
212
|
-
const storiesToAssign = selectStoriesForCapacity(stories, this.config.scaling);
|
|
211
|
+
const storiesToAssign = await selectStoriesForCapacity(stories, this.config.scaling);
|
|
213
212
|
// Separate blocker stories from regular stories
|
|
214
213
|
const blockerStories = [];
|
|
215
214
|
const regularStories = [];
|
|
216
215
|
for (const story of storiesToAssign) {
|
|
217
|
-
const dependents = getStoriesDependingOn(this.
|
|
216
|
+
const dependents = await getStoriesDependingOn(this.provider, story.id);
|
|
218
217
|
if (dependents.length > 0) {
|
|
219
218
|
blockerStories.push(story);
|
|
220
219
|
}
|
|
@@ -226,10 +225,10 @@ export class Scheduler {
|
|
|
226
225
|
const orderedStoriesToAssign = [...blockerStories, ...regularStories];
|
|
227
226
|
for (const story of orderedStoriesToAssign) {
|
|
228
227
|
// Check if story is already assigned (prevent duplicate assignment)
|
|
229
|
-
const currentStory = getStoryById(this.
|
|
228
|
+
const currentStory = await getStoryById(this.provider, story.id);
|
|
230
229
|
if (currentStory && currentStory.assigned_agent_id !== null) {
|
|
231
230
|
preventedDuplicates++;
|
|
232
|
-
createLog(this.
|
|
231
|
+
await createLog(this.provider, {
|
|
233
232
|
agentId: 'scheduler',
|
|
234
233
|
storyId: story.id,
|
|
235
234
|
eventType: 'DUPLICATE_ASSIGNMENT_PREVENTED',
|
|
@@ -238,11 +237,11 @@ export class Scheduler {
|
|
|
238
237
|
continue;
|
|
239
238
|
}
|
|
240
239
|
// Check if dependencies are satisfied before assigning
|
|
241
|
-
if (!areDependenciesSatisfied(this.
|
|
240
|
+
if (!(await areDependenciesSatisfied(this.provider, story.id))) {
|
|
242
241
|
continue;
|
|
243
242
|
}
|
|
244
243
|
// Check if this story is a blocker (has dependents)
|
|
245
|
-
const dependents = getStoriesDependingOn(this.
|
|
244
|
+
const dependents = await getStoriesDependingOn(this.provider, story.id);
|
|
246
245
|
const isBlocker = dependents.length > 0;
|
|
247
246
|
const complexity = story.complexity_score || 5;
|
|
248
247
|
let targetAgent;
|
|
@@ -254,7 +253,9 @@ export class Scheduler {
|
|
|
254
253
|
// Assign to Junior with least workload
|
|
255
254
|
const juniors = agents.filter(a => a.type === 'junior' && a.status === 'idle');
|
|
256
255
|
targetAgent =
|
|
257
|
-
juniors.length > 0
|
|
256
|
+
juniors.length > 0
|
|
257
|
+
? await selectAgentWithLeastWorkload(this.provider, juniors)
|
|
258
|
+
: undefined;
|
|
258
259
|
if (!targetAgent) {
|
|
259
260
|
try {
|
|
260
261
|
targetAgent = await this.spawnJunior(teamId, team.name, team.repo_path);
|
|
@@ -265,7 +266,7 @@ export class Scheduler {
|
|
|
265
266
|
const intermediates = agents.filter(a => a.type === 'intermediate' && a.status === 'idle');
|
|
266
267
|
targetAgent =
|
|
267
268
|
intermediates.length > 0
|
|
268
|
-
? selectAgentWithLeastWorkload(this.
|
|
269
|
+
? await selectAgentWithLeastWorkload(this.provider, intermediates)
|
|
269
270
|
: await getOrSpawnSenior();
|
|
270
271
|
}
|
|
271
272
|
}
|
|
@@ -275,7 +276,7 @@ export class Scheduler {
|
|
|
275
276
|
const intermediates = agents.filter(a => a.type === 'intermediate' && a.status === 'idle');
|
|
276
277
|
targetAgent =
|
|
277
278
|
intermediates.length > 0
|
|
278
|
-
? selectAgentWithLeastWorkload(this.
|
|
279
|
+
? await selectAgentWithLeastWorkload(this.provider, intermediates)
|
|
279
280
|
: undefined;
|
|
280
281
|
if (!targetAgent) {
|
|
281
282
|
try {
|
|
@@ -298,25 +299,27 @@ export class Scheduler {
|
|
|
298
299
|
}
|
|
299
300
|
// Assign the story (atomic transaction)
|
|
300
301
|
try {
|
|
301
|
-
await withTransaction(
|
|
302
|
-
updateStory(this.
|
|
302
|
+
await this.provider.withTransaction(async () => {
|
|
303
|
+
await updateStory(this.provider, story.id, {
|
|
303
304
|
assignedAgentId: targetAgent.id,
|
|
304
305
|
status: 'in_progress',
|
|
305
306
|
}, this.storiesDir);
|
|
306
|
-
updateAgent(this.
|
|
307
|
+
await updateAgent(this.provider, targetAgent.id, {
|
|
307
308
|
status: 'working',
|
|
308
309
|
currentStoryId: story.id,
|
|
309
310
|
});
|
|
310
311
|
const message = isBlocker
|
|
311
312
|
? `Assigned to ${targetAgent.type} (escalated due to being a dependency blocker)`
|
|
312
313
|
: `Assigned to ${targetAgent.type}`;
|
|
313
|
-
createLog(this.
|
|
314
|
+
await createLog(this.provider, {
|
|
314
315
|
agentId: targetAgent.id,
|
|
315
316
|
storyId: story.id,
|
|
316
317
|
eventType: 'STORY_ASSIGNED',
|
|
317
318
|
message,
|
|
318
319
|
});
|
|
319
|
-
}
|
|
320
|
+
});
|
|
321
|
+
if (this.saveFn)
|
|
322
|
+
this.saveFn();
|
|
320
323
|
assigned++;
|
|
321
324
|
// Keep local availability snapshot in sync so we don't reassign
|
|
322
325
|
// additional stories to an agent already marked busy this cycle.
|
|
@@ -337,7 +340,7 @@ export class Scheduler {
|
|
|
337
340
|
await this.handleJiraAfterAssignment(story, targetAgent, team);
|
|
338
341
|
});
|
|
339
342
|
this.pmQueue.enqueue(`story-${story.id}-status-transition`, async () => {
|
|
340
|
-
await syncStatusForStory(this.config.rootDir, this.
|
|
343
|
+
await syncStatusForStory(this.config.rootDir, this.provider, story.id, 'in_progress');
|
|
341
344
|
});
|
|
342
345
|
// Force an explicit context handoff in the assigned tmux session so
|
|
343
346
|
// reused sessions do not continue stale prior-story threads.
|
|
@@ -370,7 +373,7 @@ export class Scheduler {
|
|
|
370
373
|
].join(' ');
|
|
371
374
|
try {
|
|
372
375
|
await sendToTmuxSession(sessionName, handoffMessage);
|
|
373
|
-
createLog(this.
|
|
376
|
+
await createLog(this.provider, {
|
|
374
377
|
agentId: 'scheduler',
|
|
375
378
|
storyId: story.id,
|
|
376
379
|
eventType: 'STORY_PROGRESS_UPDATE',
|
|
@@ -382,7 +385,7 @@ export class Scheduler {
|
|
|
382
385
|
});
|
|
383
386
|
}
|
|
384
387
|
catch (err) {
|
|
385
|
-
createLog(this.
|
|
388
|
+
await createLog(this.provider, {
|
|
386
389
|
agentId: 'scheduler',
|
|
387
390
|
storyId: story.id,
|
|
388
391
|
eventType: 'STORY_PROGRESS_UPDATE',
|
|
@@ -407,7 +410,7 @@ export class Scheduler {
|
|
|
407
410
|
// Re-fetch the story from DB to get the latest PM data (the passed-in
|
|
408
411
|
// story object may be stale — external_issue_key is set during sync
|
|
409
412
|
// which may have completed after this object was fetched).
|
|
410
|
-
const freshStory = getStoryById(this.
|
|
413
|
+
const freshStory = await getStoryById(this.provider, story.id);
|
|
411
414
|
if (!freshStory?.external_issue_key) {
|
|
412
415
|
logger.debug(`Story ${story.id} has no external issue key, skipping subtask creation`);
|
|
413
416
|
return;
|
|
@@ -428,7 +431,7 @@ export class Scheduler {
|
|
|
428
431
|
});
|
|
429
432
|
if (subtask) {
|
|
430
433
|
// Persist subtask reference back to the story
|
|
431
|
-
updateStory(this.
|
|
434
|
+
await updateStory(this.provider, freshStory.id, {
|
|
432
435
|
externalSubtaskKey: subtask.key,
|
|
433
436
|
externalSubtaskId: subtask.id,
|
|
434
437
|
}, this.storiesDir);
|
|
@@ -449,12 +452,12 @@ export class Scheduler {
|
|
|
449
452
|
/**
|
|
450
453
|
* Get the next story to work on for a specific agent
|
|
451
454
|
*/
|
|
452
|
-
getNextStoryForAgent(agentId) {
|
|
453
|
-
const agent = getAgentById(this.
|
|
455
|
+
async getNextStoryForAgent(agentId) {
|
|
456
|
+
const agent = await getAgentById(this.provider, agentId);
|
|
454
457
|
if (!agent || !agent.team_id)
|
|
455
458
|
return null;
|
|
456
459
|
// Find unassigned planned stories for this team
|
|
457
|
-
const stories = queryAll(
|
|
460
|
+
const stories = await this.provider.queryAll(`
|
|
458
461
|
SELECT * FROM stories
|
|
459
462
|
WHERE team_id = ?
|
|
460
463
|
AND status = 'planned'
|
|
@@ -463,7 +466,7 @@ export class Scheduler {
|
|
|
463
466
|
`, [agent.team_id]);
|
|
464
467
|
// Filter out stories with unresolved dependencies
|
|
465
468
|
for (const story of stories) {
|
|
466
|
-
if (areDependenciesSatisfied(this.
|
|
469
|
+
if (await areDependenciesSatisfied(this.provider, story.id)) {
|
|
467
470
|
return story;
|
|
468
471
|
}
|
|
469
472
|
}
|
|
@@ -474,15 +477,21 @@ export class Scheduler {
|
|
|
474
477
|
* Only spawns agents when there is assignable work (stories with satisfied dependencies)
|
|
475
478
|
*/
|
|
476
479
|
async checkScaling() {
|
|
477
|
-
const teams = getAllTeams(this.
|
|
480
|
+
const teams = await getAllTeams(this.provider);
|
|
478
481
|
for (const team of teams) {
|
|
479
482
|
// Get planned stories for this team
|
|
480
|
-
const plannedStories = getPlannedStories(this.
|
|
483
|
+
const plannedStories = (await getPlannedStories(this.provider)).filter(s => s.team_id === team.id);
|
|
481
484
|
// Filter to only assignable stories (dependencies satisfied, within refactor capacity)
|
|
482
|
-
const
|
|
485
|
+
const capacityStories = selectStoriesForCapacity(plannedStories, this.config.scaling);
|
|
486
|
+
const assignableStories = [];
|
|
487
|
+
for (const story of capacityStories) {
|
|
488
|
+
if (await areDependenciesSatisfied(this.provider, story.id)) {
|
|
489
|
+
assignableStories.push(story);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
483
492
|
// Count story points only from assignable work
|
|
484
493
|
const assignableStoryPoints = assignableStories.reduce((sum, story) => sum + getCapacityPoints(story), 0);
|
|
485
|
-
const seniors = getAgentsByTeam(this.
|
|
494
|
+
const seniors = (await getAgentsByTeam(this.provider, team.id)).filter(a => a.type === 'senior' && a.status !== 'terminated');
|
|
486
495
|
// Calculate needed seniors based on assignable work only
|
|
487
496
|
const seniorCapacity = this.config.scaling.senior_capacity;
|
|
488
497
|
const neededSeniors = Math.ceil(assignableStoryPoints / seniorCapacity);
|
|
@@ -493,7 +502,7 @@ export class Scheduler {
|
|
|
493
502
|
for (let i = 0; i < toSpawn; i++) {
|
|
494
503
|
try {
|
|
495
504
|
await this.spawnSenior(team.id, team.name, team.repo_path, currentSeniors + i + 1);
|
|
496
|
-
createLog(this.
|
|
505
|
+
await createLog(this.provider, {
|
|
497
506
|
agentId: 'scheduler',
|
|
498
507
|
eventType: 'TEAM_SCALED_UP',
|
|
499
508
|
message: `Spawned additional Senior for team ${team.name}`,
|
|
@@ -502,7 +511,7 @@ export class Scheduler {
|
|
|
502
511
|
}
|
|
503
512
|
catch (error) {
|
|
504
513
|
// Log error but continue
|
|
505
|
-
createLog(this.
|
|
514
|
+
await createLog(this.provider, {
|
|
506
515
|
agentId: 'scheduler',
|
|
507
516
|
eventType: 'TEAM_SCALED_UP',
|
|
508
517
|
status: 'error',
|
|
@@ -519,7 +528,7 @@ export class Scheduler {
|
|
|
519
528
|
* Returns number of agents whose status was corrected
|
|
520
529
|
*/
|
|
521
530
|
async healthCheck() {
|
|
522
|
-
const allAgents = queryAll(
|
|
531
|
+
const allAgents = await this.provider.queryAll(`
|
|
523
532
|
SELECT * FROM agents WHERE status != 'terminated'
|
|
524
533
|
`);
|
|
525
534
|
const liveSessions = await getHiveSessions(join(this.config.rootDir, '.hive'));
|
|
@@ -538,12 +547,12 @@ export class Scheduler {
|
|
|
538
547
|
if (agent.worktree_path) {
|
|
539
548
|
this.removeAgentWorktree(agent.worktree_path, agent.id);
|
|
540
549
|
}
|
|
541
|
-
updateAgent(this.
|
|
550
|
+
await updateAgent(this.provider, agent.id, {
|
|
542
551
|
status: 'terminated',
|
|
543
552
|
currentStoryId: null,
|
|
544
553
|
worktreePath: null,
|
|
545
554
|
});
|
|
546
|
-
createLog(this.
|
|
555
|
+
await createLog(this.provider, {
|
|
547
556
|
agentId: agent.id,
|
|
548
557
|
eventType: 'AGENT_TERMINATED',
|
|
549
558
|
message: `Session ${agent.tmux_session} no longer running`,
|
|
@@ -551,18 +560,18 @@ export class Scheduler {
|
|
|
551
560
|
terminated++;
|
|
552
561
|
// If agent was working on a story, mark it for reassignment
|
|
553
562
|
if (agent.current_story_id) {
|
|
554
|
-
updateStory(this.
|
|
563
|
+
await updateStory(this.provider, agent.current_story_id, {
|
|
555
564
|
status: 'planned',
|
|
556
565
|
assignedAgentId: null,
|
|
557
566
|
}, this.storiesDir);
|
|
558
567
|
revived.push(agent.current_story_id);
|
|
559
568
|
// Sync status change to Jira (fire and forget)
|
|
560
|
-
syncStatusForStory(this.config.rootDir, this.
|
|
569
|
+
syncStatusForStory(this.config.rootDir, this.provider, agent.current_story_id, 'planned');
|
|
561
570
|
}
|
|
562
571
|
}
|
|
563
572
|
}
|
|
564
573
|
// Detect and recover orphaned stories (assigned to terminated agents)
|
|
565
|
-
const orphanedRecovered = detectAndRecoverOrphanedStories(this.
|
|
574
|
+
const orphanedRecovered = await detectAndRecoverOrphanedStories(this.provider, this.config.rootDir, this.storiesDir);
|
|
566
575
|
return { terminated, revived, orphanedRecovered };
|
|
567
576
|
}
|
|
568
577
|
/**
|
|
@@ -570,7 +579,7 @@ export class Scheduler {
|
|
|
570
579
|
* Scales QA agents based on pending work: 1 QA per 2-3 pending PRs, max 5
|
|
571
580
|
*/
|
|
572
581
|
async checkMergeQueue() {
|
|
573
|
-
const teams = getAllTeams(this.
|
|
582
|
+
const teams = await getAllTeams(this.provider);
|
|
574
583
|
for (const team of teams) {
|
|
575
584
|
await this.scaleQAAgents(team.id, team.name, team.repo_path);
|
|
576
585
|
}
|
|
@@ -590,7 +599,7 @@ export class Scheduler {
|
|
|
590
599
|
*/
|
|
591
600
|
async scaleQAAgents(teamId, teamName, repoPath) {
|
|
592
601
|
// Count pending QA work: explicit QA statuses OR any non-merged story with an open PR.
|
|
593
|
-
const qaStories = queryAll(
|
|
602
|
+
const qaStories = await this.provider.queryAll(`
|
|
594
603
|
SELECT DISTINCT s.* FROM stories s
|
|
595
604
|
LEFT JOIN pull_requests pr ON pr.story_id = s.id
|
|
596
605
|
WHERE s.team_id = ? AND (
|
|
@@ -609,7 +618,7 @@ export class Scheduler {
|
|
|
609
618
|
// If no pending work, scale down to 0 agents
|
|
610
619
|
const neededQAs = pendingCount > 0 ? Math.min(Math.ceil(pendingCount / pendingPerAgent), maxAgents) : 0;
|
|
611
620
|
// Get currently active QA agents for this team
|
|
612
|
-
const activeQAs = getAgentsByTeam(this.
|
|
621
|
+
const activeQAs = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type === 'qa' && a.status !== 'terminated');
|
|
613
622
|
const currentQACount = activeQAs.length;
|
|
614
623
|
if (neededQAs > currentQACount) {
|
|
615
624
|
// Scale up: spawn additional QA agents in parallel
|
|
@@ -621,7 +630,7 @@ export class Scheduler {
|
|
|
621
630
|
}
|
|
622
631
|
try {
|
|
623
632
|
await Promise.all(spawnPromises);
|
|
624
|
-
createLog(this.
|
|
633
|
+
await createLog(this.provider, {
|
|
625
634
|
agentId: 'scheduler',
|
|
626
635
|
eventType: 'TEAM_SCALED_UP',
|
|
627
636
|
message: `Scaled QA agents for team ${teamName}: ${currentQACount} → ${neededQAs} (${pendingCount} pending stories)`,
|
|
@@ -635,7 +644,7 @@ export class Scheduler {
|
|
|
635
644
|
});
|
|
636
645
|
}
|
|
637
646
|
catch (err) {
|
|
638
|
-
createLog(this.
|
|
647
|
+
await createLog(this.provider, {
|
|
639
648
|
agentId: 'scheduler',
|
|
640
649
|
eventType: 'AGENT_SPAWNED',
|
|
641
650
|
status: 'error',
|
|
@@ -655,7 +664,12 @@ export class Scheduler {
|
|
|
655
664
|
return bIndex - aIndex; // Descending order to remove highest indices first
|
|
656
665
|
});
|
|
657
666
|
// Filter out agents that are actively reviewing
|
|
658
|
-
const terminableAgents =
|
|
667
|
+
const terminableAgents = [];
|
|
668
|
+
for (const agent of sortedAgents) {
|
|
669
|
+
if (!(await isAgentReviewingPR(this.provider, agent.id))) {
|
|
670
|
+
terminableAgents.push(agent);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
659
673
|
const qaAgentsToTerminate = terminableAgents.slice(0, toTerminate);
|
|
660
674
|
try {
|
|
661
675
|
for (const agent of qaAgentsToTerminate) {
|
|
@@ -668,20 +682,20 @@ export class Scheduler {
|
|
|
668
682
|
this.removeAgentWorktree(agent.worktree_path, agent.id);
|
|
669
683
|
}
|
|
670
684
|
// Update database
|
|
671
|
-
updateAgent(this.
|
|
685
|
+
await updateAgent(this.provider, agent.id, {
|
|
672
686
|
status: 'terminated',
|
|
673
687
|
currentStoryId: null,
|
|
674
688
|
worktreePath: null,
|
|
675
689
|
});
|
|
676
690
|
// Log the event
|
|
677
|
-
createLog(this.
|
|
691
|
+
await createLog(this.provider, {
|
|
678
692
|
agentId: agent.id,
|
|
679
693
|
eventType: 'AGENT_TERMINATED',
|
|
680
694
|
message: 'QA agent scaled down due to reduced PR queue',
|
|
681
695
|
metadata: { teamId, agentType: 'qa', reason: 'queue_shrink', pendingCount },
|
|
682
696
|
});
|
|
683
697
|
}
|
|
684
|
-
createLog(this.
|
|
698
|
+
await createLog(this.provider, {
|
|
685
699
|
agentId: 'scheduler',
|
|
686
700
|
eventType: 'TEAM_SCALED_DOWN',
|
|
687
701
|
message: `Scaled down QA agents for team ${teamName}: ${currentQACount} → ${neededQAs} (${pendingCount} pending stories)`,
|
|
@@ -695,7 +709,7 @@ export class Scheduler {
|
|
|
695
709
|
});
|
|
696
710
|
}
|
|
697
711
|
catch (err) {
|
|
698
|
-
createLog(this.
|
|
712
|
+
await createLog(this.provider, {
|
|
699
713
|
agentId: 'scheduler',
|
|
700
714
|
eventType: 'AGENT_TERMINATED',
|
|
701
715
|
status: 'error',
|
|
@@ -723,7 +737,7 @@ export class Scheduler {
|
|
|
723
737
|
: generateSessionName(type, teamName, index, hiveDir);
|
|
724
738
|
// Prevent creating duplicate agents on same tmux session (for senior agents)
|
|
725
739
|
if (type === 'senior') {
|
|
726
|
-
const existingSeniors = getAgentsByTeam(this.
|
|
740
|
+
const existingSeniors = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type === 'senior');
|
|
727
741
|
const existingOnSession = existingSeniors.find(a => a.tmux_session === sessionName && a.status !== 'terminated');
|
|
728
742
|
if (existingOnSession && (await isTmuxSessionRunning(sessionName))) {
|
|
729
743
|
const sessionSeniorAvailable = existingOnSession.status === 'idle' ||
|
|
@@ -738,7 +752,7 @@ export class Scheduler {
|
|
|
738
752
|
let modelConfig = this.config.models[type];
|
|
739
753
|
// Override Claude runtime models to Opus 4.6 when godmode is active
|
|
740
754
|
const configuredCliTool = modelConfig.cli_tool || 'claude';
|
|
741
|
-
if (this.isGodmodeActive() && configuredCliTool === 'claude') {
|
|
755
|
+
if ((await this.isGodmodeActive()) && configuredCliTool === 'claude') {
|
|
742
756
|
modelConfig = {
|
|
743
757
|
provider: 'anthropic',
|
|
744
758
|
model: 'claude-opus-4-6',
|
|
@@ -759,10 +773,10 @@ export class Scheduler {
|
|
|
759
773
|
catch (err) {
|
|
760
774
|
// Create an escalation for human review instead of spawning a broken agent
|
|
761
775
|
const errorMessage = err instanceof Error ? err.message : 'Unknown compatibility error';
|
|
762
|
-
createEscalation(this.
|
|
776
|
+
await createEscalation(this.provider, {
|
|
763
777
|
reason: `Configuration mismatch: Cannot spawn ${type} agent for team ${teamName}. ${errorMessage}`,
|
|
764
778
|
});
|
|
765
|
-
createLog(this.
|
|
779
|
+
await createLog(this.provider, {
|
|
766
780
|
agentId: 'scheduler',
|
|
767
781
|
eventType: 'AGENT_SPAWN_FAILED',
|
|
768
782
|
status: 'error',
|
|
@@ -778,26 +792,26 @@ export class Scheduler {
|
|
|
778
792
|
// Throw the error to prevent agent creation
|
|
779
793
|
throw new OperationalError(`Cannot spawn ${type} agent: ${errorMessage}`);
|
|
780
794
|
}
|
|
781
|
-
const agent = createAgent(this.
|
|
795
|
+
const agent = await createAgent(this.provider, {
|
|
782
796
|
type,
|
|
783
797
|
teamId,
|
|
784
798
|
model: runtimeModel,
|
|
785
799
|
});
|
|
786
800
|
// Determine the target branch for this team's stories
|
|
787
|
-
const targetBranch = this.getTargetBranchForTeam(teamId);
|
|
801
|
+
const targetBranch = await this.getTargetBranchForTeam(teamId);
|
|
788
802
|
// Create git worktree for this agent from the correct base branch
|
|
789
803
|
const worktreePath = await this.createWorktree(agent.id, teamId, repoPath, targetBranch);
|
|
790
804
|
const workDir = `${this.config.rootDir}/${worktreePath}`;
|
|
791
805
|
if (!(await isTmuxSessionRunning(sessionName))) {
|
|
792
806
|
// Build the initial prompt for this agent type
|
|
793
|
-
const team = getTeamById(this.
|
|
807
|
+
const team = await getTeamById(this.provider, teamId);
|
|
794
808
|
const includeProgressUpdates = this.shouldIncludeProgressUpdates();
|
|
795
809
|
const hiveDir = join(this.config.rootDir, '.hive');
|
|
796
810
|
const techLeadSession = getTechLeadSessionName(hiveDir);
|
|
797
811
|
const chromeEnabled = this.config.hiveConfig?.agents?.chrome_enabled === true && cliTool === 'claude';
|
|
798
812
|
let prompt;
|
|
799
813
|
if (type === 'senior') {
|
|
800
|
-
const stories = this.getTeamStories(teamId);
|
|
814
|
+
const stories = await this.getTeamStories(teamId);
|
|
801
815
|
prompt = generateSeniorPrompt(teamName, team?.repo_url || '', worktreePath, stories, targetBranch, { includeProgressUpdates, techLeadSession, chromeEnabled }, sessionName);
|
|
802
816
|
}
|
|
803
817
|
else if (type === 'intermediate') {
|
|
@@ -834,7 +848,7 @@ export class Scheduler {
|
|
|
834
848
|
// Auto-start manager when spawning agents
|
|
835
849
|
await this.ensureManagerRunning();
|
|
836
850
|
}
|
|
837
|
-
updateAgent(this.
|
|
851
|
+
await updateAgent(this.provider, agent.id, {
|
|
838
852
|
tmuxSession: sessionName,
|
|
839
853
|
status: 'idle',
|
|
840
854
|
worktreePath,
|
|
@@ -850,8 +864,8 @@ export class Scheduler {
|
|
|
850
864
|
* Checks requirements directly rather than through stories, so godmode stays
|
|
851
865
|
* active even after stories move from planned to in_progress/review/qa.
|
|
852
866
|
*/
|
|
853
|
-
isGodmodeActive() {
|
|
854
|
-
const activeRequirements = queryAll(
|
|
867
|
+
async isGodmodeActive() {
|
|
868
|
+
const activeRequirements = await this.provider.queryAll(`SELECT * FROM requirements WHERE status IN ('planning', 'planned', 'in_progress') AND godmode = 1`);
|
|
855
869
|
return activeRequirements.length > 0;
|
|
856
870
|
}
|
|
857
871
|
/**
|
|
@@ -889,12 +903,12 @@ export class Scheduler {
|
|
|
889
903
|
return this.spawnAgent('senior', teamId, teamName, repoPath, index);
|
|
890
904
|
}
|
|
891
905
|
async spawnIntermediate(teamId, teamName, repoPath) {
|
|
892
|
-
const existing = getAgentsByTeam(this.
|
|
906
|
+
const existing = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type === 'intermediate');
|
|
893
907
|
const index = existing.length + 1;
|
|
894
908
|
return this.spawnAgent('intermediate', teamId, teamName, repoPath, index);
|
|
895
909
|
}
|
|
896
910
|
async spawnJunior(teamId, teamName, repoPath) {
|
|
897
|
-
const existing = getAgentsByTeam(this.
|
|
911
|
+
const existing = (await getAgentsByTeam(this.provider, teamId)).filter(a => a.type === 'junior');
|
|
898
912
|
const index = existing.length + 1;
|
|
899
913
|
return this.spawnAgent('junior', teamId, teamName, repoPath, index);
|
|
900
914
|
}
|
|
@@ -904,13 +918,13 @@ export class Scheduler {
|
|
|
904
918
|
* If stories come from multiple requirements with different target branches,
|
|
905
919
|
* use the most common one. Defaults to 'main' if no requirement or target_branch is set.
|
|
906
920
|
*/
|
|
907
|
-
getTargetBranchForTeam(teamId) {
|
|
908
|
-
const stories = this.getTeamStories(teamId);
|
|
921
|
+
async getTargetBranchForTeam(teamId) {
|
|
922
|
+
const stories = await this.getTeamStories(teamId);
|
|
909
923
|
const branchCounts = new Map();
|
|
910
924
|
for (const story of stories) {
|
|
911
925
|
if (!story.requirement_id)
|
|
912
926
|
continue;
|
|
913
|
-
const requirement = getRequirementById(this.
|
|
927
|
+
const requirement = await getRequirementById(this.provider, story.requirement_id);
|
|
914
928
|
if (!requirement?.target_branch)
|
|
915
929
|
continue;
|
|
916
930
|
const count = branchCounts.get(requirement.target_branch) || 0;
|
|
@@ -929,8 +943,8 @@ export class Scheduler {
|
|
|
929
943
|
}
|
|
930
944
|
return maxBranch;
|
|
931
945
|
}
|
|
932
|
-
getTeamStories(teamId) {
|
|
933
|
-
return queryAll(
|
|
946
|
+
async getTeamStories(teamId) {
|
|
947
|
+
return this.provider.queryAll(`
|
|
934
948
|
SELECT * FROM stories
|
|
935
949
|
WHERE team_id = ? AND status IN ('planned', 'estimated')
|
|
936
950
|
ORDER BY complexity_score DESC
|
|
@@ -949,17 +963,17 @@ export class Scheduler {
|
|
|
949
963
|
*/
|
|
950
964
|
async createFeatureBranchesForPlannedStories(stories, errors) {
|
|
951
965
|
const storyIds = stories.map(s => s.id);
|
|
952
|
-
const requirementIds = getRequirementsNeedingFeatureBranch(this.
|
|
966
|
+
const requirementIds = await getRequirementsNeedingFeatureBranch(this.provider, storyIds, this.config.hiveConfig);
|
|
953
967
|
if (requirementIds.length === 0)
|
|
954
968
|
return;
|
|
955
969
|
// Find the repo path from the first team that has stories
|
|
956
970
|
// (all stories for a requirement typically belong to the same repo)
|
|
957
|
-
const teams = getAllTeams(this.
|
|
971
|
+
const teams = await getAllTeams(this.provider);
|
|
958
972
|
const repoPath = teams.length > 0 ? `${this.config.rootDir}/${teams[0].repo_path}` : null;
|
|
959
973
|
if (!repoPath)
|
|
960
974
|
return;
|
|
961
975
|
for (const reqId of requirementIds) {
|
|
962
|
-
const branch = await createRequirementFeatureBranch(this.
|
|
976
|
+
const branch = await createRequirementFeatureBranch(this.provider, repoPath, reqId, this.saveFn);
|
|
963
977
|
if (!branch) {
|
|
964
978
|
errors.push(`Failed to create feature branch for requirement ${reqId}`);
|
|
965
979
|
}
|