@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,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize a label for use in IDs
|
|
3
|
+
* - lowercase
|
|
4
|
+
* - remove special chars (keep alphanumeric only)
|
|
5
|
+
* - max 20 chars
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeLabel(label) {
|
|
8
|
+
return label
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/[^a-z0-9]/g, '')
|
|
11
|
+
.slice(0, 20);
|
|
12
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed ID utility for compile-time type safety
|
|
3
|
+
*
|
|
4
|
+
* Creates a "typed" string by adding a phantom type property.
|
|
5
|
+
* The __model property only exists at compile-time and has zero runtime cost.
|
|
6
|
+
*/
|
|
7
|
+
export type Id<Model> = string & {
|
|
8
|
+
readonly __model: Model;
|
|
9
|
+
};
|
|
10
|
+
export declare const HivemindIdType: {
|
|
11
|
+
readonly Agent: "AgentId";
|
|
12
|
+
readonly Plan: "PlanId";
|
|
13
|
+
readonly Task: "TaskId";
|
|
14
|
+
readonly Event: "EventId";
|
|
15
|
+
readonly Worktree: "WorktreeId";
|
|
16
|
+
};
|
|
17
|
+
export type HivemindIdType = (typeof HivemindIdType)[keyof typeof HivemindIdType];
|
|
18
|
+
export type AgentId = Id<typeof HivemindIdType.Agent>;
|
|
19
|
+
export type PlanId = Id<typeof HivemindIdType.Plan>;
|
|
20
|
+
export type TaskId = Id<typeof HivemindIdType.Task>;
|
|
21
|
+
export type EventId = Id<typeof HivemindIdType.Event>;
|
|
22
|
+
export type WorktreeId = Id<typeof HivemindIdType.Worktree>;
|
|
23
|
+
export declare const createId: <M extends HivemindIdType>(raw: string) => Id<M>;
|
|
24
|
+
export declare const agentId: (id: string) => AgentId;
|
|
25
|
+
export declare const planId: (id: string) => PlanId;
|
|
26
|
+
export declare const taskId: (id: string) => TaskId;
|
|
27
|
+
export declare const eventId: (id: string) => EventId;
|
|
28
|
+
export declare const worktreeId: (id: string) => WorktreeId;
|
|
29
|
+
export declare const isAgentId: (id: string) => id is AgentId;
|
|
30
|
+
export declare const isPlanId: (id: string) => id is PlanId;
|
|
31
|
+
export declare const isTaskId: (id: string) => id is TaskId;
|
|
32
|
+
export declare const isEventId: (id: string) => id is EventId;
|
|
33
|
+
export declare const isWorktreeId: (id: string) => id is WorktreeId;
|
|
34
|
+
export type ExtractIdType<T> = T extends AgentId ? typeof HivemindIdType.Agent : T extends PlanId ? typeof HivemindIdType.Plan : T extends TaskId ? typeof HivemindIdType.Task : T extends EventId ? typeof HivemindIdType.Event : T extends WorktreeId ? typeof HivemindIdType.Worktree : never;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Define all hivemind entity ID types
|
|
2
|
+
export const HivemindIdType = {
|
|
3
|
+
Agent: 'AgentId',
|
|
4
|
+
Plan: 'PlanId',
|
|
5
|
+
Task: 'TaskId',
|
|
6
|
+
Event: 'EventId',
|
|
7
|
+
Worktree: 'WorktreeId',
|
|
8
|
+
};
|
|
9
|
+
// Core helper functions
|
|
10
|
+
export const createId = (raw) => raw;
|
|
11
|
+
// Convenience creator functions (for casting existing strings)
|
|
12
|
+
export const agentId = (id) => id;
|
|
13
|
+
export const planId = (id) => id;
|
|
14
|
+
export const taskId = (id) => id;
|
|
15
|
+
export const eventId = (id) => id;
|
|
16
|
+
export const worktreeId = (id) => id;
|
|
17
|
+
// Type guards for runtime validation
|
|
18
|
+
export const isAgentId = (id) => id.startsWith('agt_');
|
|
19
|
+
export const isPlanId = (id) => id.startsWith('pln_');
|
|
20
|
+
export const isTaskId = (id) => id.startsWith('tsk_');
|
|
21
|
+
export const isEventId = (id) => id.startsWith('evt_');
|
|
22
|
+
export const isWorktreeId = (id) => id.startsWith('wkt_');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code configuration for hivemind
|
|
3
|
+
*
|
|
4
|
+
* When `hivemind init` runs, it sets up:
|
|
5
|
+
* 1. .claude/settings.json - SessionStart hook for auto-registration
|
|
6
|
+
* 2. .claude/CLAUDE.md - Behavioral instructions for agents
|
|
7
|
+
*
|
|
8
|
+
* Projects can customize agent behavior by adding a `## Hivemind Events`
|
|
9
|
+
* section to their root CLAUDE.md - it gets extracted and injected.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Extract a markdown section by heading from content
|
|
13
|
+
* Returns the section content (including heading) or null if not found
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractMarkdownSection(content: string, heading: string): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Build the CLAUDE.md content, optionally with custom events section
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildHivemindClaudeMd(customEventsSection?: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Settings.json hooks for auto-registration
|
|
22
|
+
*/
|
|
23
|
+
export declare function getHivemindHooks(hivemindRoot: string): {
|
|
24
|
+
hooks: {
|
|
25
|
+
SessionStart: {
|
|
26
|
+
hooks: {
|
|
27
|
+
type: string;
|
|
28
|
+
command: string;
|
|
29
|
+
}[];
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Initialize Claude Code configuration for hivemind
|
|
35
|
+
*/
|
|
36
|
+
export declare function initClaudeConfig(projectRoot: string, _project: string, hivemindRoot: string): {
|
|
37
|
+
created: string[];
|
|
38
|
+
updated: string[];
|
|
39
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code configuration for hivemind
|
|
3
|
+
*
|
|
4
|
+
* When `hivemind init` runs, it sets up:
|
|
5
|
+
* 1. .claude/settings.json - SessionStart hook for auto-registration
|
|
6
|
+
* 2. .claude/CLAUDE.md - Behavioral instructions for agents
|
|
7
|
+
*
|
|
8
|
+
* Projects can customize agent behavior by adding a `## Hivemind Events`
|
|
9
|
+
* section to their root CLAUDE.md - it gets extracted and injected.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
/**
|
|
14
|
+
* Default events instructions (used if project doesn't define custom ones)
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_EVENTS_SECTION = `## Hivemind Events
|
|
17
|
+
|
|
18
|
+
Emit concise events to coordinate. **Under 80 chars.** Map, not territory.
|
|
19
|
+
|
|
20
|
+
\`\`\`
|
|
21
|
+
hivemind_emit type=decision content="Redis for cache, Postgres for persistence"
|
|
22
|
+
hivemind_emit type=context content="API rate limit: 100/min per key"
|
|
23
|
+
hivemind_emit type=note content="003 done, starting 004"
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
**Emit for:** architectural decisions, discoveries others need, blockers, questions.
|
|
27
|
+
|
|
28
|
+
**Skip:** routine progress, obvious steps, anything verbose.`;
|
|
29
|
+
/**
|
|
30
|
+
* Extract a markdown section by heading from content
|
|
31
|
+
* Returns the section content (including heading) or null if not found
|
|
32
|
+
*/
|
|
33
|
+
export function extractMarkdownSection(content, heading) {
|
|
34
|
+
// Match ## Heading through end of section (next ## or EOF)
|
|
35
|
+
// Split into lines and find section boundaries
|
|
36
|
+
const lines = content.split('\n');
|
|
37
|
+
const startPattern = new RegExp(`^## ${heading}\\s*$`, 'i');
|
|
38
|
+
let startIdx = -1;
|
|
39
|
+
let endIdx = lines.length;
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
if (startIdx === -1 && startPattern.test(lines[i])) {
|
|
42
|
+
startIdx = i;
|
|
43
|
+
}
|
|
44
|
+
else if (startIdx !== -1 && /^## /.test(lines[i])) {
|
|
45
|
+
endIdx = i;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (startIdx === -1)
|
|
50
|
+
return null;
|
|
51
|
+
return lines.slice(startIdx, endIdx).join('\n').trim();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the CLAUDE.md content, optionally with custom events section
|
|
55
|
+
*/
|
|
56
|
+
export function buildHivemindClaudeMd(customEventsSection) {
|
|
57
|
+
const eventsSection = customEventsSection || DEFAULT_EVENTS_SECTION;
|
|
58
|
+
return `# Hivemind Agent Instructions
|
|
59
|
+
|
|
60
|
+
You are part of a **hivemind** - a coordinated group of Claude agents working together.
|
|
61
|
+
|
|
62
|
+
## Automatic Behaviors
|
|
63
|
+
|
|
64
|
+
**Your todos are automatically synced to hivemind.** When you use TodoWrite, the hivemind watcher detects changes and syncs them to a shared plan. Other agents can see your progress in real-time.
|
|
65
|
+
|
|
66
|
+
Your lifecycle is tracked by PID - no heartbeats needed. When you exit, hivemind automatically marks you as inactive.
|
|
67
|
+
|
|
68
|
+
## MCP Tools
|
|
69
|
+
|
|
70
|
+
- \`hivemind_status\` - View active agents, plans, and recent activity
|
|
71
|
+
- \`hivemind_query\` - See what other agents are doing
|
|
72
|
+
- \`hivemind_emit\` - Share notes, decisions, questions with other agents
|
|
73
|
+
|
|
74
|
+
${eventsSection}
|
|
75
|
+
|
|
76
|
+
## Coordination Protocol
|
|
77
|
+
|
|
78
|
+
1. **Before starting work**: Check \`hivemind_status\` to see what others are doing
|
|
79
|
+
2. **When making decisions**: Use \`hivemind_emit\` with type "decision" to share
|
|
80
|
+
3. **When blocked**: Use \`hivemind_emit\` with type "question" to ask for help
|
|
81
|
+
4. **Just work**: Your todos sync automatically - focus on the task!
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Settings.json hooks for auto-registration
|
|
86
|
+
*/
|
|
87
|
+
export function getHivemindHooks(hivemindRoot) {
|
|
88
|
+
return {
|
|
89
|
+
hooks: {
|
|
90
|
+
SessionStart: [
|
|
91
|
+
{
|
|
92
|
+
hooks: [
|
|
93
|
+
{
|
|
94
|
+
type: 'command',
|
|
95
|
+
command: `bun run ${hivemindRoot}/src/hooks/sessionStart.ts`,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Initialize Claude Code configuration for hivemind
|
|
105
|
+
*/
|
|
106
|
+
export function initClaudeConfig(projectRoot, _project, hivemindRoot) {
|
|
107
|
+
const claudeDir = join(projectRoot, '.claude');
|
|
108
|
+
const settingsPath = join(claudeDir, 'settings.json');
|
|
109
|
+
const claudeMdPath = join(claudeDir, 'CLAUDE.md');
|
|
110
|
+
const projectClaudeMdPath = join(projectRoot, 'CLAUDE.md');
|
|
111
|
+
const created = [];
|
|
112
|
+
const updated = [];
|
|
113
|
+
// Ensure .claude directory exists
|
|
114
|
+
if (!existsSync(claudeDir)) {
|
|
115
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
116
|
+
created.push('.claude/');
|
|
117
|
+
}
|
|
118
|
+
// Create or update settings.json
|
|
119
|
+
let settings = {};
|
|
120
|
+
if (existsSync(settingsPath)) {
|
|
121
|
+
try {
|
|
122
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Invalid JSON, start fresh
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const hooks = getHivemindHooks(hivemindRoot);
|
|
129
|
+
const existingHooks = settings.hooks;
|
|
130
|
+
if (!existingHooks?.SessionStart) {
|
|
131
|
+
settings.hooks = { ...existingHooks, ...hooks.hooks };
|
|
132
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
133
|
+
updated.push('.claude/settings.json');
|
|
134
|
+
}
|
|
135
|
+
// Extract custom events section from project's root CLAUDE.md (if exists)
|
|
136
|
+
let customEventsSection;
|
|
137
|
+
if (existsSync(projectClaudeMdPath)) {
|
|
138
|
+
const projectClaudeMd = readFileSync(projectClaudeMdPath, 'utf-8');
|
|
139
|
+
const extracted = extractMarkdownSection(projectClaudeMd, 'Hivemind Events');
|
|
140
|
+
if (extracted) {
|
|
141
|
+
customEventsSection = extracted;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Build the hivemind instructions (with custom or default events section)
|
|
145
|
+
const hivemindClaudeMd = buildHivemindClaudeMd(customEventsSection);
|
|
146
|
+
// Create or update .claude/CLAUDE.md
|
|
147
|
+
if (!existsSync(claudeMdPath)) {
|
|
148
|
+
writeFileSync(claudeMdPath, hivemindClaudeMd);
|
|
149
|
+
created.push('.claude/CLAUDE.md');
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Check if hivemind instructions are already there
|
|
153
|
+
const existing = readFileSync(claudeMdPath, 'utf-8');
|
|
154
|
+
if (!existing.includes('Hivemind Agent Instructions')) {
|
|
155
|
+
// Append hivemind instructions
|
|
156
|
+
writeFileSync(claudeMdPath, existing + '\n\n' + hivemindClaudeMd);
|
|
157
|
+
updated.push('.claude/CLAUDE.md');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return { created, updated };
|
|
161
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task extraction from plan markdown
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* 1. Fast regex parsing (default) - handles common formats instantly
|
|
6
|
+
* 2. LLM extraction (optional) - for complex plans, user-triggered
|
|
7
|
+
*/
|
|
8
|
+
export type ExtractedTask = {
|
|
9
|
+
title: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
status: 'pending' | 'in_progress' | 'done';
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Fast regex-based task extraction
|
|
15
|
+
* Handles common markdown patterns:
|
|
16
|
+
* - [ ] pending task
|
|
17
|
+
* - [x] completed task
|
|
18
|
+
* - [ ] ~in progress~ (strikethrough = in progress)
|
|
19
|
+
* ### 1. Numbered section headers
|
|
20
|
+
* 1. Numbered list items
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractTasksWithRegex(markdown: string): ExtractedTask[];
|
|
23
|
+
/**
|
|
24
|
+
* LLM-based task extraction (slower, more accurate for complex plans)
|
|
25
|
+
* Use extractTasksWithRegex() for real-time sync
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractTasksWithLLM(markdown: string): Promise<ExtractedTask[]>;
|
|
28
|
+
export declare const extractTasksFromPlan: typeof extractTasksWithRegex;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task extraction from plan markdown
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* 1. Fast regex parsing (default) - handles common formats instantly
|
|
6
|
+
* 2. LLM extraction (optional) - for complex plans, user-triggered
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
/**
|
|
10
|
+
* Fast regex-based task extraction
|
|
11
|
+
* Handles common markdown patterns:
|
|
12
|
+
* - [ ] pending task
|
|
13
|
+
* - [x] completed task
|
|
14
|
+
* - [ ] ~in progress~ (strikethrough = in progress)
|
|
15
|
+
* ### 1. Numbered section headers
|
|
16
|
+
* 1. Numbered list items
|
|
17
|
+
*/
|
|
18
|
+
export function extractTasksWithRegex(markdown) {
|
|
19
|
+
const tasks = [];
|
|
20
|
+
const lines = markdown.split('\n');
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
// Checkbox tasks: - [ ] task or - [x] task
|
|
23
|
+
const checkboxMatch = line.match(/^[\s]*[-*]\s*\[([ xX])\]\s*(.+)$/);
|
|
24
|
+
if (checkboxMatch) {
|
|
25
|
+
const isDone = checkboxMatch[1].toLowerCase() === 'x';
|
|
26
|
+
const title = checkboxMatch[2].trim();
|
|
27
|
+
tasks.push({
|
|
28
|
+
title: title.slice(0, 100),
|
|
29
|
+
status: isDone ? 'done' : 'pending',
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Numbered section headers: ### 1. Task name or ## 1. Task name
|
|
34
|
+
const sectionMatch = line.match(/^#{2,4}\s*\d+\.\s*(.+)$/);
|
|
35
|
+
if (sectionMatch) {
|
|
36
|
+
const title = sectionMatch[1].trim();
|
|
37
|
+
// Skip if it looks like a file path or code
|
|
38
|
+
if (!title.includes('/') && !title.includes('`')) {
|
|
39
|
+
tasks.push({
|
|
40
|
+
title: title.slice(0, 100),
|
|
41
|
+
status: 'pending',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Top-level numbered list: 1. Task item (only at start of line)
|
|
47
|
+
const numberedMatch = line.match(/^\d+\.\s+([A-Z][^.]+)$/);
|
|
48
|
+
if (numberedMatch) {
|
|
49
|
+
const title = numberedMatch[1].trim();
|
|
50
|
+
tasks.push({
|
|
51
|
+
title: title.slice(0, 100),
|
|
52
|
+
status: 'pending',
|
|
53
|
+
});
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return tasks;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* LLM-based task extraction (slower, more accurate for complex plans)
|
|
61
|
+
* Use extractTasksWithRegex() for real-time sync
|
|
62
|
+
*/
|
|
63
|
+
export async function extractTasksWithLLM(markdown) {
|
|
64
|
+
const MAX_LENGTH = 4000;
|
|
65
|
+
const truncated = markdown.length > MAX_LENGTH
|
|
66
|
+
? markdown.slice(0, MAX_LENGTH) + '\n\n[... truncated]'
|
|
67
|
+
: markdown;
|
|
68
|
+
const prompt = `I'm building a multi-agent coordination system. Extract implementation tasks from this plan as JSON array:
|
|
69
|
+
[{"title": "Task name", "status": "pending"}]
|
|
70
|
+
|
|
71
|
+
Plan:
|
|
72
|
+
${truncated}`;
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const proc = spawn('claude', ['--print', '--output-format', 'text', prompt], {
|
|
75
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
76
|
+
});
|
|
77
|
+
let stdout = '';
|
|
78
|
+
let stderr = '';
|
|
79
|
+
proc.stdout.on('data', (d) => { stdout += d.toString(); });
|
|
80
|
+
proc.stderr.on('data', (d) => { stderr += d.toString(); });
|
|
81
|
+
proc.on('error', (err) => reject(new Error(`spawn failed: ${err.message}`)));
|
|
82
|
+
proc.on('close', (code) => {
|
|
83
|
+
if (code !== 0) {
|
|
84
|
+
reject(new Error(`claude exited ${code}: ${stderr || stdout}`));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const match = stdout.match(/```(?:json)?\s*([\s\S]*?)```/) || stdout.match(/\[[\s\S]*\]/);
|
|
89
|
+
const jsonStr = match ? (match[1] || match[0]).trim() : null;
|
|
90
|
+
if (!jsonStr) {
|
|
91
|
+
resolve([]);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const tasks = JSON.parse(jsonStr);
|
|
95
|
+
resolve(tasks.map((t) => ({
|
|
96
|
+
title: String(t.title || '').slice(0, 100),
|
|
97
|
+
description: t.description,
|
|
98
|
+
status: ['pending', 'in_progress', 'done'].includes(t.status) ? t.status : 'pending',
|
|
99
|
+
})).filter((t) => t.title));
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
reject(new Error(`JSON parse failed: ${err}`));
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// Default export uses fast regex
|
|
108
|
+
export const extractTasksFromPlan = extractTasksWithRegex;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconcile extracted tasks with database
|
|
3
|
+
* Plan file is source of truth - DB reflects what's in the file
|
|
4
|
+
*/
|
|
5
|
+
import type { Database } from 'bun:sqlite';
|
|
6
|
+
import type { Task } from '../tasks/types';
|
|
7
|
+
import type { ExtractedTask } from './extractTasks';
|
|
8
|
+
export type ReconcileResult = {
|
|
9
|
+
created: Task[];
|
|
10
|
+
updated: Task[];
|
|
11
|
+
removed: Task[];
|
|
12
|
+
unchanged: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Reconcile extracted tasks with existing tasks in a plan
|
|
16
|
+
*
|
|
17
|
+
* - Tasks in file but not DB → create
|
|
18
|
+
* - Tasks in DB but not file → mark done (removed)
|
|
19
|
+
* - Tasks in both → update status if changed
|
|
20
|
+
*/
|
|
21
|
+
export declare function reconcileTasks(db: Database, planId: string, extracted: ExtractedTask[]): ReconcileResult;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconcile extracted tasks with database
|
|
3
|
+
* Plan file is source of truth - DB reflects what's in the file
|
|
4
|
+
*/
|
|
5
|
+
import { createTask } from '../tasks/createTask';
|
|
6
|
+
import { getTasksByPlan } from '../tasks/getTasksByPlan';
|
|
7
|
+
import { completeTask } from '../tasks/completeTask';
|
|
8
|
+
import { startTask } from '../tasks/startTask';
|
|
9
|
+
import { emit } from '../events/emit';
|
|
10
|
+
/**
|
|
11
|
+
* Reconcile extracted tasks with existing tasks in a plan
|
|
12
|
+
*
|
|
13
|
+
* - Tasks in file but not DB → create
|
|
14
|
+
* - Tasks in DB but not file → mark done (removed)
|
|
15
|
+
* - Tasks in both → update status if changed
|
|
16
|
+
*/
|
|
17
|
+
export function reconcileTasks(db, planId, extracted) {
|
|
18
|
+
const existing = getTasksByPlan(db, planId);
|
|
19
|
+
const existingByTitle = new Map(existing.map((t) => [t.title.toLowerCase(), t]));
|
|
20
|
+
const extractedTitles = new Set(extracted.map((t) => t.title.toLowerCase()));
|
|
21
|
+
const created = [];
|
|
22
|
+
const updated = [];
|
|
23
|
+
const removed = [];
|
|
24
|
+
let unchanged = 0;
|
|
25
|
+
// Process extracted tasks
|
|
26
|
+
for (const ext of extracted) {
|
|
27
|
+
const titleKey = ext.title.toLowerCase();
|
|
28
|
+
const existingTask = existingByTitle.get(titleKey);
|
|
29
|
+
if (existingTask) {
|
|
30
|
+
// Task exists - check if status changed
|
|
31
|
+
const dbStatus = existingTask.status;
|
|
32
|
+
const extStatus = ext.status;
|
|
33
|
+
// Map extracted status to DB status
|
|
34
|
+
let needsUpdate = false;
|
|
35
|
+
if (extStatus === 'done' && dbStatus !== 'done') {
|
|
36
|
+
completeTask(db, existingTask.id);
|
|
37
|
+
updated.push({ ...existingTask, status: 'done' });
|
|
38
|
+
needsUpdate = true;
|
|
39
|
+
}
|
|
40
|
+
else if (extStatus === 'in_progress' && dbStatus !== 'in_progress') {
|
|
41
|
+
startTask(db, existingTask.id);
|
|
42
|
+
updated.push({ ...existingTask, status: 'in_progress' });
|
|
43
|
+
needsUpdate = true;
|
|
44
|
+
}
|
|
45
|
+
if (!needsUpdate) {
|
|
46
|
+
unchanged++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// New task - create it
|
|
51
|
+
const task = createTask(db, {
|
|
52
|
+
plan_id: planId,
|
|
53
|
+
title: ext.title,
|
|
54
|
+
description: ext.description,
|
|
55
|
+
});
|
|
56
|
+
// Emit task:create system event
|
|
57
|
+
emit(db, {
|
|
58
|
+
type: 'task:create',
|
|
59
|
+
task_id: task.id,
|
|
60
|
+
plan_id: planId,
|
|
61
|
+
content: `Task created: ${task.title}`,
|
|
62
|
+
});
|
|
63
|
+
// Set initial status if not pending
|
|
64
|
+
if (ext.status === 'in_progress') {
|
|
65
|
+
startTask(db, task.id);
|
|
66
|
+
}
|
|
67
|
+
else if (ext.status === 'done') {
|
|
68
|
+
completeTask(db, task.id);
|
|
69
|
+
}
|
|
70
|
+
created.push(task);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Tasks in DB but not in file → mark as done (removed from plan)
|
|
74
|
+
for (const task of existing) {
|
|
75
|
+
const titleKey = task.title.toLowerCase();
|
|
76
|
+
if (!extractedTitles.has(titleKey) && task.status !== 'done') {
|
|
77
|
+
completeTask(db, task.id);
|
|
78
|
+
removed.push({ ...task, status: 'done' });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { created, updated, removed, unchanged };
|
|
82
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { setupTool, executeSetup, registerTool, executeRegister, emitEventTool, executeEmitEvent, queryTool, executeQuery, statusTool, executeStatus, resetTool, executeReset, claimTaskTool, executeClaimTask, startTaskTool, executeStartTask, completeTaskTool, executeCompleteTask, eventsTool, executeEvents, worktreeCleanupTool, executeWorktreeCleanup, } from './tools/index';
|
|
6
|
+
const server = new Server({
|
|
7
|
+
name: 'hivemind',
|
|
8
|
+
version: '0.1.0',
|
|
9
|
+
}, {
|
|
10
|
+
capabilities: {
|
|
11
|
+
tools: {},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
// List available tools
|
|
15
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
16
|
+
return {
|
|
17
|
+
tools: [
|
|
18
|
+
setupTool,
|
|
19
|
+
registerTool,
|
|
20
|
+
statusTool,
|
|
21
|
+
eventsTool,
|
|
22
|
+
emitEventTool,
|
|
23
|
+
queryTool,
|
|
24
|
+
claimTaskTool,
|
|
25
|
+
startTaskTool,
|
|
26
|
+
completeTaskTool,
|
|
27
|
+
worktreeCleanupTool,
|
|
28
|
+
resetTool,
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
// Handle tool calls
|
|
33
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
34
|
+
const { name, arguments: args } = request.params;
|
|
35
|
+
try {
|
|
36
|
+
let result;
|
|
37
|
+
switch (name) {
|
|
38
|
+
case 'hivemind_setup':
|
|
39
|
+
result = executeSetup(args);
|
|
40
|
+
break;
|
|
41
|
+
case 'hivemind_register':
|
|
42
|
+
result = executeRegister(args);
|
|
43
|
+
break;
|
|
44
|
+
case 'hivemind_emit':
|
|
45
|
+
result = executeEmitEvent(args);
|
|
46
|
+
break;
|
|
47
|
+
case 'hivemind_query':
|
|
48
|
+
result = executeQuery(args);
|
|
49
|
+
break;
|
|
50
|
+
case 'hivemind_status':
|
|
51
|
+
result = executeStatus(args);
|
|
52
|
+
break;
|
|
53
|
+
case 'hivemind_reset':
|
|
54
|
+
result = executeReset(args);
|
|
55
|
+
break;
|
|
56
|
+
case 'hivemind_claim_task':
|
|
57
|
+
result = executeClaimTask(args);
|
|
58
|
+
break;
|
|
59
|
+
case 'hivemind_start_task':
|
|
60
|
+
result = executeStartTask(args);
|
|
61
|
+
break;
|
|
62
|
+
case 'hivemind_complete_task':
|
|
63
|
+
result = executeCompleteTask(args);
|
|
64
|
+
break;
|
|
65
|
+
case 'hivemind_events':
|
|
66
|
+
result = executeEvents(args);
|
|
67
|
+
break;
|
|
68
|
+
case 'hivemind_worktree_cleanup':
|
|
69
|
+
result = executeWorktreeCleanup(args);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
text: JSON.stringify(result, null, 2),
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: JSON.stringify({ error: message }),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
async function main() {
|
|
97
|
+
const transport = new StdioServerTransport();
|
|
98
|
+
await server.connect(transport);
|
|
99
|
+
}
|
|
100
|
+
main().catch(console.error);
|