hungry-ghost-hive 0.30.0 → 0.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/manager/agent-monitoring.d.ts +22 -0
- package/dist/cli/commands/manager/agent-monitoring.d.ts.map +1 -0
- package/dist/cli/commands/manager/agent-monitoring.js +161 -0
- package/dist/cli/commands/manager/agent-monitoring.js.map +1 -0
- package/dist/cli/commands/manager/escalation-handler.d.ts +9 -0
- package/dist/cli/commands/manager/escalation-handler.d.ts.map +1 -0
- package/dist/cli/commands/manager/escalation-handler.js +92 -0
- package/dist/cli/commands/manager/escalation-handler.js.map +1 -0
- package/dist/cli/commands/manager/handoff-recovery.d.ts +4 -0
- package/dist/cli/commands/manager/handoff-recovery.d.ts.map +1 -0
- package/dist/cli/commands/manager/handoff-recovery.js +188 -0
- package/dist/cli/commands/manager/handoff-recovery.js.map +1 -0
- package/dist/cli/commands/{manager.d.ts → manager/index.d.ts} +1 -1
- package/dist/cli/commands/manager/index.d.ts.map +1 -0
- package/dist/cli/commands/manager/index.js +576 -0
- package/dist/cli/commands/manager/index.js.map +1 -0
- package/dist/cli/commands/manager/index.test.d.ts +2 -0
- package/dist/cli/commands/manager/index.test.d.ts.map +1 -0
- package/dist/cli/commands/{manager.test.js → manager/index.test.js} +10 -10
- package/dist/cli/commands/manager/index.test.js.map +1 -0
- package/dist/cli/commands/manager/spin-down.d.ts +4 -0
- package/dist/cli/commands/manager/spin-down.d.ts.map +1 -0
- package/dist/cli/commands/manager/spin-down.js +111 -0
- package/dist/cli/commands/manager/spin-down.js.map +1 -0
- package/dist/cli/commands/manager/types.d.ts +57 -0
- package/dist/cli/commands/manager/types.d.ts.map +1 -0
- package/dist/cli/commands/manager/types.js +21 -0
- package/dist/cli/commands/manager/types.js.map +1 -0
- package/dist/cluster/adapters.d.ts +5 -0
- package/dist/cluster/adapters.d.ts.map +1 -0
- package/dist/cluster/adapters.js +401 -0
- package/dist/cluster/adapters.js.map +1 -0
- package/dist/cluster/events.d.ts +14 -0
- package/dist/cluster/events.d.ts.map +1 -0
- package/dist/cluster/events.js +151 -0
- package/dist/cluster/events.js.map +1 -0
- package/dist/cluster/replication.d.ts +4 -25
- package/dist/cluster/replication.d.ts.map +1 -1
- package/dist/cluster/replication.js +6 -943
- package/dist/cluster/replication.js.map +1 -1
- package/dist/cluster/story-merge.d.ts +3 -0
- package/dist/cluster/story-merge.d.ts.map +1 -0
- package/dist/cluster/story-merge.js +185 -0
- package/dist/cluster/story-merge.js.map +1 -0
- package/dist/cluster/sync.d.ts +5 -0
- package/dist/cluster/sync.d.ts.map +1 -0
- package/dist/cluster/sync.js +121 -0
- package/dist/cluster/sync.js.map +1 -0
- package/dist/cluster/types.d.ts +66 -0
- package/dist/cluster/types.d.ts.map +1 -0
- package/dist/cluster/types.js +3 -0
- package/dist/cluster/types.js.map +1 -0
- package/dist/cluster/utils.d.ts +16 -0
- package/dist/cluster/utils.d.ts.map +1 -0
- package/dist/cluster/utils.js +106 -0
- package/dist/cluster/utils.js.map +1 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +75 -223
- package/dist/db/client.js.map +1 -1
- package/dist/integrations/jira/sprints.d.ts +7 -4
- package/dist/integrations/jira/sprints.d.ts.map +1 -1
- package/dist/integrations/jira/sprints.js +49 -16
- package/dist/integrations/jira/sprints.js.map +1 -1
- package/dist/integrations/jira/sprints.test.js +55 -3
- package/dist/integrations/jira/sprints.test.js.map +1 -1
- package/dist/orchestrator/agent-selector.d.ts +12 -0
- package/dist/orchestrator/agent-selector.d.ts.map +1 -0
- package/dist/orchestrator/agent-selector.js +30 -0
- package/dist/orchestrator/agent-selector.js.map +1 -0
- package/dist/orchestrator/capacity-planner.d.ts +15 -0
- package/dist/orchestrator/capacity-planner.d.ts.map +1 -0
- package/dist/orchestrator/capacity-planner.js +56 -0
- package/dist/orchestrator/capacity-planner.js.map +1 -0
- package/dist/orchestrator/dependency-resolver.d.ts +19 -0
- package/dist/orchestrator/dependency-resolver.d.ts.map +1 -0
- package/dist/orchestrator/dependency-resolver.js +88 -0
- package/dist/orchestrator/dependency-resolver.js.map +1 -0
- package/dist/orchestrator/orphan-recovery.d.ts +7 -0
- package/dist/orchestrator/orphan-recovery.d.ts.map +1 -0
- package/dist/orchestrator/orphan-recovery.js +35 -0
- package/dist/orchestrator/orphan-recovery.js.map +1 -0
- package/dist/orchestrator/scheduler.d.ts +0 -42
- package/dist/orchestrator/scheduler.d.ts.map +1 -1
- package/dist/orchestrator/scheduler.js +22 -208
- package/dist/orchestrator/scheduler.js.map +1 -1
- package/dist/orchestrator/scheduler.test.js +91 -147
- package/dist/orchestrator/scheduler.test.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/index.ts +1 -1
- package/src/cli/commands/manager/agent-monitoring.ts +232 -0
- package/src/cli/commands/manager/escalation-handler.ts +143 -0
- package/src/cli/commands/manager/handoff-recovery.ts +270 -0
- package/src/cli/commands/{manager.test.ts → manager/index.test.ts} +9 -9
- package/src/cli/commands/manager/index.ts +760 -0
- package/src/cli/commands/manager/spin-down.ts +167 -0
- package/src/cli/commands/manager/types.ts +69 -0
- package/src/cluster/adapters.ts +459 -0
- package/src/cluster/events.ts +234 -0
- package/src/cluster/replication.ts +22 -1279
- package/src/cluster/story-merge.ts +235 -0
- package/src/cluster/sync.ts +170 -0
- package/src/cluster/types.ts +96 -0
- package/src/cluster/utils.ts +139 -0
- package/src/db/client.ts +74 -237
- package/src/db/migrations/002-add-agent-model.sql +5 -0
- package/src/db/migrations/003-fix-pull-requests.sql +41 -0
- package/src/db/migrations/004-add-messages.sql +15 -0
- package/src/db/migrations/008-add-godmode.sql +5 -0
- package/src/db/migrations/009-add-pr-sync-indexes.sql +6 -0
- package/src/db/migrations/010-add-target-branch.sql +5 -0
- package/src/db/migrations/011-generic-integration-fields.sql +36 -0
- package/src/db/migrations/012-sprint-tracking.sql +9 -0
- package/src/integrations/jira/sprints.test.ts +61 -3
- package/src/integrations/jira/sprints.ts +51 -16
- package/src/orchestrator/agent-selector.ts +40 -0
- package/src/orchestrator/capacity-planner.ts +75 -0
- package/src/orchestrator/dependency-resolver.ts +109 -0
- package/src/orchestrator/orphan-recovery.ts +41 -0
- package/src/orchestrator/scheduler.test.ts +142 -156
- package/src/orchestrator/scheduler.ts +24 -256
- package/dist/cli/commands/manager.d.ts.map +0 -1
- package/dist/cli/commands/manager.js +0 -1105
- package/dist/cli/commands/manager.js.map +0 -1
- package/dist/cli/commands/manager.test.d.ts +0 -2
- package/dist/cli/commands/manager.test.d.ts.map +0 -1
- package/dist/cli/commands/manager.test.js.map +0 -1
- package/src/cli/commands/manager.ts +0 -1552
|
@@ -10,7 +10,7 @@ export { configCommand } from './config.js';
|
|
|
10
10
|
export { escalationsCommand } from './escalations.js';
|
|
11
11
|
export { initCommand } from './init.js';
|
|
12
12
|
export { jiraCommand } from './jira.js';
|
|
13
|
-
export { managerCommand } from './manager.js';
|
|
13
|
+
export { managerCommand } from './manager/index.js';
|
|
14
14
|
export { msgCommand } from './msg.js';
|
|
15
15
|
export { myStoriesCommand } from './my-stories.js';
|
|
16
16
|
export { nukeCommand } from './nuke.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -11,7 +11,7 @@ export { configCommand } from './config.js';
|
|
|
11
11
|
export { escalationsCommand } from './escalations.js';
|
|
12
12
|
export { initCommand } from './init.js';
|
|
13
13
|
export { jiraCommand } from './jira.js';
|
|
14
|
-
export { managerCommand } from './manager.js';
|
|
14
|
+
export { managerCommand } from './manager/index.js';
|
|
15
15
|
export { msgCommand } from './msg.js';
|
|
16
16
|
export { myStoriesCommand } from './my-stories.js';
|
|
17
17
|
export { nukeCommand } from './nuke.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HiveConfig } from '../../../config/schema.js';
|
|
2
|
+
import type { getAllAgents } from '../../../db/queries/agents.js';
|
|
3
|
+
import { getStateDetector, type StateDetectionResult } from '../../../state-detectors/index.js';
|
|
4
|
+
import { AgentState } from '../../../state-detectors/types.js';
|
|
5
|
+
import { captureTmuxPane, sendToTmuxSession } from '../../../tmux/manager.js';
|
|
6
|
+
import { buildAutoRecoveryReminder, type CLITool } from '../../../utils/cli-commands.js';
|
|
7
|
+
import type { AgentStateTracking, ManagerCheckContext, MessageRow } from './types.js';
|
|
8
|
+
export declare const agentStates: Map<string, AgentStateTracking>;
|
|
9
|
+
export declare const stateDetectors: Record<CLITool, ReturnType<typeof getStateDetector>>;
|
|
10
|
+
export declare function detectAgentState(output: string, cliTool: CLITool): StateDetectionResult;
|
|
11
|
+
export declare function describeAgentState(state: AgentState, cliTool: CLITool): string;
|
|
12
|
+
export declare function getAgentSafetyMode(config: HiveConfig, agent: ReturnType<typeof getAllAgents>[number] | undefined): 'safe' | 'unsafe';
|
|
13
|
+
export declare function enforceBypassMode(sessionName: string, output: string, agentCliTool: CLITool, safetyMode: 'safe' | 'unsafe'): Promise<void>;
|
|
14
|
+
export declare function updateAgentStateTracking(sessionName: string, stateResult: StateDetectionResult, now: number): void;
|
|
15
|
+
export declare function handlePermissionPrompt(ctx: ManagerCheckContext, sessionName: string, stateResult: StateDetectionResult, safetyMode: 'safe' | 'unsafe'): Promise<boolean>;
|
|
16
|
+
export declare function handlePlanApproval(sessionName: string, stateResult: StateDetectionResult, now: number, agentCliTool: CLITool, safetyMode: 'safe' | 'unsafe'): Promise<void>;
|
|
17
|
+
export declare function getAgentType(sessionName: string): 'senior' | 'intermediate' | 'junior' | 'qa' | 'unknown';
|
|
18
|
+
export declare function nudgeAgent(_root: string, sessionName: string, customMessage?: string, agentType?: string, reason?: string, agentCliTool?: CLITool): Promise<void>;
|
|
19
|
+
export declare function forwardMessages(sessionName: string, messages: MessageRow[], cliTool?: CLITool): Promise<void>;
|
|
20
|
+
export { AgentState, buildAutoRecoveryReminder, captureTmuxPane, sendToTmuxSession };
|
|
21
|
+
export type { CLITool, StateDetectionResult };
|
|
22
|
+
//# sourceMappingURL=agent-monitoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-monitoring.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/agent-monitoring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAEL,eAAe,EAIf,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,yBAAyB,EAEzB,KAAK,OAAO,EACb,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAItF,eAAO,MAAM,WAAW,iCAAwC,CAAC;AAEjE,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAI/E,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,oBAAoB,CAEvF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAE9E;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,GACzD,MAAM,GAAG,QAAQ,CAGnB;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAC5B,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,oBAAoB,EACjC,GAAG,EAAE,MAAM,GACV,IAAI,CAaN;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,mBAAmB,EACxB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,oBAAoB,EACjC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAC5B,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAED,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,oBAAoB,EACjC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,OAAO,EACrB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAC5B,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAClB,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAMzD;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Cf;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,GAAE,OAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;AACrF,YAAY,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Licensed under the Hungry Ghost Hive License. See LICENSE.
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { createLog } from '../../../db/queries/logs.js';
|
|
4
|
+
import { getStateDetector } from '../../../state-detectors/index.js';
|
|
5
|
+
import { AgentState } from '../../../state-detectors/types.js';
|
|
6
|
+
import { autoApprovePermission, captureTmuxPane, forceBypassMode, sendEnterToTmuxSession, sendMessageWithConfirmation, sendToTmuxSession, } from '../../../tmux/manager.js';
|
|
7
|
+
import { buildAutoRecoveryReminder, getAvailableCommands, } from '../../../utils/cli-commands.js';
|
|
8
|
+
import { BYPASS_MODE_MAX_RETRIES, MESSAGE_FORWARD_DELAY_MS, POST_NUDGE_DELAY_MS } from './types.js';
|
|
9
|
+
// In-memory state tracking per agent session
|
|
10
|
+
export const agentStates = new Map();
|
|
11
|
+
export const stateDetectors = {
|
|
12
|
+
claude: getStateDetector('claude'),
|
|
13
|
+
codex: getStateDetector('codex'),
|
|
14
|
+
gemini: getStateDetector('gemini'),
|
|
15
|
+
};
|
|
16
|
+
export function detectAgentState(output, cliTool) {
|
|
17
|
+
return stateDetectors[cliTool].detectState(output);
|
|
18
|
+
}
|
|
19
|
+
export function describeAgentState(state, cliTool) {
|
|
20
|
+
return stateDetectors[cliTool].getStateDescription(state);
|
|
21
|
+
}
|
|
22
|
+
export function getAgentSafetyMode(config, agent) {
|
|
23
|
+
if (!agent)
|
|
24
|
+
return 'unsafe';
|
|
25
|
+
return config.models[agent.type].safety_mode;
|
|
26
|
+
}
|
|
27
|
+
export async function enforceBypassMode(sessionName, output, agentCliTool, safetyMode) {
|
|
28
|
+
if (safetyMode === 'safe') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const needsBypassEnforcement = output.toLowerCase().includes('plan mode on') ||
|
|
32
|
+
output.toLowerCase().includes('safe mode on') ||
|
|
33
|
+
output.match(/permission.*required/i) ||
|
|
34
|
+
output.match(/approve.*\[y\/n\]/i);
|
|
35
|
+
if (needsBypassEnforcement) {
|
|
36
|
+
const enforced = await forceBypassMode(sessionName, agentCliTool, BYPASS_MODE_MAX_RETRIES);
|
|
37
|
+
if (enforced) {
|
|
38
|
+
console.log(chalk.yellow(` Enforced bypass mode on ${sessionName}`));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log(chalk.red(` Failed to enforce bypass mode on ${sessionName}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function updateAgentStateTracking(sessionName, stateResult, now) {
|
|
46
|
+
const trackedState = agentStates.get(sessionName);
|
|
47
|
+
if (!trackedState) {
|
|
48
|
+
agentStates.set(sessionName, {
|
|
49
|
+
lastState: stateResult.state,
|
|
50
|
+
lastStateChangeTime: now,
|
|
51
|
+
lastNudgeTime: 0,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else if (trackedState.lastState !== stateResult.state) {
|
|
55
|
+
trackedState.lastState = stateResult.state;
|
|
56
|
+
trackedState.lastStateChangeTime = now;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function handlePermissionPrompt(ctx, sessionName, stateResult, safetyMode) {
|
|
60
|
+
if (stateResult.state === AgentState.PERMISSION_REQUIRED && safetyMode === 'unsafe') {
|
|
61
|
+
const approved = await autoApprovePermission(sessionName);
|
|
62
|
+
if (approved) {
|
|
63
|
+
createLog(ctx.db.db, {
|
|
64
|
+
agentId: 'manager',
|
|
65
|
+
eventType: 'STORY_PROGRESS_UPDATE',
|
|
66
|
+
message: `Auto-approved permission prompt for ${sessionName}`,
|
|
67
|
+
metadata: {
|
|
68
|
+
session_name: sessionName,
|
|
69
|
+
detected_state: stateResult.state,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
ctx.db.save();
|
|
73
|
+
console.log(chalk.green(` AUTO-APPROVED: ${sessionName} permission prompt`));
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
export async function handlePlanApproval(sessionName, stateResult, now, agentCliTool, safetyMode) {
|
|
80
|
+
if (stateResult.state === AgentState.PLAN_APPROVAL && safetyMode === 'unsafe') {
|
|
81
|
+
const restored = await forceBypassMode(sessionName, agentCliTool);
|
|
82
|
+
if (restored) {
|
|
83
|
+
console.log(chalk.green(` BYPASS MODE RESTORED: ${sessionName} cycled out of plan mode`));
|
|
84
|
+
const tracked = agentStates.get(sessionName);
|
|
85
|
+
if (tracked) {
|
|
86
|
+
tracked.lastState = AgentState.IDLE_AT_PROMPT;
|
|
87
|
+
tracked.lastStateChangeTime = now;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export function getAgentType(sessionName) {
|
|
93
|
+
if (sessionName.includes('-senior-'))
|
|
94
|
+
return 'senior';
|
|
95
|
+
if (sessionName.includes('-intermediate-'))
|
|
96
|
+
return 'intermediate';
|
|
97
|
+
if (sessionName.includes('-junior-'))
|
|
98
|
+
return 'junior';
|
|
99
|
+
if (sessionName.includes('-qa-'))
|
|
100
|
+
return 'qa';
|
|
101
|
+
return 'unknown';
|
|
102
|
+
}
|
|
103
|
+
export async function nudgeAgent(_root, sessionName, customMessage, agentType, reason, agentCliTool) {
|
|
104
|
+
if (customMessage) {
|
|
105
|
+
await sendToTmuxSession(sessionName, customMessage);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const type = agentType || getAgentType(sessionName);
|
|
109
|
+
const cliTool = agentCliTool || 'claude';
|
|
110
|
+
const commands = getAvailableCommands(cliTool);
|
|
111
|
+
// Build contextual nudge message based on agent type and reason
|
|
112
|
+
let nudge;
|
|
113
|
+
switch (type) {
|
|
114
|
+
case 'qa':
|
|
115
|
+
nudge = `# You are a QA agent. Check for PRs to review:
|
|
116
|
+
# ${commands.queueCheck()}
|
|
117
|
+
# If there are PRs, review them with: hive pr review <pr-id>`;
|
|
118
|
+
break;
|
|
119
|
+
case 'senior':
|
|
120
|
+
nudge = `# You are a Senior developer. Continue with your assigned stories.
|
|
121
|
+
# Check your work: # ${commands.getMyStories(sessionName)}
|
|
122
|
+
# If no active stories, check for available work: hive stories list --status planned`;
|
|
123
|
+
break;
|
|
124
|
+
case 'intermediate':
|
|
125
|
+
case 'junior':
|
|
126
|
+
nudge = `# Continue with your assigned story. Check status:
|
|
127
|
+
# ${commands.getMyStories(sessionName)}
|
|
128
|
+
# If stuck, ask your Senior for help via: hive msg send hive-senior-<team> "your question"
|
|
129
|
+
# If done, submit PR: hive pr submit -b <branch> -s <story-id> --from ${sessionName}`;
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
nudge = `# Check current status and continue working:
|
|
133
|
+
hive status`;
|
|
134
|
+
}
|
|
135
|
+
// Add reason context if provided
|
|
136
|
+
if (reason) {
|
|
137
|
+
nudge = `# Manager detected: ${reason}\n${nudge}`;
|
|
138
|
+
}
|
|
139
|
+
await sendToTmuxSession(sessionName, nudge);
|
|
140
|
+
// Also send Enter to ensure prompt is activated
|
|
141
|
+
await new Promise(resolve => setTimeout(resolve, POST_NUDGE_DELAY_MS));
|
|
142
|
+
await sendEnterToTmuxSession(sessionName);
|
|
143
|
+
}
|
|
144
|
+
export async function forwardMessages(sessionName, messages, cliTool = 'claude') {
|
|
145
|
+
const commands = getAvailableCommands(cliTool);
|
|
146
|
+
for (const msg of messages) {
|
|
147
|
+
const notification = `# New message from ${msg.from_session}${msg.subject ? ` - ${msg.subject}` : ''}
|
|
148
|
+
# ${msg.body}
|
|
149
|
+
# Reply with: # ${commands.msgReply(msg.id, 'your response', sessionName)}`;
|
|
150
|
+
// Send with delivery confirmation - wait for message to appear in session output before proceeding
|
|
151
|
+
const delivered = await sendMessageWithConfirmation(sessionName, notification);
|
|
152
|
+
if (!delivered) {
|
|
153
|
+
console.warn(`Failed to confirm delivery of message ${msg.id} to ${sessionName} after retries`);
|
|
154
|
+
// Continue to next message even if delivery not confirmed to avoid blocking the manager
|
|
155
|
+
}
|
|
156
|
+
// Small delay between messages to allow recipient time to read
|
|
157
|
+
await new Promise(resolve => setTimeout(resolve, MESSAGE_FORWARD_DELAY_MS));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export { AgentState, buildAutoRecoveryReminder, captureTmuxPane, sendToTmuxSession };
|
|
161
|
+
//# sourceMappingURL=agent-monitoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-monitoring.js","sourceRoot":"","sources":["../../../../src/cli/commands/manager/agent-monitoring.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAA6B,MAAM,mCAAmC,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,yBAAyB,EACzB,oBAAoB,GAErB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpG,6CAA6C;AAC7C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEjE,MAAM,CAAC,MAAM,cAAc,GAAyD;IAClF,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAClC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC;IAChC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC;CACnC,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAgB;IAC/D,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAiB,EAAE,OAAgB;IACpE,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAkB,EAClB,KAA0D;IAE1D,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,MAAc,EACd,YAAqB,EACrB,UAA6B;IAE7B,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,MAAM,sBAAsB,GAC1B,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC7C,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAErC,IAAI,sBAAsB,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,YAAY,EAAE,uBAAuB,CAAC,CAAC;QAC3F,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,6BAA6B,WAAW,EAAE,CAAC,CAAC,CAAC;QACxE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sCAAsC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,WAAiC,EACjC,GAAW;IAEX,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAElD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE;YAC3B,SAAS,EAAE,WAAW,CAAC,KAAK;YAC5B,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,CAAC;SACjB,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,YAAY,CAAC,SAAS,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;QACxD,YAAY,CAAC,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC;QAC3C,YAAY,CAAC,mBAAmB,GAAG,GAAG,CAAC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,GAAwB,EACxB,WAAmB,EACnB,WAAiC,EACjC,UAA6B;IAE7B,IAAI,WAAW,CAAC,KAAK,KAAK,UAAU,CAAC,mBAAmB,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QACpF,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,uBAAuB;gBAClC,OAAO,EAAE,uCAAuC,WAAW,EAAE;gBAC7D,QAAQ,EAAE;oBACR,YAAY,EAAE,WAAW;oBACzB,cAAc,EAAE,WAAW,CAAC,KAAK;iBAClC;aACF,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,WAAW,oBAAoB,CAAC,CAAC,CAAC;YAC9E,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,WAAiC,EACjC,GAAW,EACX,YAAqB,EACrB,UAA6B;IAE7B,IAAI,WAAW,CAAC,KAAK,KAAK,UAAU,CAAC,aAAa,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC9E,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAClE,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2BAA2B,WAAW,0BAA0B,CAAC,CAAC,CAAC;YAC3F,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,cAAc,CAAC;gBAC9C,OAAO,CAAC,mBAAmB,GAAG,GAAG,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,WAAmB;IAEnB,IAAI,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC;IACtD,IAAI,WAAW,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAAE,OAAO,cAAc,CAAC;IAClE,IAAI,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC;IACtD,IAAI,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAa,EACb,WAAmB,EACnB,aAAsB,EACtB,SAAkB,EAClB,MAAe,EACf,YAAsB;IAEtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,iBAAiB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,YAAY,IAAK,QAAoB,CAAC;IACtD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAE/C,gEAAgE;IAChE,IAAI,KAAa,CAAC;IAClB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,IAAI;YACP,KAAK,GAAG;IACV,QAAQ,CAAC,UAAU,EAAE;6DACoC,CAAC;YACxD,MAAM;QACR,KAAK,QAAQ;YACX,KAAK,GAAG;uBACS,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC;qFAC4B,CAAC;YAChF,MAAM;QACR,KAAK,cAAc,CAAC;QACpB,KAAK,QAAQ;YACX,KAAK,GAAG;IACV,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC;;wEAEkC,WAAW,EAAE,CAAC;YAChF,MAAM;QACR;YACE,KAAK,GAAG;YACF,CAAC;IACX,CAAC;IAED,iCAAiC;IACjC,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,GAAG,uBAAuB,MAAM,KAAK,KAAK,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAE5C,gDAAgD;IAChD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACvE,MAAM,sBAAsB,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,QAAsB,EACtB,UAAmB,QAAQ;IAE3B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,sBAAsB,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;IACpG,GAAG,CAAC,IAAI;kBACM,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,CAAC;QAExE,mGAAmG;QACnG,MAAM,SAAS,GAAG,MAAM,2BAA2B,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAE/E,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,yCAAyC,GAAG,CAAC,EAAE,OAAO,WAAW,gBAAgB,CAClF,CAAC;YACF,wFAAwF;QAC1F,CAAC;QAED,+DAA+D;QAC/D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { getAllAgents } from '../../../db/queries/agents.js';
|
|
2
|
+
import { type CLITool } from './agent-monitoring.js';
|
|
3
|
+
import type { ManagerCheckContext } from './types.js';
|
|
4
|
+
export declare function handleEscalationAndNudge(ctx: ManagerCheckContext, sessionName: string, agent: ReturnType<typeof getAllAgents>[number] | undefined, stateResult: {
|
|
5
|
+
state: import('../../../state-detectors/types.js').AgentState;
|
|
6
|
+
isWaiting: boolean;
|
|
7
|
+
needsHuman: boolean;
|
|
8
|
+
}, agentCliTool: CLITool, now: number): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=escalation-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation-handler.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/escalation-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAQlE,OAAO,EAUL,KAAK,OAAO,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,mBAAmB,EACxB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,EAC1D,WAAW,EAAE;IACX,KAAK,EAAE,OAAO,mCAAmC,EAAE,UAAU,CAAC;IAC9D,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB,EACD,YAAY,EAAE,OAAO,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAyGf"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Licensed under the Hungry Ghost Hive License. See LICENSE.
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { createEscalation, getActiveEscalationsForAgent, getRecentEscalationsForAgent, updateEscalation, } from '../../../db/queries/escalations.js';
|
|
4
|
+
import { createLog } from '../../../db/queries/logs.js';
|
|
5
|
+
import { AgentState, agentStates, buildAutoRecoveryReminder, captureTmuxPane, describeAgentState, detectAgentState, getAgentType, nudgeAgent, sendToTmuxSession, } from './agent-monitoring.js';
|
|
6
|
+
import { RECENT_ESCALATION_LOOKBACK_MINUTES, TMUX_CAPTURE_LINES } from './types.js';
|
|
7
|
+
export async function handleEscalationAndNudge(ctx, sessionName, agent, stateResult, agentCliTool, now) {
|
|
8
|
+
const waitingInfo = {
|
|
9
|
+
isWaiting: stateResult.isWaiting,
|
|
10
|
+
needsHuman: stateResult.needsHuman,
|
|
11
|
+
reason: stateResult.needsHuman
|
|
12
|
+
? describeAgentState(stateResult.state, agentCliTool)
|
|
13
|
+
: undefined,
|
|
14
|
+
};
|
|
15
|
+
const hasRecentEscalation = ctx.escalatedSessions.has(sessionName) ||
|
|
16
|
+
getRecentEscalationsForAgent(ctx.db.db, sessionName, RECENT_ESCALATION_LOOKBACK_MINUTES)
|
|
17
|
+
.length > 0;
|
|
18
|
+
if (waitingInfo.needsHuman && !hasRecentEscalation) {
|
|
19
|
+
// Create escalation for human attention
|
|
20
|
+
const storyId = agent?.current_story_id || null;
|
|
21
|
+
const escalation = createEscalation(ctx.db.db, {
|
|
22
|
+
storyId,
|
|
23
|
+
fromAgentId: sessionName,
|
|
24
|
+
toAgentId: null,
|
|
25
|
+
reason: `Approval required: ${waitingInfo.reason || 'Unknown question'}`,
|
|
26
|
+
});
|
|
27
|
+
createLog(ctx.db.db, {
|
|
28
|
+
agentId: 'manager',
|
|
29
|
+
storyId,
|
|
30
|
+
eventType: 'ESCALATION_CREATED',
|
|
31
|
+
status: 'error',
|
|
32
|
+
message: `${sessionName} requires human approval: ${waitingInfo.reason || 'Unknown question'}`,
|
|
33
|
+
metadata: {
|
|
34
|
+
escalation_id: escalation.id,
|
|
35
|
+
session_name: sessionName,
|
|
36
|
+
detected_state: stateResult.state,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
ctx.db.save();
|
|
40
|
+
ctx.counters.escalationsCreated++;
|
|
41
|
+
ctx.escalatedSessions.add(sessionName);
|
|
42
|
+
const reminder = buildAutoRecoveryReminder(sessionName, agentCliTool);
|
|
43
|
+
await sendToTmuxSession(sessionName, reminder);
|
|
44
|
+
console.log(chalk.red(` ESCALATION: ${sessionName} needs human input`));
|
|
45
|
+
}
|
|
46
|
+
else if (!waitingInfo.isWaiting && !waitingInfo.needsHuman) {
|
|
47
|
+
// Agent recovered - auto-resolve active escalations
|
|
48
|
+
const activeEscalations = getActiveEscalationsForAgent(ctx.db.db, sessionName);
|
|
49
|
+
for (const escalation of activeEscalations) {
|
|
50
|
+
updateEscalation(ctx.db.db, escalation.id, {
|
|
51
|
+
status: 'resolved',
|
|
52
|
+
resolution: `Agent recovered: no longer in waiting state`,
|
|
53
|
+
});
|
|
54
|
+
ctx.counters.escalationsResolved++;
|
|
55
|
+
}
|
|
56
|
+
if (activeEscalations.length > 0) {
|
|
57
|
+
createLog(ctx.db.db, {
|
|
58
|
+
agentId: 'manager',
|
|
59
|
+
eventType: 'ESCALATION_RESOLVED',
|
|
60
|
+
message: `${sessionName} recovered and manager auto-resolved ${activeEscalations.length} escalation(s)`,
|
|
61
|
+
metadata: {
|
|
62
|
+
session_name: sessionName,
|
|
63
|
+
resolved_count: activeEscalations.length,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
ctx.db.save();
|
|
67
|
+
console.log(chalk.green(` AUTO-RESOLVED: ${sessionName} recovered, resolved ${activeEscalations.length} escalation(s)`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (waitingInfo.isWaiting && stateResult.state !== AgentState.THINKING) {
|
|
71
|
+
// Agent idle/waiting - check if we should nudge
|
|
72
|
+
const currentTrackedState = agentStates.get(sessionName);
|
|
73
|
+
if (currentTrackedState) {
|
|
74
|
+
const timeSinceStateChange = now - currentTrackedState.lastStateChangeTime;
|
|
75
|
+
const timeSinceLastNudge = now - currentTrackedState.lastNudgeTime;
|
|
76
|
+
if (timeSinceStateChange > ctx.config.manager.stuck_threshold_ms &&
|
|
77
|
+
timeSinceLastNudge > ctx.config.manager.nudge_cooldown_ms) {
|
|
78
|
+
const recheckOutput = await captureTmuxPane(sessionName, TMUX_CAPTURE_LINES);
|
|
79
|
+
const recheckState = detectAgentState(recheckOutput, agentCliTool);
|
|
80
|
+
if (recheckState.isWaiting &&
|
|
81
|
+
!recheckState.needsHuman &&
|
|
82
|
+
recheckState.state !== AgentState.THINKING) {
|
|
83
|
+
const agentType = getAgentType(sessionName);
|
|
84
|
+
await nudgeAgent(ctx.root, sessionName, undefined, agentType, waitingInfo.reason, agentCliTool);
|
|
85
|
+
currentTrackedState.lastNudgeTime = now;
|
|
86
|
+
ctx.counters.nudged++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=escalation-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation-handler.js","sourceRoot":"","sources":["../../../../src/cli/commands/manager/escalation-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ManagerCheckContext, PlanningHandoffTracking } from './types.js';
|
|
2
|
+
export declare const planningHandoffState: Map<string, PlanningHandoffTracking>;
|
|
3
|
+
export declare function handleStalledPlanningHandoff(ctx: ManagerCheckContext): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=handoff-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-recovery.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/handoff-recovery.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAI/E,eAAO,MAAM,oBAAoB,sCAA6C,CAAC;AAwJ/E,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoG1F"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Licensed under the Hungry Ghost Hive License. See LICENSE.
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { queryAll, withTransaction } from '../../../db/client.js';
|
|
4
|
+
import { getTechLead } from '../../../db/queries/agents.js';
|
|
5
|
+
import { createEscalation } from '../../../db/queries/escalations.js';
|
|
6
|
+
import { createLog } from '../../../db/queries/logs.js';
|
|
7
|
+
import { updateRequirement } from '../../../db/queries/requirements.js';
|
|
8
|
+
import { getStoriesByStatus, updateStory } from '../../../db/queries/stories.js';
|
|
9
|
+
import { syncStatusToJira } from '../../../integrations/jira/transitions.js';
|
|
10
|
+
import { isTmuxSessionRunning } from '../../../tmux/manager.js';
|
|
11
|
+
import { nudgeAgent } from './agent-monitoring.js';
|
|
12
|
+
import { PROACTIVE_HANDOFF_RETRY_DELAY_MS } from './types.js';
|
|
13
|
+
// In-memory state tracking for planning handoff dedup
|
|
14
|
+
export const planningHandoffState = new Map();
|
|
15
|
+
function getRequirementKey(requirementId) {
|
|
16
|
+
return requirementId || '__unscoped__';
|
|
17
|
+
}
|
|
18
|
+
function formatRequirementLabel(requirementId) {
|
|
19
|
+
return requirementId || 'unscoped stories';
|
|
20
|
+
}
|
|
21
|
+
function getLatestStoryUpdateMs(stories) {
|
|
22
|
+
let latestMs = 0;
|
|
23
|
+
for (const story of stories) {
|
|
24
|
+
const updatedAtMs = Date.parse(story.updated_at);
|
|
25
|
+
if (!Number.isNaN(updatedAtMs) && updatedAtMs > latestMs) {
|
|
26
|
+
latestMs = updatedAtMs;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return latestMs;
|
|
30
|
+
}
|
|
31
|
+
function getActivePipelineCountForRequirement(db, requirementId) {
|
|
32
|
+
const statuses = `'planned', 'in_progress', 'review', 'qa', 'qa_failed', 'pr_submitted'`;
|
|
33
|
+
if (requirementId) {
|
|
34
|
+
const result = queryAll(db, `
|
|
35
|
+
SELECT COUNT(*) as count
|
|
36
|
+
FROM stories
|
|
37
|
+
WHERE requirement_id = ?
|
|
38
|
+
AND status IN (${statuses})
|
|
39
|
+
`, [requirementId]);
|
|
40
|
+
return result[0]?.count || 0;
|
|
41
|
+
}
|
|
42
|
+
const result = queryAll(db, `
|
|
43
|
+
SELECT COUNT(*) as count
|
|
44
|
+
FROM stories
|
|
45
|
+
WHERE requirement_id IS NULL
|
|
46
|
+
AND status IN (${statuses})
|
|
47
|
+
`);
|
|
48
|
+
return result[0]?.count || 0;
|
|
49
|
+
}
|
|
50
|
+
async function nudgeTechLeadForStalledHandoff(ctx, requirementId, estimatedCount) {
|
|
51
|
+
const techLead = getTechLead(ctx.db.db);
|
|
52
|
+
const sessionName = techLead?.tmux_session || 'hive-tech-lead';
|
|
53
|
+
if (!(await isTmuxSessionRunning(sessionName))) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const requirementLabel = formatRequirementLabel(requirementId);
|
|
57
|
+
const nudgeMessage = `# Manager intervention: planning handoff appears stalled for ${requirementLabel} (${estimatedCount} estimated story/ies).
|
|
58
|
+
# Please move stories from estimated -> planned and run:
|
|
59
|
+
# hive assign`;
|
|
60
|
+
const cliTool = (techLead?.cli_tool || 'claude');
|
|
61
|
+
await nudgeAgent(ctx.root, sessionName, nudgeMessage, undefined, undefined, cliTool);
|
|
62
|
+
ctx.counters.nudged++;
|
|
63
|
+
createLog(ctx.db.db, {
|
|
64
|
+
agentId: 'manager',
|
|
65
|
+
eventType: 'STORY_PROGRESS_UPDATE',
|
|
66
|
+
message: `Nudged Tech Lead to unblock stalled planning handoff for ${requirementLabel}`,
|
|
67
|
+
metadata: { requirement_id: requirementId, estimated_count: estimatedCount },
|
|
68
|
+
});
|
|
69
|
+
ctx.db.save();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
async function promoteEstimatedStoriesToPlanned(ctx, requirementId, stories, reason) {
|
|
73
|
+
let promoted = 0;
|
|
74
|
+
await withTransaction(ctx.db.db, () => {
|
|
75
|
+
for (const story of stories) {
|
|
76
|
+
updateStory(ctx.db.db, story.id, { status: 'planned' });
|
|
77
|
+
promoted++;
|
|
78
|
+
}
|
|
79
|
+
if (requirementId) {
|
|
80
|
+
updateRequirement(ctx.db.db, requirementId, { status: 'planned' });
|
|
81
|
+
}
|
|
82
|
+
createLog(ctx.db.db, {
|
|
83
|
+
agentId: 'manager',
|
|
84
|
+
eventType: 'PLANNING_COMPLETED',
|
|
85
|
+
message: `Auto-promoted ${promoted} estimated story/ies to planned (${reason})`,
|
|
86
|
+
metadata: { requirement_id: requirementId, promoted, reason },
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
ctx.db.save();
|
|
90
|
+
// Sync status changes to Jira
|
|
91
|
+
for (const story of stories) {
|
|
92
|
+
await syncStatusToJira(ctx.root, ctx.db.db, story.id, 'planned');
|
|
93
|
+
}
|
|
94
|
+
return promoted;
|
|
95
|
+
}
|
|
96
|
+
async function runAutoAssignmentAfterHandoff(ctx) {
|
|
97
|
+
await ctx.scheduler.checkScaling();
|
|
98
|
+
await ctx.scheduler.checkMergeQueue();
|
|
99
|
+
const result = await ctx.scheduler.assignStories();
|
|
100
|
+
ctx.db.save();
|
|
101
|
+
ctx.counters.handoffAutoAssigned += result.assigned;
|
|
102
|
+
if (result.assigned > 0) {
|
|
103
|
+
console.log(chalk.green(` Auto-assigned ${result.assigned} story(ies) after handoff recovery`));
|
|
104
|
+
}
|
|
105
|
+
if (result.errors.length > 0) {
|
|
106
|
+
const reason = `Manager auto-handoff recovered planning but assignment still has errors: ${result.errors.join('; ')}`;
|
|
107
|
+
createEscalation(ctx.db.db, { reason });
|
|
108
|
+
createLog(ctx.db.db, {
|
|
109
|
+
agentId: 'manager',
|
|
110
|
+
eventType: 'ESCALATION_CREATED',
|
|
111
|
+
status: 'error',
|
|
112
|
+
message: reason,
|
|
113
|
+
});
|
|
114
|
+
ctx.db.save();
|
|
115
|
+
console.log(chalk.red(` Auto-assignment errors after handoff recovery (${result.errors.length})`));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export async function handleStalledPlanningHandoff(ctx) {
|
|
119
|
+
const estimatedStories = getStoriesByStatus(ctx.db.db, 'estimated');
|
|
120
|
+
if (estimatedStories.length === 0) {
|
|
121
|
+
planningHandoffState.clear();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const groupedStories = new Map();
|
|
125
|
+
for (const story of estimatedStories) {
|
|
126
|
+
const key = getRequirementKey(story.requirement_id);
|
|
127
|
+
const existing = groupedStories.get(key);
|
|
128
|
+
if (existing) {
|
|
129
|
+
existing.stories.push(story);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
groupedStories.set(key, { requirementId: story.requirement_id, stories: [story] });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const activeKeys = new Set();
|
|
136
|
+
let promotedTotal = 0;
|
|
137
|
+
let shouldRunAutoAssignment = false;
|
|
138
|
+
const nowMs = Date.now();
|
|
139
|
+
const stallThresholdMs = Math.max(1, ctx.config.manager.stuck_threshold_ms);
|
|
140
|
+
for (const [key, group] of groupedStories) {
|
|
141
|
+
activeKeys.add(key);
|
|
142
|
+
const latestUpdateMs = getLatestStoryUpdateMs(group.stories);
|
|
143
|
+
if (latestUpdateMs === 0 || nowMs - latestUpdateMs < stallThresholdMs) {
|
|
144
|
+
planningHandoffState.delete(key);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const activePipelineCount = getActivePipelineCountForRequirement(ctx.db.db, group.requirementId);
|
|
148
|
+
if (activePipelineCount > 0) {
|
|
149
|
+
planningHandoffState.delete(key);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const signature = `${group.stories.length}:${latestUpdateMs}`;
|
|
153
|
+
const previous = planningHandoffState.get(key);
|
|
154
|
+
// First intervention: nudge Tech Lead.
|
|
155
|
+
if (!previous || previous.signature !== signature) {
|
|
156
|
+
const nudged = await nudgeTechLeadForStalledHandoff(ctx, group.requirementId, group.stories.length);
|
|
157
|
+
if (nudged) {
|
|
158
|
+
planningHandoffState.set(key, { signature, lastNudgeAt: nowMs });
|
|
159
|
+
console.log(chalk.yellow(` Nudged Tech Lead for stalled planning handoff (${formatRequirementLabel(group.requirementId)})`));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const retryDelayMs = Math.max(PROACTIVE_HANDOFF_RETRY_DELAY_MS, ctx.config.manager.fast_poll_interval);
|
|
165
|
+
if (nowMs - previous.lastNudgeAt < retryDelayMs) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Second intervention: promote and assign automatically.
|
|
170
|
+
const promoted = await promoteEstimatedStoriesToPlanned(ctx, group.requirementId, group.stories, 'stalled_planning_handoff');
|
|
171
|
+
if (promoted > 0) {
|
|
172
|
+
promotedTotal += promoted;
|
|
173
|
+
shouldRunAutoAssignment = true;
|
|
174
|
+
ctx.counters.handoffPromoted += promoted;
|
|
175
|
+
console.log(chalk.yellow(` Auto-promoted ${promoted} stalled estimated story/ies (${formatRequirementLabel(group.requirementId)})`));
|
|
176
|
+
}
|
|
177
|
+
planningHandoffState.delete(key);
|
|
178
|
+
}
|
|
179
|
+
for (const key of Array.from(planningHandoffState.keys())) {
|
|
180
|
+
if (!activeKeys.has(key)) {
|
|
181
|
+
planningHandoffState.delete(key);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (shouldRunAutoAssignment && promotedTotal > 0) {
|
|
185
|
+
await runAutoAssignmentAfterHandoff(ctx);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=handoff-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-recovery.js","sourceRoot":"","sources":["../../../../src/cli/commands/manager/handoff-recovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/manager/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6DpC,eAAO,MAAM,cAAc,SAE1B,CAAC"}
|