hungry-ghost-hive 0.44.0 → 0.46.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 +1 -0
- package/dist/agents/base-agent.d.ts.map +1 -1
- package/dist/agents/base-agent.js +4 -0
- package/dist/agents/base-agent.js.map +1 -1
- package/dist/agents/intermediate.js +2 -2
- package/dist/agents/intermediate.js.map +1 -1
- package/dist/agents/junior.js +2 -2
- package/dist/agents/junior.js.map +1 -1
- package/dist/agents/qa.d.ts.map +1 -1
- package/dist/agents/qa.js +5 -5
- package/dist/agents/qa.js.map +1 -1
- package/dist/agents/senior.d.ts.map +1 -1
- package/dist/agents/senior.js +5 -5
- package/dist/agents/senior.js.map +1 -1
- package/dist/agents/tech-lead.d.ts.map +1 -1
- package/dist/agents/tech-lead.js +4 -2
- package/dist/agents/tech-lead.js.map +1 -1
- package/dist/cli/commands/assign.d.ts.map +1 -1
- package/dist/cli/commands/assign.js +4 -2
- package/dist/cli/commands/assign.js.map +1 -1
- package/dist/cli/commands/assign.test.js +5 -0
- package/dist/cli/commands/assign.test.js.map +1 -1
- package/dist/cli/commands/cluster.d.ts.map +1 -1
- package/dist/cli/commands/cluster.js +348 -1
- package/dist/cli/commands/cluster.js.map +1 -1
- package/dist/cli/commands/cluster.test.js +313 -9
- package/dist/cli/commands/cluster.test.js.map +1 -1
- package/dist/cli/commands/manager/handoff-recovery.d.ts.map +1 -1
- package/dist/cli/commands/manager/handoff-recovery.js +4 -2
- 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 +16 -12
- package/dist/cli/commands/manager/index.js.map +1 -1
- package/dist/cli/commands/manager/tech-lead-lifecycle.d.ts.map +1 -1
- package/dist/cli/commands/manager/tech-lead-lifecycle.js +4 -2
- package/dist/cli/commands/manager/tech-lead-lifecycle.js.map +1 -1
- package/dist/cli/commands/msg.d.ts.map +1 -1
- package/dist/cli/commands/msg.js +8 -7
- package/dist/cli/commands/msg.js.map +1 -1
- package/dist/cli/commands/my-stories.js +3 -3
- package/dist/cli/commands/my-stories.js.map +1 -1
- package/dist/cli/commands/nuke.d.ts.map +1 -1
- package/dist/cli/commands/nuke.js +18 -7
- package/dist/cli/commands/nuke.js.map +1 -1
- package/dist/cli/commands/nuke.test.js +24 -0
- package/dist/cli/commands/nuke.test.js.map +1 -1
- package/dist/cli/commands/req-spawn.test.d.ts +2 -0
- package/dist/cli/commands/req-spawn.test.d.ts.map +1 -0
- package/dist/cli/commands/req-spawn.test.js +116 -0
- package/dist/cli/commands/req-spawn.test.js.map +1 -0
- package/dist/cli/commands/req.d.ts +1 -1
- package/dist/cli/commands/req.d.ts.map +1 -1
- package/dist/cli/commands/req.js +28 -18
- package/dist/cli/commands/req.js.map +1 -1
- package/dist/cli/commands/stories.js +3 -3
- package/dist/cli/commands/stories.js.map +1 -1
- package/dist/cli/dashboard/panels/agents.d.ts.map +1 -1
- package/dist/cli/dashboard/panels/agents.js +7 -3
- package/dist/cli/dashboard/panels/agents.js.map +1 -1
- package/dist/cluster/cluster-http-server.d.ts +32 -0
- package/dist/cluster/cluster-http-server.d.ts.map +1 -1
- package/dist/cluster/cluster-http-server.js +42 -0
- package/dist/cluster/cluster-http-server.js.map +1 -1
- package/dist/cluster/distributed-runtime-coverage.test.js +9 -0
- package/dist/cluster/distributed-runtime-coverage.test.js.map +1 -1
- package/dist/cluster/distributed-system.test.js +135 -0
- package/dist/cluster/distributed-system.test.js.map +1 -1
- package/dist/cluster/events.d.ts +23 -0
- package/dist/cluster/events.d.ts.map +1 -1
- package/dist/cluster/events.js +74 -0
- package/dist/cluster/events.js.map +1 -1
- package/dist/cluster/heartbeat-manager.d.ts +2 -0
- package/dist/cluster/heartbeat-manager.d.ts.map +1 -1
- package/dist/cluster/heartbeat-manager.js +42 -6
- package/dist/cluster/heartbeat-manager.js.map +1 -1
- package/dist/cluster/membership.test.d.ts +2 -0
- package/dist/cluster/membership.test.d.ts.map +1 -0
- package/dist/cluster/membership.test.js +416 -0
- package/dist/cluster/membership.test.js.map +1 -0
- package/dist/cluster/partition-safety.test.d.ts +2 -0
- package/dist/cluster/partition-safety.test.d.ts.map +1 -0
- package/dist/cluster/partition-safety.test.js +440 -0
- package/dist/cluster/partition-safety.test.js.map +1 -0
- package/dist/cluster/raft-state-machine.d.ts +33 -1
- package/dist/cluster/raft-state-machine.d.ts.map +1 -1
- package/dist/cluster/raft-state-machine.js +65 -3
- package/dist/cluster/raft-state-machine.js.map +1 -1
- package/dist/cluster/raft-store.d.ts +26 -1
- package/dist/cluster/raft-store.d.ts.map +1 -1
- package/dist/cluster/raft-store.js +137 -0
- package/dist/cluster/raft-store.js.map +1 -1
- package/dist/cluster/replication-lag.test.d.ts +2 -0
- package/dist/cluster/replication-lag.test.d.ts.map +1 -0
- package/dist/cluster/replication-lag.test.js +239 -0
- package/dist/cluster/replication-lag.test.js.map +1 -0
- package/dist/cluster/replication.d.ts +2 -2
- package/dist/cluster/replication.d.ts.map +1 -1
- package/dist/cluster/replication.js +1 -1
- package/dist/cluster/replication.js.map +1 -1
- package/dist/cluster/runtime.d.ts +78 -0
- package/dist/cluster/runtime.d.ts.map +1 -1
- package/dist/cluster/runtime.js +400 -13
- package/dist/cluster/runtime.js.map +1 -1
- package/dist/cluster/state-recovery.test.d.ts +2 -0
- package/dist/cluster/state-recovery.test.d.ts.map +1 -0
- package/dist/cluster/state-recovery.test.js +310 -0
- package/dist/cluster/state-recovery.test.js.map +1 -0
- package/dist/cluster/types.d.ts +30 -0
- package/dist/cluster/types.d.ts.map +1 -1
- package/dist/config/schema.d.ts +48 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +11 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/context-files/generator.d.ts +1 -1
- package/dist/context-files/generator.d.ts.map +1 -1
- package/dist/context-files/generator.js +4 -3
- package/dist/context-files/generator.js.map +1 -1
- package/dist/context-files/generator.test.js +51 -0
- package/dist/context-files/generator.test.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 +1 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +6 -0
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations/015-add-story-markdown-path.sql +5 -0
- package/dist/db/queries/stories.d.ts +3 -3
- package/dist/db/queries/stories.d.ts.map +1 -1
- package/dist/db/queries/stories.js +23 -5
- package/dist/db/queries/stories.js.map +1 -1
- package/dist/db/queries/test-helpers.d.ts.map +1 -1
- package/dist/db/queries/test-helpers.js +1 -0
- package/dist/db/queries/test-helpers.js.map +1 -1
- package/dist/git/worktree.d.ts.map +1 -1
- package/dist/git/worktree.js +7 -0
- package/dist/git/worktree.js.map +1 -1
- package/dist/git/worktree.test.js +30 -0
- package/dist/git/worktree.test.js.map +1 -1
- package/dist/orchestrator/orphan-recovery.d.ts +1 -1
- package/dist/orchestrator/orphan-recovery.d.ts.map +1 -1
- package/dist/orchestrator/orphan-recovery.js +4 -4
- package/dist/orchestrator/orphan-recovery.js.map +1 -1
- package/dist/orchestrator/prompt-templates.d.ts +6 -2
- package/dist/orchestrator/prompt-templates.d.ts.map +1 -1
- package/dist/orchestrator/prompt-templates.js +61 -16
- package/dist/orchestrator/prompt-templates.js.map +1 -1
- package/dist/orchestrator/prompt-templates.test.js +214 -0
- package/dist/orchestrator/prompt-templates.test.js.map +1 -1
- package/dist/orchestrator/scheduler.d.ts +1 -0
- package/dist/orchestrator/scheduler.d.ts.map +1 -1
- package/dist/orchestrator/scheduler.js +30 -17
- package/dist/orchestrator/scheduler.js.map +1 -1
- package/dist/orchestrator/scheduler.test.js +98 -6
- package/dist/orchestrator/scheduler.test.js.map +1 -1
- package/dist/tmux/manager.d.ts +7 -6
- package/dist/tmux/manager.d.ts.map +1 -1
- package/dist/tmux/manager.js +29 -13
- package/dist/tmux/manager.js.map +1 -1
- package/dist/utils/instance.d.ts +32 -0
- package/dist/utils/instance.d.ts.map +1 -0
- package/dist/utils/instance.js +82 -0
- package/dist/utils/instance.js.map +1 -0
- package/dist/utils/instance.test.d.ts +2 -0
- package/dist/utils/instance.test.d.ts.map +1 -0
- package/dist/utils/instance.test.js +103 -0
- package/dist/utils/instance.test.js.map +1 -0
- package/dist/utils/paths.d.ts +2 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +2 -0
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/paths.test.js +6 -0
- package/dist/utils/paths.test.js.map +1 -1
- package/dist/utils/story-markdown.d.ts +16 -0
- package/dist/utils/story-markdown.d.ts.map +1 -0
- package/dist/utils/story-markdown.js +82 -0
- package/dist/utils/story-markdown.js.map +1 -0
- package/dist/utils/story-markdown.test.d.ts +2 -0
- package/dist/utils/story-markdown.test.d.ts.map +1 -0
- package/dist/utils/story-markdown.test.js +143 -0
- package/dist/utils/story-markdown.test.js.map +1 -0
- package/package.json +1 -1
- package/src/agents/base-agent.ts +5 -0
- package/src/agents/intermediate.ts +2 -2
- package/src/agents/junior.ts +2 -2
- package/src/agents/qa.ts +13 -8
- package/src/agents/senior.ts +21 -11
- package/src/agents/tech-lead.ts +24 -12
- package/src/cli/commands/assign.test.ts +5 -0
- package/src/cli/commands/assign.ts +4 -2
- package/src/cli/commands/cluster.test.ts +387 -9
- package/src/cli/commands/cluster.ts +486 -1
- package/src/cli/commands/manager/handoff-recovery.ts +4 -2
- package/src/cli/commands/manager/index.ts +16 -11
- package/src/cli/commands/manager/tech-lead-lifecycle.ts +5 -2
- package/src/cli/commands/msg.ts +8 -7
- package/src/cli/commands/my-stories.ts +22 -13
- package/src/cli/commands/nuke.test.ts +31 -0
- package/src/cli/commands/nuke.ts +18 -7
- package/src/cli/commands/req-spawn.test.ts +153 -0
- package/src/cli/commands/req.ts +40 -23
- package/src/cli/commands/stories.ts +22 -13
- package/src/cli/dashboard/panels/agents.ts +7 -3
- package/src/cluster/cluster-http-server.ts +80 -0
- package/src/cluster/distributed-runtime-coverage.test.ts +9 -0
- package/src/cluster/distributed-system.test.ts +168 -0
- package/src/cluster/events.ts +90 -0
- package/src/cluster/heartbeat-manager.ts +48 -6
- package/src/cluster/membership.test.ts +498 -0
- package/src/cluster/partition-safety.test.ts +523 -0
- package/src/cluster/raft-state-machine.ts +76 -4
- package/src/cluster/raft-store.ts +167 -1
- package/src/cluster/replication-lag.test.ts +284 -0
- package/src/cluster/replication.ts +6 -0
- package/src/cluster/runtime.ts +551 -12
- package/src/cluster/state-recovery.test.ts +420 -0
- package/src/cluster/types.ts +32 -0
- package/src/config/schema.ts +11 -0
- package/src/context-files/generator.test.ts +55 -0
- package/src/context-files/generator.ts +8 -7
- package/src/context-files/index.test.ts +1 -0
- package/src/db/client.ts +7 -0
- package/src/db/migrations/015-add-story-markdown-path.sql +5 -0
- package/src/db/queries/stories.ts +29 -5
- package/src/db/queries/test-helpers.ts +1 -0
- package/src/git/worktree.test.ts +43 -0
- package/src/git/worktree.ts +10 -0
- package/src/orchestrator/orphan-recovery.ts +32 -13
- package/src/orchestrator/prompt-templates.test.ts +267 -0
- package/src/orchestrator/prompt-templates.ts +69 -16
- package/src/orchestrator/scheduler.test.ts +130 -6
- package/src/orchestrator/scheduler.ts +66 -27
- package/src/tmux/manager.ts +42 -13
- package/src/utils/instance.test.ts +129 -0
- package/src/utils/instance.ts +95 -0
- package/src/utils/paths.test.ts +8 -0
- package/src/utils/paths.ts +3 -0
- package/src/utils/story-markdown.test.ts +176 -0
- package/src/utils/story-markdown.ts +94 -0
|
@@ -90,6 +90,7 @@ export async function createTestDatabase(): Promise<SqlJsDatabase> {
|
|
|
90
90
|
external_subtask_id TEXT,
|
|
91
91
|
external_provider TEXT,
|
|
92
92
|
in_sprint INTEGER DEFAULT 0,
|
|
93
|
+
markdown_path TEXT,
|
|
93
94
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
94
95
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
95
96
|
);
|
package/src/git/worktree.test.ts
CHANGED
|
@@ -7,12 +7,19 @@ vi.mock('child_process', () => ({
|
|
|
7
7
|
execSync: vi.fn(),
|
|
8
8
|
}));
|
|
9
9
|
|
|
10
|
+
vi.mock('fs', () => ({
|
|
11
|
+
existsSync: vi.fn(() => true),
|
|
12
|
+
}));
|
|
13
|
+
|
|
10
14
|
import { execSync } from 'child_process';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
11
16
|
|
|
12
17
|
const mockExecSync = vi.mocked(execSync);
|
|
18
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
13
19
|
|
|
14
20
|
beforeEach(() => {
|
|
15
21
|
vi.clearAllMocks();
|
|
22
|
+
mockExistsSync.mockReturnValue(true);
|
|
16
23
|
});
|
|
17
24
|
|
|
18
25
|
describe('removeWorktree', () => {
|
|
@@ -81,4 +88,40 @@ describe('removeWorktree', () => {
|
|
|
81
88
|
expect(result.success).toBe(false);
|
|
82
89
|
expect(result.error).toBe('Unknown error');
|
|
83
90
|
});
|
|
91
|
+
|
|
92
|
+
it('should return success without running git when worktree path does not exist on disk', () => {
|
|
93
|
+
mockExistsSync.mockReturnValue(false);
|
|
94
|
+
|
|
95
|
+
const result = removeWorktree('/root', 'repos/team-agent-stale');
|
|
96
|
+
|
|
97
|
+
expect(result.success).toBe(true);
|
|
98
|
+
expect(result.fullWorktreePath).toBe('/root/repos/team-agent-stale');
|
|
99
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should log debug message when path missing and HIVE_DEBUG is set', () => {
|
|
103
|
+
mockExistsSync.mockReturnValue(false);
|
|
104
|
+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
105
|
+
process.env.HIVE_DEBUG = '1';
|
|
106
|
+
|
|
107
|
+
removeWorktree('/root', 'repos/team-agent-stale');
|
|
108
|
+
|
|
109
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
110
|
+
expect.stringContaining('does not exist on disk, skipping removal')
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
delete process.env.HIVE_DEBUG;
|
|
114
|
+
consoleSpy.mockRestore();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should not log when path missing and HIVE_DEBUG is not set', () => {
|
|
118
|
+
mockExistsSync.mockReturnValue(false);
|
|
119
|
+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
120
|
+
delete process.env.HIVE_DEBUG;
|
|
121
|
+
|
|
122
|
+
removeWorktree('/root', 'repos/team-agent-stale');
|
|
123
|
+
|
|
124
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
125
|
+
consoleSpy.mockRestore();
|
|
126
|
+
});
|
|
84
127
|
});
|
package/src/git/worktree.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Licensed under the Hungry Ghost Hive License. See LICENSE.
|
|
2
2
|
|
|
3
3
|
import { execSync } from 'child_process';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
4
5
|
|
|
5
6
|
export interface RemoveWorktreeResult {
|
|
6
7
|
success: boolean;
|
|
@@ -27,6 +28,15 @@ export function removeWorktree(
|
|
|
27
28
|
return { success: true, fullWorktreePath };
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
if (!existsSync(fullWorktreePath)) {
|
|
32
|
+
if (process.env.HIVE_DEBUG) {
|
|
33
|
+
console.log(
|
|
34
|
+
`[debug] worktree path ${fullWorktreePath} does not exist on disk, skipping removal`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return { success: true, fullWorktreePath };
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
try {
|
|
31
41
|
execSync(`git worktree remove "${fullWorktreePath}" --force`, {
|
|
32
42
|
cwd: rootDir,
|
|
@@ -14,7 +14,11 @@ import {
|
|
|
14
14
|
* Detect and recover orphaned stories (assigned to terminated agents).
|
|
15
15
|
* Returns the story IDs that were recovered.
|
|
16
16
|
*/
|
|
17
|
-
export function detectAndRecoverOrphanedStories(
|
|
17
|
+
export function detectAndRecoverOrphanedStories(
|
|
18
|
+
db: Database,
|
|
19
|
+
rootDir: string,
|
|
20
|
+
storiesDir?: string
|
|
21
|
+
): string[] {
|
|
18
22
|
const orphanedAssignments = getStoriesWithOrphanedAssignments(db);
|
|
19
23
|
const staleInProgressStories = getStaleInProgressStoriesWithoutAssignment(db);
|
|
20
24
|
const inconsistentInProgressAssignments = getInProgressStoriesWithInconsistentAssignments(db);
|
|
@@ -26,10 +30,15 @@ export function detectAndRecoverOrphanedStories(db: Database, rootDir: string):
|
|
|
26
30
|
if (recoveredSet.has(assignment.id)) continue;
|
|
27
31
|
|
|
28
32
|
// Update story in single atomic operation
|
|
29
|
-
updateStory(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
updateStory(
|
|
34
|
+
db,
|
|
35
|
+
assignment.id,
|
|
36
|
+
{
|
|
37
|
+
assignedAgentId: null,
|
|
38
|
+
status: 'planned',
|
|
39
|
+
},
|
|
40
|
+
storiesDir
|
|
41
|
+
);
|
|
33
42
|
createLog(db, {
|
|
34
43
|
agentId: 'scheduler',
|
|
35
44
|
storyId: assignment.id,
|
|
@@ -52,10 +61,15 @@ export function detectAndRecoverOrphanedStories(db: Database, rootDir: string):
|
|
|
52
61
|
try {
|
|
53
62
|
if (recoveredSet.has(story.id)) continue;
|
|
54
63
|
|
|
55
|
-
updateStory(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
updateStory(
|
|
65
|
+
db,
|
|
66
|
+
story.id,
|
|
67
|
+
{
|
|
68
|
+
assignedAgentId: null,
|
|
69
|
+
status: 'planned',
|
|
70
|
+
},
|
|
71
|
+
storiesDir
|
|
72
|
+
);
|
|
59
73
|
createLog(db, {
|
|
60
74
|
agentId: 'scheduler',
|
|
61
75
|
storyId: story.id,
|
|
@@ -78,10 +92,15 @@ export function detectAndRecoverOrphanedStories(db: Database, rootDir: string):
|
|
|
78
92
|
try {
|
|
79
93
|
if (recoveredSet.has(assignment.id)) continue;
|
|
80
94
|
|
|
81
|
-
updateStory(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
updateStory(
|
|
96
|
+
db,
|
|
97
|
+
assignment.id,
|
|
98
|
+
{
|
|
99
|
+
assignedAgentId: null,
|
|
100
|
+
status: 'planned',
|
|
101
|
+
},
|
|
102
|
+
storiesDir
|
|
103
|
+
);
|
|
85
104
|
createLog(db, {
|
|
86
105
|
agentId: 'scheduler',
|
|
87
106
|
storyId: assignment.id,
|
|
@@ -114,6 +114,7 @@ describe('Prompt Templates', () => {
|
|
|
114
114
|
external_subtask_id: null,
|
|
115
115
|
external_provider: null,
|
|
116
116
|
in_sprint: 0,
|
|
117
|
+
markdown_path: null,
|
|
117
118
|
created_at: '2024-01-01',
|
|
118
119
|
updated_at: '2024-01-01',
|
|
119
120
|
},
|
|
@@ -153,6 +154,7 @@ describe('Prompt Templates', () => {
|
|
|
153
154
|
external_subtask_id: null,
|
|
154
155
|
external_provider: null,
|
|
155
156
|
in_sprint: 0,
|
|
157
|
+
markdown_path: null,
|
|
156
158
|
created_at: '2024-01-01',
|
|
157
159
|
updated_at: '2024-01-01',
|
|
158
160
|
},
|
|
@@ -162,6 +164,82 @@ describe('Prompt Templates', () => {
|
|
|
162
164
|
expect(prompt).toContain('complexity: ?');
|
|
163
165
|
});
|
|
164
166
|
|
|
167
|
+
it('should include markdown_path in prompt when set on a story', () => {
|
|
168
|
+
const stories: StoryRow[] = [
|
|
169
|
+
{
|
|
170
|
+
id: 'STORY-003',
|
|
171
|
+
title: 'Story With Markdown',
|
|
172
|
+
description: 'DB description',
|
|
173
|
+
complexity_score: 3,
|
|
174
|
+
status: 'planned',
|
|
175
|
+
team_id: 'team-1',
|
|
176
|
+
requirement_id: null,
|
|
177
|
+
acceptance_criteria: null,
|
|
178
|
+
story_points: null,
|
|
179
|
+
assigned_agent_id: null,
|
|
180
|
+
branch_name: null,
|
|
181
|
+
pr_url: null,
|
|
182
|
+
jira_issue_key: null,
|
|
183
|
+
jira_issue_id: null,
|
|
184
|
+
jira_project_key: null,
|
|
185
|
+
jira_subtask_key: null,
|
|
186
|
+
jira_subtask_id: null,
|
|
187
|
+
external_issue_key: null,
|
|
188
|
+
external_issue_id: null,
|
|
189
|
+
external_project_key: null,
|
|
190
|
+
external_subtask_key: null,
|
|
191
|
+
external_subtask_id: null,
|
|
192
|
+
external_provider: null,
|
|
193
|
+
in_sprint: 0,
|
|
194
|
+
markdown_path: '/stories/STORY-003.md',
|
|
195
|
+
created_at: '2024-01-01',
|
|
196
|
+
updated_at: '2024-01-01',
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, stories);
|
|
200
|
+
|
|
201
|
+
expect(prompt).toContain('/stories/STORY-003.md');
|
|
202
|
+
expect(prompt).toContain('read the story markdown file');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should fall back to DB description when markdown_path is null', () => {
|
|
206
|
+
const stories: StoryRow[] = [
|
|
207
|
+
{
|
|
208
|
+
id: 'STORY-004',
|
|
209
|
+
title: 'Story Without Markdown',
|
|
210
|
+
description: 'DB only description',
|
|
211
|
+
complexity_score: 2,
|
|
212
|
+
status: 'planned',
|
|
213
|
+
team_id: 'team-1',
|
|
214
|
+
requirement_id: null,
|
|
215
|
+
acceptance_criteria: null,
|
|
216
|
+
story_points: null,
|
|
217
|
+
assigned_agent_id: null,
|
|
218
|
+
branch_name: null,
|
|
219
|
+
pr_url: null,
|
|
220
|
+
jira_issue_key: null,
|
|
221
|
+
jira_issue_id: null,
|
|
222
|
+
jira_project_key: null,
|
|
223
|
+
jira_subtask_key: null,
|
|
224
|
+
jira_subtask_id: null,
|
|
225
|
+
external_issue_key: null,
|
|
226
|
+
external_issue_id: null,
|
|
227
|
+
external_project_key: null,
|
|
228
|
+
external_subtask_key: null,
|
|
229
|
+
external_subtask_id: null,
|
|
230
|
+
external_provider: null,
|
|
231
|
+
in_sprint: 0,
|
|
232
|
+
markdown_path: null,
|
|
233
|
+
created_at: '2024-01-01',
|
|
234
|
+
updated_at: '2024-01-01',
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, stories);
|
|
238
|
+
|
|
239
|
+
expect(prompt).toContain('DB only description');
|
|
240
|
+
expect(prompt).not.toContain('read the story markdown file');
|
|
241
|
+
});
|
|
242
|
+
|
|
165
243
|
it('should handle empty stories list', () => {
|
|
166
244
|
const stories: StoryRow[] = [];
|
|
167
245
|
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, stories);
|
|
@@ -230,6 +308,7 @@ describe('Prompt Templates', () => {
|
|
|
230
308
|
external_subtask_id: null,
|
|
231
309
|
external_provider: null,
|
|
232
310
|
in_sprint: 0,
|
|
311
|
+
markdown_path: null,
|
|
233
312
|
created_at: '2024-01-01',
|
|
234
313
|
updated_at: '2024-01-01',
|
|
235
314
|
},
|
|
@@ -258,6 +337,7 @@ describe('Prompt Templates', () => {
|
|
|
258
337
|
external_subtask_id: null,
|
|
259
338
|
external_provider: null,
|
|
260
339
|
in_sprint: 0,
|
|
340
|
+
markdown_path: null,
|
|
261
341
|
created_at: '2024-01-01',
|
|
262
342
|
updated_at: '2024-01-01',
|
|
263
343
|
},
|
|
@@ -810,3 +890,190 @@ describe('Prompt Templates', () => {
|
|
|
810
890
|
});
|
|
811
891
|
});
|
|
812
892
|
});
|
|
893
|
+
|
|
894
|
+
describe('Chrome Tab Isolation', () => {
|
|
895
|
+
const teamName = 'TestTeam';
|
|
896
|
+
const repoUrl = 'https://github.com/test/repo.git';
|
|
897
|
+
const repoPath = 'repos/test-repo';
|
|
898
|
+
const sessionName = 'hive-test-session';
|
|
899
|
+
|
|
900
|
+
const CHROME_TAB_MARKER = 'Chrome Browser Tab Isolation';
|
|
901
|
+
const CHROME_TAB_CREATE = 'tabs_create_mcp';
|
|
902
|
+
|
|
903
|
+
describe('generateSeniorPrompt', () => {
|
|
904
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
905
|
+
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, [], 'main', {
|
|
906
|
+
chromeEnabled: true,
|
|
907
|
+
});
|
|
908
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
909
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
913
|
+
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, [], 'main', {
|
|
914
|
+
chromeEnabled: false,
|
|
915
|
+
});
|
|
916
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
it('should not include chrome tab isolation section when chromeEnabled is not set', () => {
|
|
920
|
+
const prompt = generateSeniorPrompt(teamName, repoUrl, repoPath, []);
|
|
921
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
922
|
+
});
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
describe('generateIntermediatePrompt', () => {
|
|
926
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
927
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
928
|
+
chromeEnabled: true,
|
|
929
|
+
});
|
|
930
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
931
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
935
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
936
|
+
chromeEnabled: false,
|
|
937
|
+
});
|
|
938
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
it('should not include chrome tab isolation section when options not provided', () => {
|
|
942
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName);
|
|
943
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
describe('generateJuniorPrompt', () => {
|
|
948
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
949
|
+
const prompt = generateJuniorPrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
950
|
+
chromeEnabled: true,
|
|
951
|
+
});
|
|
952
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
953
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
957
|
+
const prompt = generateJuniorPrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
958
|
+
chromeEnabled: false,
|
|
959
|
+
});
|
|
960
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
it('should not include chrome tab isolation section when options not provided', () => {
|
|
964
|
+
const prompt = generateJuniorPrompt(teamName, repoUrl, repoPath, sessionName);
|
|
965
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
966
|
+
});
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
describe('generateQAPrompt', () => {
|
|
970
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
971
|
+
const prompt = generateQAPrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
972
|
+
chromeEnabled: true,
|
|
973
|
+
});
|
|
974
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
975
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
979
|
+
const prompt = generateQAPrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
980
|
+
chromeEnabled: false,
|
|
981
|
+
});
|
|
982
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
it('should not include chrome tab isolation section when options not provided', () => {
|
|
986
|
+
const prompt = generateQAPrompt(teamName, repoUrl, repoPath, sessionName);
|
|
987
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
988
|
+
});
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
describe('generateFeatureTestPrompt', () => {
|
|
992
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
993
|
+
const prompt = generateFeatureTestPrompt(
|
|
994
|
+
teamName,
|
|
995
|
+
repoUrl,
|
|
996
|
+
repoPath,
|
|
997
|
+
sessionName,
|
|
998
|
+
'feature/test',
|
|
999
|
+
'REQ-001',
|
|
1000
|
+
'e2e/tests',
|
|
1001
|
+
{ chromeEnabled: true }
|
|
1002
|
+
);
|
|
1003
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
1004
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
1008
|
+
const prompt = generateFeatureTestPrompt(
|
|
1009
|
+
teamName,
|
|
1010
|
+
repoUrl,
|
|
1011
|
+
repoPath,
|
|
1012
|
+
sessionName,
|
|
1013
|
+
'feature/test',
|
|
1014
|
+
'REQ-001',
|
|
1015
|
+
'e2e/tests',
|
|
1016
|
+
{ chromeEnabled: false }
|
|
1017
|
+
);
|
|
1018
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
it('should not include chrome tab isolation section when options not provided', () => {
|
|
1022
|
+
const prompt = generateFeatureTestPrompt(
|
|
1023
|
+
teamName,
|
|
1024
|
+
repoUrl,
|
|
1025
|
+
repoPath,
|
|
1026
|
+
sessionName,
|
|
1027
|
+
'feature/test',
|
|
1028
|
+
'REQ-001',
|
|
1029
|
+
'e2e/tests'
|
|
1030
|
+
);
|
|
1031
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
describe('generateAuditorPrompt', () => {
|
|
1036
|
+
it('should include chrome tab isolation section when chromeEnabled is true', () => {
|
|
1037
|
+
const prompt = generateAuditorPrompt(sessionName, repoPath, repoUrl, {
|
|
1038
|
+
chromeEnabled: true,
|
|
1039
|
+
});
|
|
1040
|
+
expect(prompt).toContain(CHROME_TAB_MARKER);
|
|
1041
|
+
expect(prompt).toContain(CHROME_TAB_CREATE);
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
it('should not include chrome tab isolation section when chromeEnabled is false', () => {
|
|
1045
|
+
const prompt = generateAuditorPrompt(sessionName, repoPath, repoUrl, {
|
|
1046
|
+
chromeEnabled: false,
|
|
1047
|
+
});
|
|
1048
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
it('should not include chrome tab isolation section when options not provided', () => {
|
|
1052
|
+
const prompt = generateAuditorPrompt(sessionName, repoPath, repoUrl);
|
|
1053
|
+
expect(prompt).not.toContain(CHROME_TAB_MARKER);
|
|
1054
|
+
});
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
describe('tab isolation instructions content', () => {
|
|
1058
|
+
it('should instruct agents to store and reuse tab ID', () => {
|
|
1059
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
1060
|
+
chromeEnabled: true,
|
|
1061
|
+
});
|
|
1062
|
+
expect(prompt).toContain('tab ID');
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
it('should instruct agents to recreate tab when closed externally', () => {
|
|
1066
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
1067
|
+
chromeEnabled: true,
|
|
1068
|
+
});
|
|
1069
|
+
expect(prompt).toContain('closed externally');
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
it('should warn agents not to use other agents tabs', () => {
|
|
1073
|
+
const prompt = generateIntermediatePrompt(teamName, repoUrl, repoPath, sessionName, 'main', {
|
|
1074
|
+
chromeEnabled: true,
|
|
1075
|
+
});
|
|
1076
|
+
expect(prompt).toContain('Never interact with tabs you did not create');
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
1079
|
+
});
|
|
@@ -4,6 +4,10 @@ import type { StoryRow } from '../db/client.js';
|
|
|
4
4
|
|
|
5
5
|
export interface AgentPromptOptions {
|
|
6
6
|
includeProgressUpdates?: boolean;
|
|
7
|
+
/** The tech lead tmux session name for messaging. Defaults to 'hive-tech-lead' for backwards compatibility. */
|
|
8
|
+
techLeadSession?: string;
|
|
9
|
+
/** Whether Chrome browser tools are enabled for this agent session. */
|
|
10
|
+
chromeEnabled?: boolean;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
/**
|
|
@@ -60,6 +64,39 @@ function shouldIncludeProgressUpdates(options?: AgentPromptOptions): boolean {
|
|
|
60
64
|
return options?.includeProgressUpdates ?? true;
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
function resolveTechLeadSession(options?: AgentPromptOptions): string {
|
|
68
|
+
return options?.techLeadSession || 'hive-tech-lead';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Generate the Chrome tab isolation section for agent prompts.
|
|
73
|
+
* Instructs agents to create a dedicated tab at session start and use it
|
|
74
|
+
* exclusively for all browser operations, preventing tab interference between
|
|
75
|
+
* concurrent agents.
|
|
76
|
+
*/
|
|
77
|
+
function chromeTabIsolationSection(): string {
|
|
78
|
+
return `# Chrome Browser Tab Isolation
|
|
79
|
+
Chrome browser tools are enabled for this session. Each agent must use its own dedicated tab to prevent interference with other agents running concurrently.
|
|
80
|
+
|
|
81
|
+
## Tab Lifecycle
|
|
82
|
+
|
|
83
|
+
**At session start**, create your dedicated tab immediately:
|
|
84
|
+
\`\`\`
|
|
85
|
+
Use mcp__claude-in-chrome__tabs_create_mcp to create a new tab.
|
|
86
|
+
Store the returned tab ID — you will use it for all browser operations.
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
**For all browser operations**, always pass your stored tab ID to every \`mcp__claude-in-chrome__*\` tool call. Never interact with tabs you did not create.
|
|
90
|
+
|
|
91
|
+
**If your tab is closed externally** (tool returns a tab-not-found error):
|
|
92
|
+
\`\`\`
|
|
93
|
+
Call mcp__claude-in-chrome__tabs_create_mcp again to get a new tab ID.
|
|
94
|
+
Update your stored tab ID and continue.
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
**At session end**, close your tab using the browser tools to free resources.`;
|
|
98
|
+
}
|
|
99
|
+
|
|
63
100
|
function repositorySection(repoPath: string, repoUrl: string): string {
|
|
64
101
|
return `## Your Repository
|
|
65
102
|
- Local path: ${repoPath}
|
|
@@ -231,20 +268,25 @@ export function generateSeniorPrompt(
|
|
|
231
268
|
sessionNameOverride?: string
|
|
232
269
|
): string {
|
|
233
270
|
const includeProgressUpdates = shouldIncludeProgressUpdates(options);
|
|
271
|
+
const techLeadSession = resolveTechLeadSession(options);
|
|
234
272
|
const storyList = stories
|
|
235
273
|
.map(s => {
|
|
236
274
|
const externalInfo = s.external_subtask_key
|
|
237
275
|
? ` | External Subtask: ${s.external_subtask_key}`
|
|
238
276
|
: '';
|
|
239
|
-
|
|
277
|
+
const descriptionOrMarkdown = s.markdown_path
|
|
278
|
+
? `For full details, read the story markdown file: \`${s.markdown_path}\``
|
|
279
|
+
: s.description;
|
|
280
|
+
return `- [${s.id}] ${s.title} (complexity: ${s.complexity_score || '?'}${externalInfo})\n ${descriptionOrMarkdown}`;
|
|
240
281
|
})
|
|
241
282
|
.join('\n\n');
|
|
242
283
|
|
|
243
284
|
const sessionName = sessionNameOverride || formatSeniorSessionName(teamName);
|
|
285
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
244
286
|
|
|
245
287
|
return `You are a Senior Developer on Team ${teamName}.
|
|
246
288
|
Your tmux session: ${sessionName}
|
|
247
|
-
|
|
289
|
+
${chromeSection}
|
|
248
290
|
${repositorySection(repoPath, repoUrl)}
|
|
249
291
|
|
|
250
292
|
## Your Responsibilities
|
|
@@ -283,7 +325,7 @@ hive pr queue
|
|
|
283
325
|
## Communication with Tech Lead
|
|
284
326
|
If you have questions or need guidance, message the Tech Lead:
|
|
285
327
|
\`\`\`bash
|
|
286
|
-
hive msg send
|
|
328
|
+
hive msg send ${techLeadSession} "Your question here" --from ${sessionName}
|
|
287
329
|
\`\`\`
|
|
288
330
|
|
|
289
331
|
Check for replies:
|
|
@@ -318,11 +360,13 @@ export function generateIntermediatePrompt(
|
|
|
318
360
|
options?: AgentPromptOptions
|
|
319
361
|
): string {
|
|
320
362
|
const includeProgressUpdates = shouldIncludeProgressUpdates(options);
|
|
363
|
+
const techLeadSession = resolveTechLeadSession(options);
|
|
321
364
|
const seniorSession = formatSeniorSessionName(teamName);
|
|
365
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
322
366
|
|
|
323
367
|
return `You are an Intermediate Developer on Team ${teamName}.
|
|
324
368
|
Your tmux session: ${sessionName}
|
|
325
|
-
|
|
369
|
+
${chromeSection}
|
|
326
370
|
${repositorySection(repoPath, repoUrl)}
|
|
327
371
|
|
|
328
372
|
## Your Responsibilities
|
|
@@ -354,7 +398,7 @@ ${prSubmissionSection(sessionName, targetBranch)}
|
|
|
354
398
|
If you have questions, message your Senior or the Tech Lead:
|
|
355
399
|
\`\`\`bash
|
|
356
400
|
hive msg send ${seniorSession} "Your question" --from ${sessionName}
|
|
357
|
-
hive msg send
|
|
401
|
+
hive msg send ${techLeadSession} "Your question" --from ${sessionName}
|
|
358
402
|
\`\`\`
|
|
359
403
|
|
|
360
404
|
Check for replies:
|
|
@@ -389,11 +433,13 @@ export function generateJuniorPrompt(
|
|
|
389
433
|
options?: AgentPromptOptions
|
|
390
434
|
): string {
|
|
391
435
|
const includeProgressUpdates = shouldIncludeProgressUpdates(options);
|
|
436
|
+
const techLeadSession = resolveTechLeadSession(options);
|
|
392
437
|
const seniorSession = formatSeniorSessionName(teamName);
|
|
438
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
393
439
|
|
|
394
440
|
return `You are a Junior Developer on Team ${teamName}.
|
|
395
441
|
Your tmux session: ${sessionName}
|
|
396
|
-
|
|
442
|
+
${chromeSection}
|
|
397
443
|
${repositorySection(repoPath, repoUrl)}
|
|
398
444
|
|
|
399
445
|
## Your Responsibilities
|
|
@@ -425,7 +471,7 @@ ${prSubmissionSection(sessionName, targetBranch)}
|
|
|
425
471
|
If you have questions, message your Senior or the Tech Lead:
|
|
426
472
|
\`\`\`bash
|
|
427
473
|
hive msg send ${seniorSession} "Your question" --from ${sessionName}
|
|
428
|
-
hive msg send
|
|
474
|
+
hive msg send ${techLeadSession} "Your question" --from ${sessionName}
|
|
429
475
|
\`\`\`
|
|
430
476
|
|
|
431
477
|
Check for replies:
|
|
@@ -456,11 +502,13 @@ export function generateQAPrompt(
|
|
|
456
502
|
repoUrl: string,
|
|
457
503
|
repoPath: string,
|
|
458
504
|
sessionName: string,
|
|
459
|
-
targetBranch: string = 'main'
|
|
505
|
+
targetBranch: string = 'main',
|
|
506
|
+
options?: AgentPromptOptions
|
|
460
507
|
): string {
|
|
508
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
461
509
|
return `You are a QA Engineer on Team ${teamName}.
|
|
462
510
|
Your tmux session: ${sessionName}
|
|
463
|
-
|
|
511
|
+
${chromeSection}
|
|
464
512
|
${repositorySection(repoPath, repoUrl)}
|
|
465
513
|
|
|
466
514
|
## Your Responsibilities
|
|
@@ -557,6 +605,8 @@ export function generateFeatureTestPrompt(
|
|
|
557
605
|
options?: AgentPromptOptions
|
|
558
606
|
): string {
|
|
559
607
|
const includeProgressUpdates = shouldIncludeProgressUpdates(options);
|
|
608
|
+
const techLeadSession = resolveTechLeadSession(options);
|
|
609
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
560
610
|
const reportResultsSection = includeProgressUpdates
|
|
561
611
|
? `**If all tests pass:**
|
|
562
612
|
\`\`\`bash
|
|
@@ -572,17 +622,17 @@ Report results directly to the Tech Lead:
|
|
|
572
622
|
|
|
573
623
|
**If all tests pass:**
|
|
574
624
|
\`\`\`bash
|
|
575
|
-
hive msg send
|
|
625
|
+
hive msg send ${techLeadSession} "E2E tests PASSED for ${requirementId} on ${featureBranch}. [Include test summary: X passed, 0 failed. Total time: Xs]" --from ${sessionName}
|
|
576
626
|
\`\`\`
|
|
577
627
|
|
|
578
628
|
**If any tests fail:**
|
|
579
629
|
\`\`\`bash
|
|
580
|
-
hive msg send
|
|
630
|
+
hive msg send ${techLeadSession} "E2E tests FAILED for ${requirementId} on ${featureBranch}. [Include failure details: X passed, Y failed. Failed tests: list. Error details: summary]" --from ${sessionName}
|
|
581
631
|
\`\`\``;
|
|
582
632
|
|
|
583
633
|
return `You are a Feature Test Agent on Team ${teamName}.
|
|
584
634
|
Your tmux session: ${sessionName}
|
|
585
|
-
|
|
635
|
+
${chromeSection}
|
|
586
636
|
${repositorySection(repoPath, repoUrl)}
|
|
587
637
|
|
|
588
638
|
## Your Mission
|
|
@@ -631,7 +681,7 @@ ${reportResultsSection}
|
|
|
631
681
|
## Communication
|
|
632
682
|
If you encounter issues running the tests, message the Tech Lead:
|
|
633
683
|
\`\`\`bash
|
|
634
|
-
hive msg send
|
|
684
|
+
hive msg send ${techLeadSession} "Issue running E2E tests for ${requirementId}: [describe issue]" --from ${sessionName}
|
|
635
685
|
\`\`\`
|
|
636
686
|
|
|
637
687
|
Check for replies:
|
|
@@ -656,11 +706,14 @@ Start by checking out the feature branch and reading the TESTING.md file.`;
|
|
|
656
706
|
export function generateAuditorPrompt(
|
|
657
707
|
sessionName: string,
|
|
658
708
|
repoPath: string,
|
|
659
|
-
repoUrl: string
|
|
709
|
+
repoUrl: string,
|
|
710
|
+
options?: AgentPromptOptions
|
|
660
711
|
): string {
|
|
712
|
+
const techLeadSession = resolveTechLeadSession(options);
|
|
713
|
+
const chromeSection = options?.chromeEnabled ? '\n\n' + chromeTabIsolationSection() : '';
|
|
661
714
|
return `You are a Hive Auditor Agent.
|
|
662
715
|
Your tmux session: ${sessionName}
|
|
663
|
-
|
|
716
|
+
${chromeSection}
|
|
664
717
|
${repositorySection(repoPath, repoUrl)}
|
|
665
718
|
|
|
666
719
|
## Your Mission
|
|
@@ -725,7 +778,7 @@ tmux send-keys -t <session-name> Enter
|
|
|
725
778
|
**Other unfixable issues:** Any issue you cannot resolve with the above actions.
|
|
726
779
|
- Escalate to tech lead:
|
|
727
780
|
\`\`\`bash
|
|
728
|
-
hive msg send
|
|
781
|
+
hive msg send ${techLeadSession} "AUDITOR: <description of issue, including agent id and story id>" --from ${sessionName}
|
|
729
782
|
\`\`\`
|
|
730
783
|
|
|
731
784
|
### 5. Self-terminate
|