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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Licensed under the Hungry Ghost Hive License. See LICENSE.
|
|
2
2
|
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import type { Database } from 'sql.js';
|
|
5
4
|
import {
|
|
6
5
|
getCliRuntimeBuilder,
|
|
7
6
|
resolveRuntimeModelForCli,
|
|
@@ -14,7 +13,7 @@ import {
|
|
|
14
13
|
postCommentOnIssue,
|
|
15
14
|
syncStatusForStory,
|
|
16
15
|
} from '../connectors/project-management/operations.js';
|
|
17
|
-
import {
|
|
16
|
+
import type { DatabaseProvider } from '../db/provider.js';
|
|
18
17
|
import {
|
|
19
18
|
createAgent,
|
|
20
19
|
getAgentById,
|
|
@@ -95,13 +94,13 @@ export interface SchedulerConfig {
|
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
export class Scheduler {
|
|
98
|
-
private
|
|
97
|
+
private provider: DatabaseProvider;
|
|
99
98
|
private config: SchedulerConfig;
|
|
100
99
|
private saveFn?: () => void;
|
|
101
100
|
private pmQueue: PMOperationQueue;
|
|
102
101
|
|
|
103
|
-
constructor(db:
|
|
104
|
-
this.
|
|
102
|
+
constructor(db: DatabaseProvider, config: SchedulerConfig) {
|
|
103
|
+
this.provider = db;
|
|
105
104
|
this.config = config;
|
|
106
105
|
this.saveFn = config.saveFn;
|
|
107
106
|
this.pmQueue = new PMOperationQueue();
|
|
@@ -179,14 +178,14 @@ export class Scheduler {
|
|
|
179
178
|
/**
|
|
180
179
|
* Remove a git worktree for an agent
|
|
181
180
|
*/
|
|
182
|
-
private removeAgentWorktree(worktreePath: string, agentId: string): void {
|
|
181
|
+
private async removeAgentWorktree(worktreePath: string, agentId: string): Promise<void> {
|
|
183
182
|
if (!worktreePath) return;
|
|
184
183
|
|
|
185
184
|
const result = removeWorktree(this.config.rootDir, worktreePath, {
|
|
186
185
|
timeout: GIT_WORKTREE_REMOVE_TIMEOUT_MS,
|
|
187
186
|
});
|
|
188
187
|
if (!result.success) {
|
|
189
|
-
createLog(this.
|
|
188
|
+
await createLog(this.provider, {
|
|
190
189
|
agentId,
|
|
191
190
|
eventType: 'WORKTREE_REMOVAL_FAILED',
|
|
192
191
|
status: 'error',
|
|
@@ -208,13 +207,13 @@ export class Scheduler {
|
|
|
208
207
|
errors: string[];
|
|
209
208
|
preventedDuplicates: number;
|
|
210
209
|
}> {
|
|
211
|
-
const plannedStories = getPlannedStories(this.
|
|
210
|
+
const plannedStories = await getPlannedStories(this.provider);
|
|
212
211
|
const errors: string[] = [];
|
|
213
212
|
let assigned = 0;
|
|
214
213
|
let preventedDuplicates = 0;
|
|
215
214
|
|
|
216
215
|
// Topological sort stories to respect dependencies
|
|
217
|
-
const sortedStories = topologicalSort(this.
|
|
216
|
+
const sortedStories = await topologicalSort(this.provider, plannedStories);
|
|
218
217
|
if (sortedStories === null) {
|
|
219
218
|
errors.push('Circular dependency detected in planned stories');
|
|
220
219
|
return { assigned, errors, preventedDuplicates };
|
|
@@ -236,18 +235,18 @@ export class Scheduler {
|
|
|
236
235
|
|
|
237
236
|
// Process each team
|
|
238
237
|
for (const [teamId, stories] of storiesByTeam) {
|
|
239
|
-
const team = getTeamById(this.
|
|
238
|
+
const team = await getTeamById(this.provider, teamId);
|
|
240
239
|
if (!team) continue;
|
|
241
240
|
|
|
242
241
|
// Get available agents for this team
|
|
243
242
|
// Include agents that are working but have no current story (effectively idle)
|
|
244
|
-
const agents = getAgentsByTeam(this.
|
|
243
|
+
const agents = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
245
244
|
a =>
|
|
246
245
|
a.type !== 'qa' &&
|
|
247
246
|
a.type !== 'auditor' &&
|
|
248
247
|
(a.status === 'idle' || (a.status === 'working' && a.current_story_id === null))
|
|
249
248
|
);
|
|
250
|
-
const activeSeniors = getAgentsByTeam(this.
|
|
249
|
+
const activeSeniors = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
251
250
|
a => a.type === 'senior' && a.status !== 'terminated'
|
|
252
251
|
);
|
|
253
252
|
const seniorSessionPrefix = generateSessionName(
|
|
@@ -302,13 +301,13 @@ export class Scheduler {
|
|
|
302
301
|
}
|
|
303
302
|
|
|
304
303
|
// Assign stories based on complexity and capacity policy
|
|
305
|
-
const storiesToAssign = selectStoriesForCapacity(stories, this.config.scaling);
|
|
304
|
+
const storiesToAssign = await selectStoriesForCapacity(stories, this.config.scaling);
|
|
306
305
|
|
|
307
306
|
// Separate blocker stories from regular stories
|
|
308
307
|
const blockerStories: StoryRow[] = [];
|
|
309
308
|
const regularStories: StoryRow[] = [];
|
|
310
309
|
for (const story of storiesToAssign) {
|
|
311
|
-
const dependents = getStoriesDependingOn(this.
|
|
310
|
+
const dependents = await getStoriesDependingOn(this.provider, story.id);
|
|
312
311
|
if (dependents.length > 0) {
|
|
313
312
|
blockerStories.push(story);
|
|
314
313
|
} else {
|
|
@@ -321,10 +320,10 @@ export class Scheduler {
|
|
|
321
320
|
|
|
322
321
|
for (const story of orderedStoriesToAssign) {
|
|
323
322
|
// Check if story is already assigned (prevent duplicate assignment)
|
|
324
|
-
const currentStory = getStoryById(this.
|
|
323
|
+
const currentStory = await getStoryById(this.provider, story.id);
|
|
325
324
|
if (currentStory && currentStory.assigned_agent_id !== null) {
|
|
326
325
|
preventedDuplicates++;
|
|
327
|
-
createLog(this.
|
|
326
|
+
await createLog(this.provider, {
|
|
328
327
|
agentId: 'scheduler',
|
|
329
328
|
storyId: story.id,
|
|
330
329
|
eventType: 'DUPLICATE_ASSIGNMENT_PREVENTED',
|
|
@@ -334,12 +333,12 @@ export class Scheduler {
|
|
|
334
333
|
}
|
|
335
334
|
|
|
336
335
|
// Check if dependencies are satisfied before assigning
|
|
337
|
-
if (!areDependenciesSatisfied(this.
|
|
336
|
+
if (!(await areDependenciesSatisfied(this.provider, story.id))) {
|
|
338
337
|
continue;
|
|
339
338
|
}
|
|
340
339
|
|
|
341
340
|
// Check if this story is a blocker (has dependents)
|
|
342
|
-
const dependents = getStoriesDependingOn(this.
|
|
341
|
+
const dependents = await getStoriesDependingOn(this.provider, story.id);
|
|
343
342
|
const isBlocker = dependents.length > 0;
|
|
344
343
|
|
|
345
344
|
const complexity = story.complexity_score || 5;
|
|
@@ -352,7 +351,9 @@ export class Scheduler {
|
|
|
352
351
|
// Assign to Junior with least workload
|
|
353
352
|
const juniors = agents.filter(a => a.type === 'junior' && a.status === 'idle');
|
|
354
353
|
targetAgent =
|
|
355
|
-
juniors.length > 0
|
|
354
|
+
juniors.length > 0
|
|
355
|
+
? await selectAgentWithLeastWorkload(this.provider, juniors)
|
|
356
|
+
: undefined;
|
|
356
357
|
if (!targetAgent) {
|
|
357
358
|
try {
|
|
358
359
|
targetAgent = await this.spawnJunior(teamId, team.name, team.repo_path);
|
|
@@ -364,7 +365,7 @@ export class Scheduler {
|
|
|
364
365
|
);
|
|
365
366
|
targetAgent =
|
|
366
367
|
intermediates.length > 0
|
|
367
|
-
? selectAgentWithLeastWorkload(this.
|
|
368
|
+
? await selectAgentWithLeastWorkload(this.provider, intermediates)
|
|
368
369
|
: await getOrSpawnSenior();
|
|
369
370
|
}
|
|
370
371
|
}
|
|
@@ -375,7 +376,7 @@ export class Scheduler {
|
|
|
375
376
|
);
|
|
376
377
|
targetAgent =
|
|
377
378
|
intermediates.length > 0
|
|
378
|
-
? selectAgentWithLeastWorkload(this.
|
|
379
|
+
? await selectAgentWithLeastWorkload(this.provider, intermediates)
|
|
379
380
|
: undefined;
|
|
380
381
|
if (!targetAgent) {
|
|
381
382
|
try {
|
|
@@ -398,37 +399,34 @@ export class Scheduler {
|
|
|
398
399
|
|
|
399
400
|
// Assign the story (atomic transaction)
|
|
400
401
|
try {
|
|
401
|
-
await withTransaction(
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
402
|
+
await this.provider.withTransaction(async () => {
|
|
403
|
+
await updateStory(
|
|
404
|
+
this.provider,
|
|
405
|
+
story.id,
|
|
406
|
+
{
|
|
407
|
+
assignedAgentId: targetAgent.id,
|
|
408
|
+
status: 'in_progress',
|
|
409
|
+
},
|
|
410
|
+
this.storiesDir
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
await updateAgent(this.provider, targetAgent.id, {
|
|
414
|
+
status: 'working',
|
|
415
|
+
currentStoryId: story.id,
|
|
416
|
+
});
|
|
413
417
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
eventType: 'STORY_ASSIGNED',
|
|
427
|
-
message,
|
|
428
|
-
});
|
|
429
|
-
},
|
|
430
|
-
this.saveFn
|
|
431
|
-
);
|
|
418
|
+
const message = isBlocker
|
|
419
|
+
? `Assigned to ${targetAgent.type} (escalated due to being a dependency blocker)`
|
|
420
|
+
: `Assigned to ${targetAgent.type}`;
|
|
421
|
+
|
|
422
|
+
await createLog(this.provider, {
|
|
423
|
+
agentId: targetAgent.id,
|
|
424
|
+
storyId: story.id,
|
|
425
|
+
eventType: 'STORY_ASSIGNED',
|
|
426
|
+
message,
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
if (this.saveFn) this.saveFn();
|
|
432
430
|
assigned++;
|
|
433
431
|
|
|
434
432
|
// Keep local availability snapshot in sync so we don't reassign
|
|
@@ -452,7 +450,7 @@ export class Scheduler {
|
|
|
452
450
|
});
|
|
453
451
|
|
|
454
452
|
this.pmQueue.enqueue(`story-${story.id}-status-transition`, async () => {
|
|
455
|
-
await syncStatusForStory(this.config.rootDir, this.
|
|
453
|
+
await syncStatusForStory(this.config.rootDir, this.provider, story.id, 'in_progress');
|
|
456
454
|
});
|
|
457
455
|
|
|
458
456
|
// Force an explicit context handoff in the assigned tmux session so
|
|
@@ -489,7 +487,7 @@ export class Scheduler {
|
|
|
489
487
|
|
|
490
488
|
try {
|
|
491
489
|
await sendToTmuxSession(sessionName, handoffMessage);
|
|
492
|
-
createLog(this.
|
|
490
|
+
await createLog(this.provider, {
|
|
493
491
|
agentId: 'scheduler',
|
|
494
492
|
storyId: story.id,
|
|
495
493
|
eventType: 'STORY_PROGRESS_UPDATE',
|
|
@@ -500,7 +498,7 @@ export class Scheduler {
|
|
|
500
498
|
},
|
|
501
499
|
});
|
|
502
500
|
} catch (err) {
|
|
503
|
-
createLog(this.
|
|
501
|
+
await createLog(this.provider, {
|
|
504
502
|
agentId: 'scheduler',
|
|
505
503
|
storyId: story.id,
|
|
506
504
|
eventType: 'STORY_PROGRESS_UPDATE',
|
|
@@ -531,7 +529,7 @@ export class Scheduler {
|
|
|
531
529
|
// Re-fetch the story from DB to get the latest PM data (the passed-in
|
|
532
530
|
// story object may be stale — external_issue_key is set during sync
|
|
533
531
|
// which may have completed after this object was fetched).
|
|
534
|
-
const freshStory = getStoryById(this.
|
|
532
|
+
const freshStory = await getStoryById(this.provider, story.id);
|
|
535
533
|
if (!freshStory?.external_issue_key) {
|
|
536
534
|
logger.debug(`Story ${story.id} has no external issue key, skipping subtask creation`);
|
|
537
535
|
return;
|
|
@@ -561,8 +559,8 @@ export class Scheduler {
|
|
|
561
559
|
|
|
562
560
|
if (subtask) {
|
|
563
561
|
// Persist subtask reference back to the story
|
|
564
|
-
updateStory(
|
|
565
|
-
this.
|
|
562
|
+
await updateStory(
|
|
563
|
+
this.provider,
|
|
566
564
|
freshStory.id,
|
|
567
565
|
{
|
|
568
566
|
externalSubtaskKey: subtask.key,
|
|
@@ -590,13 +588,12 @@ export class Scheduler {
|
|
|
590
588
|
/**
|
|
591
589
|
* Get the next story to work on for a specific agent
|
|
592
590
|
*/
|
|
593
|
-
getNextStoryForAgent(agentId: string): StoryRow | null {
|
|
594
|
-
const agent = getAgentById(this.
|
|
591
|
+
async getNextStoryForAgent(agentId: string): Promise<StoryRow | null> {
|
|
592
|
+
const agent = await getAgentById(this.provider, agentId);
|
|
595
593
|
if (!agent || !agent.team_id) return null;
|
|
596
594
|
|
|
597
595
|
// Find unassigned planned stories for this team
|
|
598
|
-
const stories = queryAll<StoryRow>(
|
|
599
|
-
this.db,
|
|
596
|
+
const stories = await this.provider.queryAll<StoryRow>(
|
|
600
597
|
`
|
|
601
598
|
SELECT * FROM stories
|
|
602
599
|
WHERE team_id = ?
|
|
@@ -609,7 +606,7 @@ export class Scheduler {
|
|
|
609
606
|
|
|
610
607
|
// Filter out stories with unresolved dependencies
|
|
611
608
|
for (const story of stories) {
|
|
612
|
-
if (areDependenciesSatisfied(this.
|
|
609
|
+
if (await areDependenciesSatisfied(this.provider, story.id)) {
|
|
613
610
|
return story;
|
|
614
611
|
}
|
|
615
612
|
}
|
|
@@ -622,17 +619,22 @@ export class Scheduler {
|
|
|
622
619
|
* Only spawns agents when there is assignable work (stories with satisfied dependencies)
|
|
623
620
|
*/
|
|
624
621
|
async checkScaling(): Promise<void> {
|
|
625
|
-
const teams = getAllTeams(this.
|
|
622
|
+
const teams = await getAllTeams(this.provider);
|
|
626
623
|
|
|
627
624
|
for (const team of teams) {
|
|
628
625
|
// Get planned stories for this team
|
|
629
|
-
const plannedStories = getPlannedStories(this.
|
|
626
|
+
const plannedStories = (await getPlannedStories(this.provider)).filter(
|
|
627
|
+
s => s.team_id === team.id
|
|
628
|
+
);
|
|
630
629
|
|
|
631
630
|
// Filter to only assignable stories (dependencies satisfied, within refactor capacity)
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
631
|
+
const capacityStories = selectStoriesForCapacity(plannedStories, this.config.scaling);
|
|
632
|
+
const assignableStories: StoryRow[] = [];
|
|
633
|
+
for (const story of capacityStories) {
|
|
634
|
+
if (await areDependenciesSatisfied(this.provider, story.id)) {
|
|
635
|
+
assignableStories.push(story);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
636
638
|
|
|
637
639
|
// Count story points only from assignable work
|
|
638
640
|
const assignableStoryPoints = assignableStories.reduce(
|
|
@@ -640,7 +642,7 @@ export class Scheduler {
|
|
|
640
642
|
0
|
|
641
643
|
);
|
|
642
644
|
|
|
643
|
-
const seniors = getAgentsByTeam(this.
|
|
645
|
+
const seniors = (await getAgentsByTeam(this.provider, team.id)).filter(
|
|
644
646
|
a => a.type === 'senior' && a.status !== 'terminated'
|
|
645
647
|
);
|
|
646
648
|
|
|
@@ -655,7 +657,7 @@ export class Scheduler {
|
|
|
655
657
|
for (let i = 0; i < toSpawn; i++) {
|
|
656
658
|
try {
|
|
657
659
|
await this.spawnSenior(team.id, team.name, team.repo_path, currentSeniors + i + 1);
|
|
658
|
-
createLog(this.
|
|
660
|
+
await createLog(this.provider, {
|
|
659
661
|
agentId: 'scheduler',
|
|
660
662
|
eventType: 'TEAM_SCALED_UP',
|
|
661
663
|
message: `Spawned additional Senior for team ${team.name}`,
|
|
@@ -663,7 +665,7 @@ export class Scheduler {
|
|
|
663
665
|
});
|
|
664
666
|
} catch (error) {
|
|
665
667
|
// Log error but continue
|
|
666
|
-
createLog(this.
|
|
668
|
+
await createLog(this.provider, {
|
|
667
669
|
agentId: 'scheduler',
|
|
668
670
|
eventType: 'TEAM_SCALED_UP',
|
|
669
671
|
status: 'error',
|
|
@@ -685,8 +687,7 @@ export class Scheduler {
|
|
|
685
687
|
revived: string[];
|
|
686
688
|
orphanedRecovered: string[];
|
|
687
689
|
}> {
|
|
688
|
-
const allAgents = queryAll<AgentRow>(
|
|
689
|
-
this.db,
|
|
690
|
+
const allAgents = await this.provider.queryAll<AgentRow>(
|
|
690
691
|
`
|
|
691
692
|
SELECT * FROM agents WHERE status != 'terminated'
|
|
692
693
|
`
|
|
@@ -712,12 +713,12 @@ export class Scheduler {
|
|
|
712
713
|
this.removeAgentWorktree(agent.worktree_path, agent.id);
|
|
713
714
|
}
|
|
714
715
|
|
|
715
|
-
updateAgent(this.
|
|
716
|
+
await updateAgent(this.provider, agent.id, {
|
|
716
717
|
status: 'terminated',
|
|
717
718
|
currentStoryId: null,
|
|
718
719
|
worktreePath: null,
|
|
719
720
|
});
|
|
720
|
-
createLog(this.
|
|
721
|
+
await createLog(this.provider, {
|
|
721
722
|
agentId: agent.id,
|
|
722
723
|
eventType: 'AGENT_TERMINATED',
|
|
723
724
|
message: `Session ${agent.tmux_session} no longer running`,
|
|
@@ -726,8 +727,8 @@ export class Scheduler {
|
|
|
726
727
|
|
|
727
728
|
// If agent was working on a story, mark it for reassignment
|
|
728
729
|
if (agent.current_story_id) {
|
|
729
|
-
updateStory(
|
|
730
|
-
this.
|
|
730
|
+
await updateStory(
|
|
731
|
+
this.provider,
|
|
731
732
|
agent.current_story_id,
|
|
732
733
|
{
|
|
733
734
|
status: 'planned',
|
|
@@ -738,14 +739,14 @@ export class Scheduler {
|
|
|
738
739
|
revived.push(agent.current_story_id);
|
|
739
740
|
|
|
740
741
|
// Sync status change to Jira (fire and forget)
|
|
741
|
-
syncStatusForStory(this.config.rootDir, this.
|
|
742
|
+
syncStatusForStory(this.config.rootDir, this.provider, agent.current_story_id, 'planned');
|
|
742
743
|
}
|
|
743
744
|
}
|
|
744
745
|
}
|
|
745
746
|
|
|
746
747
|
// Detect and recover orphaned stories (assigned to terminated agents)
|
|
747
|
-
const orphanedRecovered = detectAndRecoverOrphanedStories(
|
|
748
|
-
this.
|
|
748
|
+
const orphanedRecovered = await detectAndRecoverOrphanedStories(
|
|
749
|
+
this.provider,
|
|
749
750
|
this.config.rootDir,
|
|
750
751
|
this.storiesDir
|
|
751
752
|
);
|
|
@@ -758,7 +759,7 @@ export class Scheduler {
|
|
|
758
759
|
* Scales QA agents based on pending work: 1 QA per 2-3 pending PRs, max 5
|
|
759
760
|
*/
|
|
760
761
|
async checkMergeQueue(): Promise<void> {
|
|
761
|
-
const teams = getAllTeams(this.
|
|
762
|
+
const teams = await getAllTeams(this.provider);
|
|
762
763
|
|
|
763
764
|
for (const team of teams) {
|
|
764
765
|
await this.scaleQAAgents(team.id, team.name, team.repo_path);
|
|
@@ -780,8 +781,7 @@ export class Scheduler {
|
|
|
780
781
|
*/
|
|
781
782
|
private async scaleQAAgents(teamId: string, teamName: string, repoPath: string): Promise<void> {
|
|
782
783
|
// Count pending QA work: explicit QA statuses OR any non-merged story with an open PR.
|
|
783
|
-
const qaStories = queryAll<StoryRow>(
|
|
784
|
-
this.db,
|
|
784
|
+
const qaStories = await this.provider.queryAll<StoryRow>(
|
|
785
785
|
`
|
|
786
786
|
SELECT DISTINCT s.* FROM stories s
|
|
787
787
|
LEFT JOIN pull_requests pr ON pr.story_id = s.id
|
|
@@ -808,7 +808,7 @@ export class Scheduler {
|
|
|
808
808
|
pendingCount > 0 ? Math.min(Math.ceil(pendingCount / pendingPerAgent), maxAgents) : 0;
|
|
809
809
|
|
|
810
810
|
// Get currently active QA agents for this team
|
|
811
|
-
const activeQAs = getAgentsByTeam(this.
|
|
811
|
+
const activeQAs = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
812
812
|
a => a.type === 'qa' && a.status !== 'terminated'
|
|
813
813
|
);
|
|
814
814
|
|
|
@@ -826,7 +826,7 @@ export class Scheduler {
|
|
|
826
826
|
|
|
827
827
|
try {
|
|
828
828
|
await Promise.all(spawnPromises);
|
|
829
|
-
createLog(this.
|
|
829
|
+
await createLog(this.provider, {
|
|
830
830
|
agentId: 'scheduler',
|
|
831
831
|
eventType: 'TEAM_SCALED_UP',
|
|
832
832
|
message: `Scaled QA agents for team ${teamName}: ${currentQACount} → ${neededQAs} (${pendingCount} pending stories)`,
|
|
@@ -839,7 +839,7 @@ export class Scheduler {
|
|
|
839
839
|
},
|
|
840
840
|
});
|
|
841
841
|
} catch (err) {
|
|
842
|
-
createLog(this.
|
|
842
|
+
await createLog(this.provider, {
|
|
843
843
|
agentId: 'scheduler',
|
|
844
844
|
eventType: 'AGENT_SPAWNED',
|
|
845
845
|
status: 'error',
|
|
@@ -860,7 +860,12 @@ export class Scheduler {
|
|
|
860
860
|
});
|
|
861
861
|
|
|
862
862
|
// Filter out agents that are actively reviewing
|
|
863
|
-
const terminableAgents =
|
|
863
|
+
const terminableAgents: AgentRow[] = [];
|
|
864
|
+
for (const agent of sortedAgents) {
|
|
865
|
+
if (!(await isAgentReviewingPR(this.provider, agent.id))) {
|
|
866
|
+
terminableAgents.push(agent);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
864
869
|
const qaAgentsToTerminate = terminableAgents.slice(0, toTerminate);
|
|
865
870
|
|
|
866
871
|
try {
|
|
@@ -876,14 +881,14 @@ export class Scheduler {
|
|
|
876
881
|
}
|
|
877
882
|
|
|
878
883
|
// Update database
|
|
879
|
-
updateAgent(this.
|
|
884
|
+
await updateAgent(this.provider, agent.id, {
|
|
880
885
|
status: 'terminated',
|
|
881
886
|
currentStoryId: null,
|
|
882
887
|
worktreePath: null,
|
|
883
888
|
});
|
|
884
889
|
|
|
885
890
|
// Log the event
|
|
886
|
-
createLog(this.
|
|
891
|
+
await createLog(this.provider, {
|
|
887
892
|
agentId: agent.id,
|
|
888
893
|
eventType: 'AGENT_TERMINATED',
|
|
889
894
|
message: 'QA agent scaled down due to reduced PR queue',
|
|
@@ -891,7 +896,7 @@ export class Scheduler {
|
|
|
891
896
|
});
|
|
892
897
|
}
|
|
893
898
|
|
|
894
|
-
createLog(this.
|
|
899
|
+
await createLog(this.provider, {
|
|
895
900
|
agentId: 'scheduler',
|
|
896
901
|
eventType: 'TEAM_SCALED_DOWN',
|
|
897
902
|
message: `Scaled down QA agents for team ${teamName}: ${currentQACount} → ${neededQAs} (${pendingCount} pending stories)`,
|
|
@@ -904,7 +909,7 @@ export class Scheduler {
|
|
|
904
909
|
},
|
|
905
910
|
});
|
|
906
911
|
} catch (err) {
|
|
907
|
-
createLog(this.
|
|
912
|
+
await createLog(this.provider, {
|
|
908
913
|
agentId: 'scheduler',
|
|
909
914
|
eventType: 'AGENT_TERMINATED',
|
|
910
915
|
status: 'error',
|
|
@@ -947,7 +952,9 @@ export class Scheduler {
|
|
|
947
952
|
|
|
948
953
|
// Prevent creating duplicate agents on same tmux session (for senior agents)
|
|
949
954
|
if (type === 'senior') {
|
|
950
|
-
const existingSeniors = getAgentsByTeam(this.
|
|
955
|
+
const existingSeniors = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
956
|
+
a => a.type === 'senior'
|
|
957
|
+
);
|
|
951
958
|
const existingOnSession = existingSeniors.find(
|
|
952
959
|
a => a.tmux_session === sessionName && a.status !== 'terminated'
|
|
953
960
|
);
|
|
@@ -969,7 +976,7 @@ export class Scheduler {
|
|
|
969
976
|
|
|
970
977
|
// Override Claude runtime models to Opus 4.6 when godmode is active
|
|
971
978
|
const configuredCliTool = modelConfig.cli_tool || 'claude';
|
|
972
|
-
if (this.isGodmodeActive() && configuredCliTool === 'claude') {
|
|
979
|
+
if ((await this.isGodmodeActive()) && configuredCliTool === 'claude') {
|
|
973
980
|
modelConfig = {
|
|
974
981
|
provider: 'anthropic',
|
|
975
982
|
model: 'claude-opus-4-6',
|
|
@@ -991,11 +998,11 @@ export class Scheduler {
|
|
|
991
998
|
} catch (err) {
|
|
992
999
|
// Create an escalation for human review instead of spawning a broken agent
|
|
993
1000
|
const errorMessage = err instanceof Error ? err.message : 'Unknown compatibility error';
|
|
994
|
-
createEscalation(this.
|
|
1001
|
+
await createEscalation(this.provider, {
|
|
995
1002
|
reason: `Configuration mismatch: Cannot spawn ${type} agent for team ${teamName}. ${errorMessage}`,
|
|
996
1003
|
});
|
|
997
1004
|
|
|
998
|
-
createLog(this.
|
|
1005
|
+
await createLog(this.provider, {
|
|
999
1006
|
agentId: 'scheduler',
|
|
1000
1007
|
eventType: 'AGENT_SPAWN_FAILED',
|
|
1001
1008
|
status: 'error',
|
|
@@ -1013,14 +1020,14 @@ export class Scheduler {
|
|
|
1013
1020
|
throw new OperationalError(`Cannot spawn ${type} agent: ${errorMessage}`);
|
|
1014
1021
|
}
|
|
1015
1022
|
|
|
1016
|
-
const agent = createAgent(this.
|
|
1023
|
+
const agent = await createAgent(this.provider, {
|
|
1017
1024
|
type,
|
|
1018
1025
|
teamId,
|
|
1019
1026
|
model: runtimeModel,
|
|
1020
1027
|
});
|
|
1021
1028
|
|
|
1022
1029
|
// Determine the target branch for this team's stories
|
|
1023
|
-
const targetBranch = this.getTargetBranchForTeam(teamId);
|
|
1030
|
+
const targetBranch = await this.getTargetBranchForTeam(teamId);
|
|
1024
1031
|
|
|
1025
1032
|
// Create git worktree for this agent from the correct base branch
|
|
1026
1033
|
const worktreePath = await this.createWorktree(agent.id, teamId, repoPath, targetBranch);
|
|
@@ -1028,7 +1035,7 @@ export class Scheduler {
|
|
|
1028
1035
|
|
|
1029
1036
|
if (!(await isTmuxSessionRunning(sessionName))) {
|
|
1030
1037
|
// Build the initial prompt for this agent type
|
|
1031
|
-
const team = getTeamById(this.
|
|
1038
|
+
const team = await getTeamById(this.provider, teamId);
|
|
1032
1039
|
const includeProgressUpdates = this.shouldIncludeProgressUpdates();
|
|
1033
1040
|
const hiveDir = join(this.config.rootDir, '.hive');
|
|
1034
1041
|
const techLeadSession = getTechLeadSessionName(hiveDir);
|
|
@@ -1037,7 +1044,7 @@ export class Scheduler {
|
|
|
1037
1044
|
let prompt: string;
|
|
1038
1045
|
|
|
1039
1046
|
if (type === 'senior') {
|
|
1040
|
-
const stories = this.getTeamStories(teamId);
|
|
1047
|
+
const stories = await this.getTeamStories(teamId);
|
|
1041
1048
|
prompt = generateSeniorPrompt(
|
|
1042
1049
|
teamName,
|
|
1043
1050
|
team?.repo_url || '',
|
|
@@ -1115,7 +1122,7 @@ export class Scheduler {
|
|
|
1115
1122
|
await this.ensureManagerRunning();
|
|
1116
1123
|
}
|
|
1117
1124
|
|
|
1118
|
-
updateAgent(this.
|
|
1125
|
+
await updateAgent(this.provider, agent.id, {
|
|
1119
1126
|
tmuxSession: sessionName,
|
|
1120
1127
|
status: 'idle',
|
|
1121
1128
|
worktreePath,
|
|
@@ -1134,9 +1141,8 @@ export class Scheduler {
|
|
|
1134
1141
|
* Checks requirements directly rather than through stories, so godmode stays
|
|
1135
1142
|
* active even after stories move from planned to in_progress/review/qa.
|
|
1136
1143
|
*/
|
|
1137
|
-
private isGodmodeActive(): boolean {
|
|
1138
|
-
const activeRequirements = queryAll<RequirementRow>(
|
|
1139
|
-
this.db,
|
|
1144
|
+
private async isGodmodeActive(): Promise<boolean> {
|
|
1145
|
+
const activeRequirements = await this.provider.queryAll<RequirementRow>(
|
|
1140
1146
|
`SELECT * FROM requirements WHERE status IN ('planning', 'planned', 'in_progress') AND godmode = 1`
|
|
1141
1147
|
);
|
|
1142
1148
|
return activeRequirements.length > 0;
|
|
@@ -1213,13 +1219,17 @@ export class Scheduler {
|
|
|
1213
1219
|
teamName: string,
|
|
1214
1220
|
repoPath: string
|
|
1215
1221
|
): Promise<AgentRow> {
|
|
1216
|
-
const existing = getAgentsByTeam(this.
|
|
1222
|
+
const existing = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
1223
|
+
a => a.type === 'intermediate'
|
|
1224
|
+
);
|
|
1217
1225
|
const index = existing.length + 1;
|
|
1218
1226
|
return this.spawnAgent('intermediate', teamId, teamName, repoPath, index);
|
|
1219
1227
|
}
|
|
1220
1228
|
|
|
1221
1229
|
private async spawnJunior(teamId: string, teamName: string, repoPath: string): Promise<AgentRow> {
|
|
1222
|
-
const existing = getAgentsByTeam(this.
|
|
1230
|
+
const existing = (await getAgentsByTeam(this.provider, teamId)).filter(
|
|
1231
|
+
a => a.type === 'junior'
|
|
1232
|
+
);
|
|
1223
1233
|
const index = existing.length + 1;
|
|
1224
1234
|
return this.spawnAgent('junior', teamId, teamName, repoPath, index);
|
|
1225
1235
|
}
|
|
@@ -1230,13 +1240,13 @@ export class Scheduler {
|
|
|
1230
1240
|
* If stories come from multiple requirements with different target branches,
|
|
1231
1241
|
* use the most common one. Defaults to 'main' if no requirement or target_branch is set.
|
|
1232
1242
|
*/
|
|
1233
|
-
private getTargetBranchForTeam(teamId: string): string {
|
|
1234
|
-
const stories = this.getTeamStories(teamId);
|
|
1243
|
+
private async getTargetBranchForTeam(teamId: string): Promise<string> {
|
|
1244
|
+
const stories = await this.getTeamStories(teamId);
|
|
1235
1245
|
|
|
1236
1246
|
const branchCounts = new Map<string, number>();
|
|
1237
1247
|
for (const story of stories) {
|
|
1238
1248
|
if (!story.requirement_id) continue;
|
|
1239
|
-
const requirement = getRequirementById(this.
|
|
1249
|
+
const requirement = await getRequirementById(this.provider, story.requirement_id);
|
|
1240
1250
|
if (!requirement?.target_branch) continue;
|
|
1241
1251
|
const count = branchCounts.get(requirement.target_branch) || 0;
|
|
1242
1252
|
branchCounts.set(requirement.target_branch, count + 1);
|
|
@@ -1256,9 +1266,8 @@ export class Scheduler {
|
|
|
1256
1266
|
return maxBranch;
|
|
1257
1267
|
}
|
|
1258
1268
|
|
|
1259
|
-
private getTeamStories(teamId: string): StoryRow[] {
|
|
1260
|
-
return queryAll<StoryRow>(
|
|
1261
|
-
this.db,
|
|
1269
|
+
private async getTeamStories(teamId: string): Promise<StoryRow[]> {
|
|
1270
|
+
return this.provider.queryAll<StoryRow>(
|
|
1262
1271
|
`
|
|
1263
1272
|
SELECT * FROM stories
|
|
1264
1273
|
WHERE team_id = ? AND status IN ('planned', 'estimated')
|
|
@@ -1284,8 +1293,8 @@ export class Scheduler {
|
|
|
1284
1293
|
errors: string[]
|
|
1285
1294
|
): Promise<void> {
|
|
1286
1295
|
const storyIds = stories.map(s => s.id);
|
|
1287
|
-
const requirementIds = getRequirementsNeedingFeatureBranch(
|
|
1288
|
-
this.
|
|
1296
|
+
const requirementIds = await getRequirementsNeedingFeatureBranch(
|
|
1297
|
+
this.provider,
|
|
1289
1298
|
storyIds,
|
|
1290
1299
|
this.config.hiveConfig
|
|
1291
1300
|
);
|
|
@@ -1294,13 +1303,18 @@ export class Scheduler {
|
|
|
1294
1303
|
|
|
1295
1304
|
// Find the repo path from the first team that has stories
|
|
1296
1305
|
// (all stories for a requirement typically belong to the same repo)
|
|
1297
|
-
const teams = getAllTeams(this.
|
|
1306
|
+
const teams = await getAllTeams(this.provider);
|
|
1298
1307
|
const repoPath = teams.length > 0 ? `${this.config.rootDir}/${teams[0].repo_path}` : null;
|
|
1299
1308
|
|
|
1300
1309
|
if (!repoPath) return;
|
|
1301
1310
|
|
|
1302
1311
|
for (const reqId of requirementIds) {
|
|
1303
|
-
const branch = await createRequirementFeatureBranch(
|
|
1312
|
+
const branch = await createRequirementFeatureBranch(
|
|
1313
|
+
this.provider,
|
|
1314
|
+
repoPath,
|
|
1315
|
+
reqId,
|
|
1316
|
+
this.saveFn
|
|
1317
|
+
);
|
|
1304
1318
|
|
|
1305
1319
|
if (!branch) {
|
|
1306
1320
|
errors.push(`Failed to create feature branch for requirement ${reqId}`);
|