@inixiative/hivemind 0.1.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/LICENSE +21 -0
- package/README.md +115 -0
- package/dist/agents/agents.test.d.ts +1 -0
- package/dist/agents/agents.test.js +167 -0
- package/dist/agents/getActiveAgents.d.ts +6 -0
- package/dist/agents/getActiveAgents.js +11 -0
- package/dist/agents/getAgent.d.ts +6 -0
- package/dist/agents/getAgent.js +7 -0
- package/dist/agents/getAgentBySessionId.d.ts +10 -0
- package/dist/agents/getAgentBySessionId.js +17 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/markAgentDead.d.ts +6 -0
- package/dist/agents/markAgentDead.js +26 -0
- package/dist/agents/markAgentIdle.d.ts +5 -0
- package/dist/agents/markAgentIdle.js +12 -0
- package/dist/agents/registerAgent.d.ts +6 -0
- package/dist/agents/registerAgent.js +29 -0
- package/dist/agents/types.d.ts +30 -0
- package/dist/agents/types.js +1 -0
- package/dist/agents/unregisterAgent.d.ts +5 -0
- package/dist/agents/unregisterAgent.js +8 -0
- package/dist/agents/updateAgentContext.d.ts +5 -0
- package/dist/agents/updateAgentContext.js +12 -0
- package/dist/agents/updateAgentTask.d.ts +5 -0
- package/dist/agents/updateAgentTask.js +12 -0
- package/dist/agents/updateAgentWorktree.d.ts +5 -0
- package/dist/agents/updateAgentWorktree.js +12 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +8 -0
- package/dist/cli/init.d.ts +14 -0
- package/dist/cli/init.js +71 -0
- package/dist/cli/install.d.ts +8 -0
- package/dist/cli/install.js +47 -0
- package/dist/cli/join.d.ts +9 -0
- package/dist/cli/join.js +38 -0
- package/dist/cli/registerMcp.d.ts +28 -0
- package/dist/cli/registerMcp.js +138 -0
- package/dist/cli/status.d.ts +8 -0
- package/dist/cli/status.js +82 -0
- package/dist/cli/watch.d.ts +6 -0
- package/dist/cli/watch.js +68 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +49 -0
- package/dist/coordinator/coordinator.test.d.ts +1 -0
- package/dist/coordinator/coordinator.test.js +171 -0
- package/dist/coordinator/index.d.ts +16 -0
- package/dist/coordinator/index.js +166 -0
- package/dist/coordinator/spawn.d.ts +22 -0
- package/dist/coordinator/spawn.js +66 -0
- package/dist/datetime/datetime.test.d.ts +1 -0
- package/dist/datetime/datetime.test.js +63 -0
- package/dist/datetime/formatDate.d.ts +6 -0
- package/dist/datetime/formatDate.js +11 -0
- package/dist/datetime/formatDatetime.d.ts +6 -0
- package/dist/datetime/formatDatetime.js +12 -0
- package/dist/datetime/formatTime.d.ts +6 -0
- package/dist/datetime/formatTime.js +11 -0
- package/dist/datetime/index.d.ts +4 -0
- package/dist/datetime/index.js +7 -0
- package/dist/datetime/isStale.d.ts +10 -0
- package/dist/datetime/isStale.js +18 -0
- package/dist/datetime/now.d.ts +6 -0
- package/dist/datetime/now.js +9 -0
- package/dist/datetime/parseDatetime.d.ts +7 -0
- package/dist/datetime/parseDatetime.js +28 -0
- package/dist/db/constants.d.ts +4 -0
- package/dist/db/constants.js +6 -0
- package/dist/db/db.test.d.ts +1 -0
- package/dist/db/db.test.js +141 -0
- package/dist/db/ensureProjectDirs.d.ts +4 -0
- package/dist/db/ensureProjectDirs.js +12 -0
- package/dist/db/getConnection.d.ts +19 -0
- package/dist/db/getConnection.js +51 -0
- package/dist/db/getCurrentProject.d.ts +8 -0
- package/dist/db/getCurrentProject.js +14 -0
- package/dist/db/getProjectPaths.d.ts +21 -0
- package/dist/db/getProjectPaths.js +26 -0
- package/dist/db/index.d.ts +10 -0
- package/dist/db/index.js +13 -0
- package/dist/db/initializeDb.d.ts +7 -0
- package/dist/db/initializeDb.js +23 -0
- package/dist/db/nextEventSeq.d.ts +5 -0
- package/dist/db/nextEventSeq.js +13 -0
- package/dist/db/nextSubtaskSeq.d.ts +5 -0
- package/dist/db/nextSubtaskSeq.js +12 -0
- package/dist/db/nextTaskSeq.d.ts +5 -0
- package/dist/db/nextTaskSeq.js +13 -0
- package/dist/db/resetDb.d.ts +10 -0
- package/dist/db/resetDb.js +36 -0
- package/dist/events/emit.d.ts +6 -0
- package/dist/events/emit.js +31 -0
- package/dist/events/events.test.d.ts +1 -0
- package/dist/events/events.test.js +145 -0
- package/dist/events/getEventsByAgent.d.ts +6 -0
- package/dist/events/getEventsByAgent.js +14 -0
- package/dist/events/getEventsByBranch.d.ts +6 -0
- package/dist/events/getEventsByBranch.js +12 -0
- package/dist/events/getEventsByPlan.d.ts +6 -0
- package/dist/events/getEventsByPlan.js +14 -0
- package/dist/events/getEventsByWorktree.d.ts +6 -0
- package/dist/events/getEventsByWorktree.js +12 -0
- package/dist/events/getEventsSince.d.ts +12 -0
- package/dist/events/getEventsSince.js +47 -0
- package/dist/events/getRecentEvents.d.ts +6 -0
- package/dist/events/getRecentEvents.js +12 -0
- package/dist/events/index.d.ts +8 -0
- package/dist/events/index.js +9 -0
- package/dist/events/types.d.ts +34 -0
- package/dist/events/types.js +1 -0
- package/dist/git/getBranch.d.ts +4 -0
- package/dist/git/getBranch.js +14 -0
- package/dist/git/getCurrentWorktree.d.ts +5 -0
- package/dist/git/getCurrentWorktree.js +15 -0
- package/dist/git/getGitInfo.d.ts +10 -0
- package/dist/git/getGitInfo.js +23 -0
- package/dist/git/getRepoName.d.ts +4 -0
- package/dist/git/getRepoName.js +32 -0
- package/dist/git/getRepoRoot.d.ts +4 -0
- package/dist/git/getRepoRoot.js +14 -0
- package/dist/git/getWorktrees.d.ts +10 -0
- package/dist/git/getWorktrees.js +39 -0
- package/dist/git/index.d.ts +9 -0
- package/dist/git/index.js +7 -0
- package/dist/git/isGitRepo.d.ts +4 -0
- package/dist/git/isGitRepo.js +13 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/sessionStart.d.ts +21 -0
- package/dist/hooks/sessionStart.js +93 -0
- package/dist/ids/generateHex.d.ts +4 -0
- package/dist/ids/generateHex.js +7 -0
- package/dist/ids/getParentTaskId.d.ts +7 -0
- package/dist/ids/getParentTaskId.js +15 -0
- package/dist/ids/getPlanHexFromTaskId.d.ts +6 -0
- package/dist/ids/getPlanHexFromTaskId.js +9 -0
- package/dist/ids/ids.test.d.ts +1 -0
- package/dist/ids/ids.test.js +215 -0
- package/dist/ids/index.d.ts +16 -0
- package/dist/ids/index.js +17 -0
- package/dist/ids/isSubtask.d.ts +7 -0
- package/dist/ids/isSubtask.js +11 -0
- package/dist/ids/isValidId.d.ts +9 -0
- package/dist/ids/isValidId.js +22 -0
- package/dist/ids/makeAgentId.d.ts +8 -0
- package/dist/ids/makeAgentId.js +15 -0
- package/dist/ids/makeEventId.d.ts +11 -0
- package/dist/ids/makeEventId.js +12 -0
- package/dist/ids/makePlanId.d.ts +11 -0
- package/dist/ids/makePlanId.js +15 -0
- package/dist/ids/makeSubtaskId.d.ts +8 -0
- package/dist/ids/makeSubtaskId.js +15 -0
- package/dist/ids/makeTaskId.d.ts +8 -0
- package/dist/ids/makeTaskId.js +14 -0
- package/dist/ids/makeWorktreeId.d.ts +5 -0
- package/dist/ids/makeWorktreeId.js +12 -0
- package/dist/ids/parseId.d.ts +11 -0
- package/dist/ids/parseId.js +26 -0
- package/dist/ids/sanitizeLabel.d.ts +7 -0
- package/dist/ids/sanitizeLabel.js +12 -0
- package/dist/ids/typedIds.d.ts +34 -0
- package/dist/ids/typedIds.js +22 -0
- package/dist/ids/types.d.ts +14 -0
- package/dist/ids/types.js +1 -0
- package/dist/init/claudeConfig.d.ts +39 -0
- package/dist/init/claudeConfig.js +161 -0
- package/dist/llm/extractTasks.d.ts +28 -0
- package/dist/llm/extractTasks.js +108 -0
- package/dist/llm/index.d.ts +2 -0
- package/dist/llm/index.js +2 -0
- package/dist/llm/reconcileTasks.d.ts +21 -0
- package/dist/llm/reconcileTasks.js +82 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +100 -0
- package/dist/mcp/tools/emitEvent.d.ts +62 -0
- package/dist/mcp/tools/emitEvent.js +84 -0
- package/dist/mcp/tools/events.d.ts +55 -0
- package/dist/mcp/tools/events.js +56 -0
- package/dist/mcp/tools/index.d.ts +18 -0
- package/dist/mcp/tools/index.js +13 -0
- package/dist/mcp/tools/query.d.ts +54 -0
- package/dist/mcp/tools/query.js +70 -0
- package/dist/mcp/tools/register.d.ts +47 -0
- package/dist/mcp/tools/register.js +79 -0
- package/dist/mcp/tools/reset.d.ts +38 -0
- package/dist/mcp/tools/reset.js +56 -0
- package/dist/mcp/tools/setup.d.ts +42 -0
- package/dist/mcp/tools/setup.js +75 -0
- package/dist/mcp/tools/status.d.ts +44 -0
- package/dist/mcp/tools/status.js +74 -0
- package/dist/mcp/tools/tasks.d.ts +116 -0
- package/dist/mcp/tools/tasks.js +143 -0
- package/dist/mcp/tools/worktreeCleanup.d.ts +38 -0
- package/dist/mcp/tools/worktreeCleanup.js +67 -0
- package/dist/plans/createPlan.d.ts +6 -0
- package/dist/plans/createPlan.js +29 -0
- package/dist/plans/getActivePlans.d.ts +6 -0
- package/dist/plans/getActivePlans.js +11 -0
- package/dist/plans/getPlan.d.ts +6 -0
- package/dist/plans/getPlan.js +7 -0
- package/dist/plans/index.d.ts +5 -0
- package/dist/plans/index.js +5 -0
- package/dist/plans/plans.test.d.ts +1 -0
- package/dist/plans/plans.test.js +107 -0
- package/dist/plans/types.d.ts +32 -0
- package/dist/plans/types.js +1 -0
- package/dist/plans/updatePlanStatus.d.ts +6 -0
- package/dist/plans/updatePlanStatus.js +8 -0
- package/dist/tasks/assignTask.d.ts +7 -0
- package/dist/tasks/assignTask.js +20 -0
- package/dist/tasks/blockTask.d.ts +5 -0
- package/dist/tasks/blockTask.js +12 -0
- package/dist/tasks/claimTask.d.ts +7 -0
- package/dist/tasks/claimTask.js +21 -0
- package/dist/tasks/completeTask.d.ts +6 -0
- package/dist/tasks/completeTask.js +18 -0
- package/dist/tasks/createTask.d.ts +6 -0
- package/dist/tasks/createTask.js +36 -0
- package/dist/tasks/getPendingTasks.d.ts +6 -0
- package/dist/tasks/getPendingTasks.js +19 -0
- package/dist/tasks/getTask.d.ts +6 -0
- package/dist/tasks/getTask.js +7 -0
- package/dist/tasks/getTasksByPlan.d.ts +6 -0
- package/dist/tasks/getTasksByPlan.js +11 -0
- package/dist/tasks/index.d.ts +11 -0
- package/dist/tasks/index.js +12 -0
- package/dist/tasks/startTask.d.ts +5 -0
- package/dist/tasks/startTask.js +12 -0
- package/dist/tasks/tasks.test.d.ts +1 -0
- package/dist/tasks/tasks.test.js +209 -0
- package/dist/tasks/types.d.ts +36 -0
- package/dist/tasks/types.js +1 -0
- package/dist/tasks/unclaimTask.d.ts +5 -0
- package/dist/tasks/unclaimTask.js +12 -0
- package/dist/test/factories/agentFactory.d.ts +13 -0
- package/dist/test/factories/agentFactory.js +5 -0
- package/dist/test/factories/eventFactory.d.ts +20 -0
- package/dist/test/factories/eventFactory.js +16 -0
- package/dist/test/factories/factories.test.d.ts +1 -0
- package/dist/test/factories/factories.test.js +101 -0
- package/dist/test/factories/index.d.ts +4 -0
- package/dist/test/factories/index.js +4 -0
- package/dist/test/factories/planFactory.d.ts +15 -0
- package/dist/test/factories/planFactory.js +14 -0
- package/dist/test/factories/taskFactory.d.ts +22 -0
- package/dist/test/factories/taskFactory.js +44 -0
- package/dist/test/multiAgentDemo.d.ts +16 -0
- package/dist/test/multiAgentDemo.js +20 -0
- package/dist/test/multiAgentDemo.test.d.ts +1 -0
- package/dist/test/multiAgentDemo.test.js +14 -0
- package/dist/test/setup.d.ts +9 -0
- package/dist/test/setup.js +50 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/math.d.ts +6 -0
- package/dist/utils/math.js +10 -0
- package/dist/utils/math.test.d.ts +1 -0
- package/dist/utils/math.test.js +26 -0
- package/dist/utils/string.d.ts +11 -0
- package/dist/utils/string.js +17 -0
- package/dist/utils/string.test.d.ts +1 -0
- package/dist/utils/string.test.js +30 -0
- package/dist/watcher/index.d.ts +1 -0
- package/dist/watcher/index.js +1 -0
- package/dist/watcher/planWatcher.d.ts +31 -0
- package/dist/watcher/planWatcher.js +171 -0
- package/dist/worktrees/getAllWorktrees.d.ts +6 -0
- package/dist/worktrees/getAllWorktrees.js +10 -0
- package/dist/worktrees/getWorktreeById.d.ts +6 -0
- package/dist/worktrees/getWorktreeById.js +7 -0
- package/dist/worktrees/getWorktreeByPath.d.ts +6 -0
- package/dist/worktrees/getWorktreeByPath.js +7 -0
- package/dist/worktrees/index.d.ts +9 -0
- package/dist/worktrees/index.js +13 -0
- package/dist/worktrees/registerWorktree.d.ts +6 -0
- package/dist/worktrees/registerWorktree.js +28 -0
- package/dist/worktrees/removeWorktree.d.ts +6 -0
- package/dist/worktrees/removeWorktree.js +9 -0
- package/dist/worktrees/syncWorktreesFromGit.d.ts +7 -0
- package/dist/worktrees/syncWorktreesFromGit.js +51 -0
- package/dist/worktrees/types.d.ts +29 -0
- package/dist/worktrees/types.js +1 -0
- package/dist/worktrees/updateWorktreeCommit.d.ts +5 -0
- package/dist/worktrees/updateWorktreeCommit.js +13 -0
- package/dist/worktrees/updateWorktreeSeen.d.ts +5 -0
- package/dist/worktrees/updateWorktreeSeen.js +13 -0
- package/package.json +58 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { getProjectPaths } from '../../db/getProjectPaths';
|
|
3
|
+
import { initializeDb } from '../../db/initializeDb';
|
|
4
|
+
import { formatDatetime } from '../../datetime/formatDatetime';
|
|
5
|
+
import { getGitInfo } from '../../git/getGitInfo';
|
|
6
|
+
export const setupTool = {
|
|
7
|
+
name: 'hivemind_setup',
|
|
8
|
+
description: 'Initialize hivemind for a project. Detects git repo info automatically.',
|
|
9
|
+
annotations: {
|
|
10
|
+
readOnlyHint: false,
|
|
11
|
+
destructiveHint: false,
|
|
12
|
+
idempotentHint: true,
|
|
13
|
+
openWorldHint: false,
|
|
14
|
+
},
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
project: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Project name. If omitted, will use git repo name or prompt.',
|
|
21
|
+
},
|
|
22
|
+
useGit: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: 'Use git repo info for project name (default: true if in git repo)',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Execute setup - may return prompt for user input
|
|
31
|
+
*/
|
|
32
|
+
export function executeSetup(input) {
|
|
33
|
+
const gitInfo = getGitInfo();
|
|
34
|
+
// If no project specified and we're in a git repo, ask to use it
|
|
35
|
+
if (!input.project && gitInfo.isRepo && input.useGit === undefined) {
|
|
36
|
+
return {
|
|
37
|
+
needsInput: true,
|
|
38
|
+
gitInfo: {
|
|
39
|
+
repoName: gitInfo.repoName,
|
|
40
|
+
branch: gitInfo.branch,
|
|
41
|
+
root: gitInfo.root,
|
|
42
|
+
},
|
|
43
|
+
message: `Git repository detected: ${gitInfo.repoName}\nUse this for project name? (set useGit: true/false)`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Determine project name
|
|
47
|
+
let projectName;
|
|
48
|
+
if (input.project) {
|
|
49
|
+
projectName = input.project;
|
|
50
|
+
}
|
|
51
|
+
else if (input.useGit !== false && gitInfo.isRepo && gitInfo.repoName) {
|
|
52
|
+
projectName = gitInfo.repoName;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
projectName = process.cwd().split('/').pop() || 'default';
|
|
56
|
+
}
|
|
57
|
+
// Initialize
|
|
58
|
+
const paths = getProjectPaths(projectName);
|
|
59
|
+
const isNew = !existsSync(paths.dbPath);
|
|
60
|
+
const db = initializeDb(projectName);
|
|
61
|
+
let stats = '';
|
|
62
|
+
if (!isNew) {
|
|
63
|
+
const agentCount = db.prepare('SELECT COUNT(*) as c FROM agents').get().c;
|
|
64
|
+
const planCount = db.prepare('SELECT COUNT(*) as c FROM plans').get().c;
|
|
65
|
+
const eventCount = db.prepare('SELECT COUNT(*) as c FROM events').get().c;
|
|
66
|
+
stats = `\nstats: ${agentCount} agents, ${planCount} plans, ${eventCount} events`;
|
|
67
|
+
}
|
|
68
|
+
db.close();
|
|
69
|
+
return {
|
|
70
|
+
needsInput: false,
|
|
71
|
+
project: projectName,
|
|
72
|
+
dbPath: paths.dbPath,
|
|
73
|
+
message: `hivemind ${isNew ? 'created' : 'connected'}: ${projectName}\ndb: ${paths.dbPath}${stats}\ntimestamp: ${formatDatetime()}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Agent } from '../../agents/types';
|
|
2
|
+
import type { WorktreeRecord } from '../../worktrees/types';
|
|
3
|
+
import type { Event } from '../../events/types';
|
|
4
|
+
import type { Plan } from '../../plans/types';
|
|
5
|
+
export declare const statusTool: {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
annotations: {
|
|
9
|
+
readOnlyHint: boolean;
|
|
10
|
+
destructiveHint: boolean;
|
|
11
|
+
idempotentHint: boolean;
|
|
12
|
+
openWorldHint: boolean;
|
|
13
|
+
};
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: string;
|
|
16
|
+
properties: {
|
|
17
|
+
project: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
required: string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type StatusInput = {
|
|
26
|
+
project: string;
|
|
27
|
+
};
|
|
28
|
+
export type PlanWithTasks = Plan & {
|
|
29
|
+
taskCounts: {
|
|
30
|
+
pending: number;
|
|
31
|
+
in_progress: number;
|
|
32
|
+
done: number;
|
|
33
|
+
total: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export type StatusResult = {
|
|
37
|
+
project: string;
|
|
38
|
+
activeAgents: Agent[];
|
|
39
|
+
worktrees: WorktreeRecord[];
|
|
40
|
+
plans: PlanWithTasks[];
|
|
41
|
+
recentEvents: Event[];
|
|
42
|
+
summary: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function executeStatus(input: StatusInput): StatusResult;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { getConnection } from '../../db/getConnection';
|
|
2
|
+
import { getActiveAgents } from '../../agents/getActiveAgents';
|
|
3
|
+
import { getAllWorktrees } from '../../worktrees/getAllWorktrees';
|
|
4
|
+
import { getRecentEvents } from '../../events/getRecentEvents';
|
|
5
|
+
import { getActivePlans } from '../../plans/getActivePlans';
|
|
6
|
+
export const statusTool = {
|
|
7
|
+
name: 'hivemind_status',
|
|
8
|
+
description: 'Get current hivemind status: active agents, worktrees, recent events.',
|
|
9
|
+
annotations: {
|
|
10
|
+
readOnlyHint: true,
|
|
11
|
+
destructiveHint: false,
|
|
12
|
+
idempotentHint: true,
|
|
13
|
+
openWorldHint: false,
|
|
14
|
+
},
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
project: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Project name',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ['project'],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export function executeStatus(input) {
|
|
27
|
+
const db = getConnection(input.project);
|
|
28
|
+
const activeAgents = getActiveAgents(db);
|
|
29
|
+
const worktrees = getAllWorktrees(db);
|
|
30
|
+
const recentEvents = getRecentEvents(db, 10);
|
|
31
|
+
// Get active plans with task counts
|
|
32
|
+
const activePlans = getActivePlans(db);
|
|
33
|
+
const plans = activePlans.map((plan) => {
|
|
34
|
+
const counts = db
|
|
35
|
+
.prepare(`
|
|
36
|
+
SELECT
|
|
37
|
+
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
|
|
38
|
+
SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
|
|
39
|
+
SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as done,
|
|
40
|
+
COUNT(*) as total
|
|
41
|
+
FROM tasks
|
|
42
|
+
WHERE plan_id = ?
|
|
43
|
+
`)
|
|
44
|
+
.get(plan.id);
|
|
45
|
+
return {
|
|
46
|
+
...plan,
|
|
47
|
+
taskCounts: {
|
|
48
|
+
pending: counts?.pending ?? 0,
|
|
49
|
+
in_progress: counts?.in_progress ?? 0,
|
|
50
|
+
done: counts?.done ?? 0,
|
|
51
|
+
total: counts?.total ?? 0,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
// Count plans with open work
|
|
56
|
+
const plansWithWork = plans.filter((p) => p.taskCounts.pending > 0 || p.taskCounts.in_progress > 0);
|
|
57
|
+
const summary = [
|
|
58
|
+
`hivemind:${input.project}`,
|
|
59
|
+
`${activeAgents.length} active agent(s)`,
|
|
60
|
+
`${worktrees.length} worktree(s)`,
|
|
61
|
+
plansWithWork.length > 0 ? `${plansWithWork.length} plan(s) with open work` : null,
|
|
62
|
+
`${recentEvents.length} recent event(s)`,
|
|
63
|
+
]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(' | ');
|
|
66
|
+
return {
|
|
67
|
+
project: input.project,
|
|
68
|
+
activeAgents,
|
|
69
|
+
worktrees,
|
|
70
|
+
plans,
|
|
71
|
+
recentEvents,
|
|
72
|
+
summary,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task management MCP tools
|
|
3
|
+
* - Claim tasks to work on
|
|
4
|
+
* - Complete tasks when done
|
|
5
|
+
*/
|
|
6
|
+
export declare const claimTaskTool: {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
annotations: {
|
|
10
|
+
readOnlyHint: boolean;
|
|
11
|
+
destructiveHint: boolean;
|
|
12
|
+
idempotentHint: boolean;
|
|
13
|
+
openWorldHint: boolean;
|
|
14
|
+
};
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: string;
|
|
17
|
+
properties: {
|
|
18
|
+
project: {
|
|
19
|
+
type: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
taskId: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
agentId: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
required: string[];
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export type ClaimTaskInput = {
|
|
35
|
+
project: string;
|
|
36
|
+
taskId: string;
|
|
37
|
+
agentId: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function executeClaimTask(input: ClaimTaskInput): {
|
|
40
|
+
success: boolean;
|
|
41
|
+
message: string;
|
|
42
|
+
};
|
|
43
|
+
export declare const startTaskTool: {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
annotations: {
|
|
47
|
+
readOnlyHint: boolean;
|
|
48
|
+
destructiveHint: boolean;
|
|
49
|
+
idempotentHint: boolean;
|
|
50
|
+
openWorldHint: boolean;
|
|
51
|
+
};
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: string;
|
|
54
|
+
properties: {
|
|
55
|
+
project: {
|
|
56
|
+
type: string;
|
|
57
|
+
description: string;
|
|
58
|
+
};
|
|
59
|
+
taskId: {
|
|
60
|
+
type: string;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
agentId: {
|
|
64
|
+
type: string;
|
|
65
|
+
description: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
required: string[];
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export type StartTaskInput = {
|
|
72
|
+
project: string;
|
|
73
|
+
taskId: string;
|
|
74
|
+
agentId: string;
|
|
75
|
+
};
|
|
76
|
+
export declare function executeStartTask(input: StartTaskInput): {
|
|
77
|
+
success: boolean;
|
|
78
|
+
message: string;
|
|
79
|
+
};
|
|
80
|
+
export declare const completeTaskTool: {
|
|
81
|
+
name: string;
|
|
82
|
+
description: string;
|
|
83
|
+
annotations: {
|
|
84
|
+
readOnlyHint: boolean;
|
|
85
|
+
destructiveHint: boolean;
|
|
86
|
+
idempotentHint: boolean;
|
|
87
|
+
openWorldHint: boolean;
|
|
88
|
+
};
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: string;
|
|
91
|
+
properties: {
|
|
92
|
+
project: {
|
|
93
|
+
type: string;
|
|
94
|
+
description: string;
|
|
95
|
+
};
|
|
96
|
+
taskId: {
|
|
97
|
+
type: string;
|
|
98
|
+
description: string;
|
|
99
|
+
};
|
|
100
|
+
agentId: {
|
|
101
|
+
type: string;
|
|
102
|
+
description: string;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
required: string[];
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
export type CompleteTaskInput = {
|
|
109
|
+
project: string;
|
|
110
|
+
taskId: string;
|
|
111
|
+
agentId: string;
|
|
112
|
+
};
|
|
113
|
+
export declare function executeCompleteTask(input: CompleteTaskInput): {
|
|
114
|
+
success: boolean;
|
|
115
|
+
message: string;
|
|
116
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task management MCP tools
|
|
3
|
+
* - Claim tasks to work on
|
|
4
|
+
* - Complete tasks when done
|
|
5
|
+
*/
|
|
6
|
+
import { getConnection } from '../../db/getConnection';
|
|
7
|
+
import { getTask } from '../../tasks/getTask';
|
|
8
|
+
import { claimTask } from '../../tasks/claimTask';
|
|
9
|
+
import { completeTask } from '../../tasks/completeTask';
|
|
10
|
+
import { startTask } from '../../tasks/startTask';
|
|
11
|
+
import { emit } from '../../events/emit';
|
|
12
|
+
// ─────────────────────────────────────────────────────────────
|
|
13
|
+
// Claim Task
|
|
14
|
+
// ─────────────────────────────────────────────────────────────
|
|
15
|
+
export const claimTaskTool = {
|
|
16
|
+
name: 'hivemind_claim_task',
|
|
17
|
+
description: 'Claim a task to work on. Other agents will see you own this task.',
|
|
18
|
+
annotations: {
|
|
19
|
+
readOnlyHint: false,
|
|
20
|
+
destructiveHint: false,
|
|
21
|
+
idempotentHint: true,
|
|
22
|
+
openWorldHint: false,
|
|
23
|
+
},
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
project: { type: 'string', description: 'Project name' },
|
|
28
|
+
taskId: { type: 'string', description: 'Task ID to claim' },
|
|
29
|
+
agentId: { type: 'string', description: 'Your agent ID' },
|
|
30
|
+
},
|
|
31
|
+
required: ['project', 'taskId', 'agentId'],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export function executeClaimTask(input) {
|
|
35
|
+
const db = getConnection(input.project);
|
|
36
|
+
const task = getTask(db, input.taskId);
|
|
37
|
+
if (!task) {
|
|
38
|
+
return { success: false, message: `Task ${input.taskId} not found` };
|
|
39
|
+
}
|
|
40
|
+
if (task.status === 'done') {
|
|
41
|
+
return { success: false, message: `Task ${input.taskId} is already done` };
|
|
42
|
+
}
|
|
43
|
+
if (task.claimed_by && task.claimed_by !== input.agentId) {
|
|
44
|
+
return { success: false, message: `Task ${input.taskId} is claimed by ${task.claimed_by}` };
|
|
45
|
+
}
|
|
46
|
+
const result = claimTask(db, input.taskId, input.agentId);
|
|
47
|
+
if (!result) {
|
|
48
|
+
return { success: false, message: `Failed to claim task ${input.taskId}` };
|
|
49
|
+
}
|
|
50
|
+
emit(db, {
|
|
51
|
+
type: 'task:claim',
|
|
52
|
+
content: `${input.agentId} claimed: ${task.title}`,
|
|
53
|
+
agent_id: input.agentId,
|
|
54
|
+
task_id: input.taskId,
|
|
55
|
+
plan_id: task.plan_id,
|
|
56
|
+
});
|
|
57
|
+
return { success: true, message: `Claimed task: ${task.title}` };
|
|
58
|
+
}
|
|
59
|
+
// ─────────────────────────────────────────────────────────────
|
|
60
|
+
// Start Task (mark in progress)
|
|
61
|
+
// ─────────────────────────────────────────────────────────────
|
|
62
|
+
export const startTaskTool = {
|
|
63
|
+
name: 'hivemind_start_task',
|
|
64
|
+
description: 'Mark a task as in progress. Call after claiming when you begin work.',
|
|
65
|
+
annotations: {
|
|
66
|
+
readOnlyHint: false,
|
|
67
|
+
destructiveHint: false,
|
|
68
|
+
idempotentHint: true,
|
|
69
|
+
openWorldHint: false,
|
|
70
|
+
},
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
project: { type: 'string', description: 'Project name' },
|
|
75
|
+
taskId: { type: 'string', description: 'Task ID to start' },
|
|
76
|
+
agentId: { type: 'string', description: 'Your agent ID' },
|
|
77
|
+
},
|
|
78
|
+
required: ['project', 'taskId', 'agentId'],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
export function executeStartTask(input) {
|
|
82
|
+
const db = getConnection(input.project);
|
|
83
|
+
const task = getTask(db, input.taskId);
|
|
84
|
+
if (!task) {
|
|
85
|
+
return { success: false, message: `Task ${input.taskId} not found` };
|
|
86
|
+
}
|
|
87
|
+
if (task.status === 'done') {
|
|
88
|
+
return { success: false, message: `Task ${input.taskId} is already done` };
|
|
89
|
+
}
|
|
90
|
+
startTask(db, input.taskId);
|
|
91
|
+
emit(db, {
|
|
92
|
+
type: 'task:start',
|
|
93
|
+
content: `${input.agentId} started: ${task.title}`,
|
|
94
|
+
agent_id: input.agentId,
|
|
95
|
+
task_id: input.taskId,
|
|
96
|
+
plan_id: task.plan_id,
|
|
97
|
+
});
|
|
98
|
+
return { success: true, message: `Started task: ${task.title}` };
|
|
99
|
+
}
|
|
100
|
+
// ─────────────────────────────────────────────────────────────
|
|
101
|
+
// Complete Task
|
|
102
|
+
// ─────────────────────────────────────────────────────────────
|
|
103
|
+
export const completeTaskTool = {
|
|
104
|
+
name: 'hivemind_complete_task',
|
|
105
|
+
description: 'Mark a task as done.',
|
|
106
|
+
annotations: {
|
|
107
|
+
readOnlyHint: false,
|
|
108
|
+
destructiveHint: false,
|
|
109
|
+
idempotentHint: true,
|
|
110
|
+
openWorldHint: false,
|
|
111
|
+
},
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
project: { type: 'string', description: 'Project name' },
|
|
116
|
+
taskId: { type: 'string', description: 'Task ID to complete' },
|
|
117
|
+
agentId: { type: 'string', description: 'Your agent ID' },
|
|
118
|
+
},
|
|
119
|
+
required: ['project', 'taskId', 'agentId'],
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
export function executeCompleteTask(input) {
|
|
123
|
+
const db = getConnection(input.project);
|
|
124
|
+
const task = getTask(db, input.taskId);
|
|
125
|
+
if (!task) {
|
|
126
|
+
return { success: false, message: `Task ${input.taskId} not found` };
|
|
127
|
+
}
|
|
128
|
+
if (task.status === 'done') {
|
|
129
|
+
return { success: false, message: `Task ${input.taskId} is already done` };
|
|
130
|
+
}
|
|
131
|
+
const result = completeTask(db, input.taskId);
|
|
132
|
+
if (!result) {
|
|
133
|
+
return { success: false, message: `Failed to complete task ${input.taskId}` };
|
|
134
|
+
}
|
|
135
|
+
emit(db, {
|
|
136
|
+
type: 'task:complete',
|
|
137
|
+
content: `${input.agentId} completed: ${task.title}`,
|
|
138
|
+
agent_id: input.agentId,
|
|
139
|
+
task_id: input.taskId,
|
|
140
|
+
plan_id: task.plan_id,
|
|
141
|
+
});
|
|
142
|
+
return { success: true, message: `Completed task: ${task.title}` };
|
|
143
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hivemind_worktree_cleanup - Clean up stale worktrees
|
|
3
|
+
*/
|
|
4
|
+
export declare const worktreeCleanupTool: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
annotations: {
|
|
8
|
+
readOnlyHint: boolean;
|
|
9
|
+
destructiveHint: boolean;
|
|
10
|
+
idempotentHint: boolean;
|
|
11
|
+
openWorldHint: boolean;
|
|
12
|
+
};
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object";
|
|
15
|
+
properties: {
|
|
16
|
+
project: {
|
|
17
|
+
type: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
dryRun: {
|
|
21
|
+
type: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
required: string[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export type WorktreeCleanupInput = {
|
|
29
|
+
project: string;
|
|
30
|
+
dryRun?: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type WorktreeCleanupResult = {
|
|
33
|
+
checked: number;
|
|
34
|
+
removed: string[];
|
|
35
|
+
kept: string[];
|
|
36
|
+
dryRun: boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare function executeWorktreeCleanup(input: WorktreeCleanupInput): WorktreeCleanupResult;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hivemind_worktree_cleanup - Clean up stale worktrees
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
import { getConnection } from '../../db/getConnection';
|
|
6
|
+
import { getAllWorktrees } from '../../worktrees/getAllWorktrees';
|
|
7
|
+
import { removeWorktree } from '../../worktrees/removeWorktree';
|
|
8
|
+
import { emit } from '../../events/emit';
|
|
9
|
+
export const worktreeCleanupTool = {
|
|
10
|
+
name: 'hivemind_worktree_cleanup',
|
|
11
|
+
description: 'Clean up stale worktrees from hivemind database',
|
|
12
|
+
annotations: {
|
|
13
|
+
readOnlyHint: false,
|
|
14
|
+
destructiveHint: true,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
project: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Project name',
|
|
24
|
+
},
|
|
25
|
+
dryRun: {
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
description: 'Preview without deleting',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['project'],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export function executeWorktreeCleanup(input) {
|
|
34
|
+
const db = getConnection(input.project);
|
|
35
|
+
const worktrees = getAllWorktrees(db);
|
|
36
|
+
const removed = [];
|
|
37
|
+
const kept = [];
|
|
38
|
+
for (const wt of worktrees) {
|
|
39
|
+
const exists = existsSync(wt.path);
|
|
40
|
+
if (!exists) {
|
|
41
|
+
if (!input.dryRun) {
|
|
42
|
+
removeWorktree(db, wt.id);
|
|
43
|
+
emit(db, {
|
|
44
|
+
type: 'worktree:stale',
|
|
45
|
+
worktree_id: wt.id,
|
|
46
|
+
branch: wt.branch ?? undefined,
|
|
47
|
+
content: `Worktree removed: ${wt.path} (path gone)`,
|
|
48
|
+
metadata: {
|
|
49
|
+
path: wt.path,
|
|
50
|
+
branch: wt.branch,
|
|
51
|
+
last_seen: wt.last_seen,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
removed.push(`${wt.id} (${wt.path})`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
kept.push(`${wt.id} (${wt.path})`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
checked: worktrees.length,
|
|
63
|
+
removed,
|
|
64
|
+
kept,
|
|
65
|
+
dryRun: input.dryRun ?? false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { makePlanId } from '../ids/makePlanId';
|
|
2
|
+
import { sanitizeLabel } from '../ids/sanitizeLabel';
|
|
3
|
+
import { now } from '../datetime/now';
|
|
4
|
+
/**
|
|
5
|
+
* Create a new plan
|
|
6
|
+
*/
|
|
7
|
+
export function createPlan(db, input) {
|
|
8
|
+
const { id, hex } = makePlanId(input.label);
|
|
9
|
+
const label = input.label ? sanitizeLabel(input.label) : null;
|
|
10
|
+
const timestamp = now();
|
|
11
|
+
const stmt = db.prepare(`
|
|
12
|
+
INSERT INTO plans (id, hex, label, title, description, status, branch, worktree_id, claude_session_id, created_at, created_by)
|
|
13
|
+
VALUES (?, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?)
|
|
14
|
+
`);
|
|
15
|
+
stmt.run(id, hex, label, input.title, input.description ?? null, input.branch ?? null, input.worktree_id ?? null, input.claude_session_id ?? null, timestamp, input.created_by ?? null);
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
hex,
|
|
19
|
+
label,
|
|
20
|
+
title: input.title,
|
|
21
|
+
description: input.description ?? null,
|
|
22
|
+
status: 'active',
|
|
23
|
+
branch: input.branch ?? null,
|
|
24
|
+
worktree_id: input.worktree_id ?? null,
|
|
25
|
+
claude_session_id: input.claude_session_id ?? null,
|
|
26
|
+
created_at: timestamp,
|
|
27
|
+
created_by: input.created_by ?? null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|