@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.
Files changed (287) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/dist/agents/agents.test.d.ts +1 -0
  4. package/dist/agents/agents.test.js +167 -0
  5. package/dist/agents/getActiveAgents.d.ts +6 -0
  6. package/dist/agents/getActiveAgents.js +11 -0
  7. package/dist/agents/getAgent.d.ts +6 -0
  8. package/dist/agents/getAgent.js +7 -0
  9. package/dist/agents/getAgentBySessionId.d.ts +10 -0
  10. package/dist/agents/getAgentBySessionId.js +17 -0
  11. package/dist/agents/index.d.ts +10 -0
  12. package/dist/agents/index.js +12 -0
  13. package/dist/agents/markAgentDead.d.ts +6 -0
  14. package/dist/agents/markAgentDead.js +26 -0
  15. package/dist/agents/markAgentIdle.d.ts +5 -0
  16. package/dist/agents/markAgentIdle.js +12 -0
  17. package/dist/agents/registerAgent.d.ts +6 -0
  18. package/dist/agents/registerAgent.js +29 -0
  19. package/dist/agents/types.d.ts +30 -0
  20. package/dist/agents/types.js +1 -0
  21. package/dist/agents/unregisterAgent.d.ts +5 -0
  22. package/dist/agents/unregisterAgent.js +8 -0
  23. package/dist/agents/updateAgentContext.d.ts +5 -0
  24. package/dist/agents/updateAgentContext.js +12 -0
  25. package/dist/agents/updateAgentTask.d.ts +5 -0
  26. package/dist/agents/updateAgentTask.js +12 -0
  27. package/dist/agents/updateAgentWorktree.d.ts +5 -0
  28. package/dist/agents/updateAgentWorktree.js +12 -0
  29. package/dist/cli/index.d.ts +8 -0
  30. package/dist/cli/index.js +8 -0
  31. package/dist/cli/init.d.ts +14 -0
  32. package/dist/cli/init.js +71 -0
  33. package/dist/cli/install.d.ts +8 -0
  34. package/dist/cli/install.js +47 -0
  35. package/dist/cli/join.d.ts +9 -0
  36. package/dist/cli/join.js +38 -0
  37. package/dist/cli/registerMcp.d.ts +28 -0
  38. package/dist/cli/registerMcp.js +138 -0
  39. package/dist/cli/status.d.ts +8 -0
  40. package/dist/cli/status.js +82 -0
  41. package/dist/cli/watch.d.ts +6 -0
  42. package/dist/cli/watch.js +68 -0
  43. package/dist/cli.d.ts +12 -0
  44. package/dist/cli.js +49 -0
  45. package/dist/coordinator/coordinator.test.d.ts +1 -0
  46. package/dist/coordinator/coordinator.test.js +171 -0
  47. package/dist/coordinator/index.d.ts +16 -0
  48. package/dist/coordinator/index.js +166 -0
  49. package/dist/coordinator/spawn.d.ts +22 -0
  50. package/dist/coordinator/spawn.js +66 -0
  51. package/dist/datetime/datetime.test.d.ts +1 -0
  52. package/dist/datetime/datetime.test.js +63 -0
  53. package/dist/datetime/formatDate.d.ts +6 -0
  54. package/dist/datetime/formatDate.js +11 -0
  55. package/dist/datetime/formatDatetime.d.ts +6 -0
  56. package/dist/datetime/formatDatetime.js +12 -0
  57. package/dist/datetime/formatTime.d.ts +6 -0
  58. package/dist/datetime/formatTime.js +11 -0
  59. package/dist/datetime/index.d.ts +4 -0
  60. package/dist/datetime/index.js +7 -0
  61. package/dist/datetime/isStale.d.ts +10 -0
  62. package/dist/datetime/isStale.js +18 -0
  63. package/dist/datetime/now.d.ts +6 -0
  64. package/dist/datetime/now.js +9 -0
  65. package/dist/datetime/parseDatetime.d.ts +7 -0
  66. package/dist/datetime/parseDatetime.js +28 -0
  67. package/dist/db/constants.d.ts +4 -0
  68. package/dist/db/constants.js +6 -0
  69. package/dist/db/db.test.d.ts +1 -0
  70. package/dist/db/db.test.js +141 -0
  71. package/dist/db/ensureProjectDirs.d.ts +4 -0
  72. package/dist/db/ensureProjectDirs.js +12 -0
  73. package/dist/db/getConnection.d.ts +19 -0
  74. package/dist/db/getConnection.js +51 -0
  75. package/dist/db/getCurrentProject.d.ts +8 -0
  76. package/dist/db/getCurrentProject.js +14 -0
  77. package/dist/db/getProjectPaths.d.ts +21 -0
  78. package/dist/db/getProjectPaths.js +26 -0
  79. package/dist/db/index.d.ts +10 -0
  80. package/dist/db/index.js +13 -0
  81. package/dist/db/initializeDb.d.ts +7 -0
  82. package/dist/db/initializeDb.js +23 -0
  83. package/dist/db/nextEventSeq.d.ts +5 -0
  84. package/dist/db/nextEventSeq.js +13 -0
  85. package/dist/db/nextSubtaskSeq.d.ts +5 -0
  86. package/dist/db/nextSubtaskSeq.js +12 -0
  87. package/dist/db/nextTaskSeq.d.ts +5 -0
  88. package/dist/db/nextTaskSeq.js +13 -0
  89. package/dist/db/resetDb.d.ts +10 -0
  90. package/dist/db/resetDb.js +36 -0
  91. package/dist/events/emit.d.ts +6 -0
  92. package/dist/events/emit.js +31 -0
  93. package/dist/events/events.test.d.ts +1 -0
  94. package/dist/events/events.test.js +145 -0
  95. package/dist/events/getEventsByAgent.d.ts +6 -0
  96. package/dist/events/getEventsByAgent.js +14 -0
  97. package/dist/events/getEventsByBranch.d.ts +6 -0
  98. package/dist/events/getEventsByBranch.js +12 -0
  99. package/dist/events/getEventsByPlan.d.ts +6 -0
  100. package/dist/events/getEventsByPlan.js +14 -0
  101. package/dist/events/getEventsByWorktree.d.ts +6 -0
  102. package/dist/events/getEventsByWorktree.js +12 -0
  103. package/dist/events/getEventsSince.d.ts +12 -0
  104. package/dist/events/getEventsSince.js +47 -0
  105. package/dist/events/getRecentEvents.d.ts +6 -0
  106. package/dist/events/getRecentEvents.js +12 -0
  107. package/dist/events/index.d.ts +8 -0
  108. package/dist/events/index.js +9 -0
  109. package/dist/events/types.d.ts +34 -0
  110. package/dist/events/types.js +1 -0
  111. package/dist/git/getBranch.d.ts +4 -0
  112. package/dist/git/getBranch.js +14 -0
  113. package/dist/git/getCurrentWorktree.d.ts +5 -0
  114. package/dist/git/getCurrentWorktree.js +15 -0
  115. package/dist/git/getGitInfo.d.ts +10 -0
  116. package/dist/git/getGitInfo.js +23 -0
  117. package/dist/git/getRepoName.d.ts +4 -0
  118. package/dist/git/getRepoName.js +32 -0
  119. package/dist/git/getRepoRoot.d.ts +4 -0
  120. package/dist/git/getRepoRoot.js +14 -0
  121. package/dist/git/getWorktrees.d.ts +10 -0
  122. package/dist/git/getWorktrees.js +39 -0
  123. package/dist/git/index.d.ts +9 -0
  124. package/dist/git/index.js +7 -0
  125. package/dist/git/isGitRepo.d.ts +4 -0
  126. package/dist/git/isGitRepo.js +13 -0
  127. package/dist/hooks/index.d.ts +1 -0
  128. package/dist/hooks/index.js +1 -0
  129. package/dist/hooks/sessionStart.d.ts +21 -0
  130. package/dist/hooks/sessionStart.js +93 -0
  131. package/dist/ids/generateHex.d.ts +4 -0
  132. package/dist/ids/generateHex.js +7 -0
  133. package/dist/ids/getParentTaskId.d.ts +7 -0
  134. package/dist/ids/getParentTaskId.js +15 -0
  135. package/dist/ids/getPlanHexFromTaskId.d.ts +6 -0
  136. package/dist/ids/getPlanHexFromTaskId.js +9 -0
  137. package/dist/ids/ids.test.d.ts +1 -0
  138. package/dist/ids/ids.test.js +215 -0
  139. package/dist/ids/index.d.ts +16 -0
  140. package/dist/ids/index.js +17 -0
  141. package/dist/ids/isSubtask.d.ts +7 -0
  142. package/dist/ids/isSubtask.js +11 -0
  143. package/dist/ids/isValidId.d.ts +9 -0
  144. package/dist/ids/isValidId.js +22 -0
  145. package/dist/ids/makeAgentId.d.ts +8 -0
  146. package/dist/ids/makeAgentId.js +15 -0
  147. package/dist/ids/makeEventId.d.ts +11 -0
  148. package/dist/ids/makeEventId.js +12 -0
  149. package/dist/ids/makePlanId.d.ts +11 -0
  150. package/dist/ids/makePlanId.js +15 -0
  151. package/dist/ids/makeSubtaskId.d.ts +8 -0
  152. package/dist/ids/makeSubtaskId.js +15 -0
  153. package/dist/ids/makeTaskId.d.ts +8 -0
  154. package/dist/ids/makeTaskId.js +14 -0
  155. package/dist/ids/makeWorktreeId.d.ts +5 -0
  156. package/dist/ids/makeWorktreeId.js +12 -0
  157. package/dist/ids/parseId.d.ts +11 -0
  158. package/dist/ids/parseId.js +26 -0
  159. package/dist/ids/sanitizeLabel.d.ts +7 -0
  160. package/dist/ids/sanitizeLabel.js +12 -0
  161. package/dist/ids/typedIds.d.ts +34 -0
  162. package/dist/ids/typedIds.js +22 -0
  163. package/dist/ids/types.d.ts +14 -0
  164. package/dist/ids/types.js +1 -0
  165. package/dist/init/claudeConfig.d.ts +39 -0
  166. package/dist/init/claudeConfig.js +161 -0
  167. package/dist/llm/extractTasks.d.ts +28 -0
  168. package/dist/llm/extractTasks.js +108 -0
  169. package/dist/llm/index.d.ts +2 -0
  170. package/dist/llm/index.js +2 -0
  171. package/dist/llm/reconcileTasks.d.ts +21 -0
  172. package/dist/llm/reconcileTasks.js +82 -0
  173. package/dist/mcp/server.d.ts +2 -0
  174. package/dist/mcp/server.js +100 -0
  175. package/dist/mcp/tools/emitEvent.d.ts +62 -0
  176. package/dist/mcp/tools/emitEvent.js +84 -0
  177. package/dist/mcp/tools/events.d.ts +55 -0
  178. package/dist/mcp/tools/events.js +56 -0
  179. package/dist/mcp/tools/index.d.ts +18 -0
  180. package/dist/mcp/tools/index.js +13 -0
  181. package/dist/mcp/tools/query.d.ts +54 -0
  182. package/dist/mcp/tools/query.js +70 -0
  183. package/dist/mcp/tools/register.d.ts +47 -0
  184. package/dist/mcp/tools/register.js +79 -0
  185. package/dist/mcp/tools/reset.d.ts +38 -0
  186. package/dist/mcp/tools/reset.js +56 -0
  187. package/dist/mcp/tools/setup.d.ts +42 -0
  188. package/dist/mcp/tools/setup.js +75 -0
  189. package/dist/mcp/tools/status.d.ts +44 -0
  190. package/dist/mcp/tools/status.js +74 -0
  191. package/dist/mcp/tools/tasks.d.ts +116 -0
  192. package/dist/mcp/tools/tasks.js +143 -0
  193. package/dist/mcp/tools/worktreeCleanup.d.ts +38 -0
  194. package/dist/mcp/tools/worktreeCleanup.js +67 -0
  195. package/dist/plans/createPlan.d.ts +6 -0
  196. package/dist/plans/createPlan.js +29 -0
  197. package/dist/plans/getActivePlans.d.ts +6 -0
  198. package/dist/plans/getActivePlans.js +11 -0
  199. package/dist/plans/getPlan.d.ts +6 -0
  200. package/dist/plans/getPlan.js +7 -0
  201. package/dist/plans/index.d.ts +5 -0
  202. package/dist/plans/index.js +5 -0
  203. package/dist/plans/plans.test.d.ts +1 -0
  204. package/dist/plans/plans.test.js +107 -0
  205. package/dist/plans/types.d.ts +32 -0
  206. package/dist/plans/types.js +1 -0
  207. package/dist/plans/updatePlanStatus.d.ts +6 -0
  208. package/dist/plans/updatePlanStatus.js +8 -0
  209. package/dist/tasks/assignTask.d.ts +7 -0
  210. package/dist/tasks/assignTask.js +20 -0
  211. package/dist/tasks/blockTask.d.ts +5 -0
  212. package/dist/tasks/blockTask.js +12 -0
  213. package/dist/tasks/claimTask.d.ts +7 -0
  214. package/dist/tasks/claimTask.js +21 -0
  215. package/dist/tasks/completeTask.d.ts +6 -0
  216. package/dist/tasks/completeTask.js +18 -0
  217. package/dist/tasks/createTask.d.ts +6 -0
  218. package/dist/tasks/createTask.js +36 -0
  219. package/dist/tasks/getPendingTasks.d.ts +6 -0
  220. package/dist/tasks/getPendingTasks.js +19 -0
  221. package/dist/tasks/getTask.d.ts +6 -0
  222. package/dist/tasks/getTask.js +7 -0
  223. package/dist/tasks/getTasksByPlan.d.ts +6 -0
  224. package/dist/tasks/getTasksByPlan.js +11 -0
  225. package/dist/tasks/index.d.ts +11 -0
  226. package/dist/tasks/index.js +12 -0
  227. package/dist/tasks/startTask.d.ts +5 -0
  228. package/dist/tasks/startTask.js +12 -0
  229. package/dist/tasks/tasks.test.d.ts +1 -0
  230. package/dist/tasks/tasks.test.js +209 -0
  231. package/dist/tasks/types.d.ts +36 -0
  232. package/dist/tasks/types.js +1 -0
  233. package/dist/tasks/unclaimTask.d.ts +5 -0
  234. package/dist/tasks/unclaimTask.js +12 -0
  235. package/dist/test/factories/agentFactory.d.ts +13 -0
  236. package/dist/test/factories/agentFactory.js +5 -0
  237. package/dist/test/factories/eventFactory.d.ts +20 -0
  238. package/dist/test/factories/eventFactory.js +16 -0
  239. package/dist/test/factories/factories.test.d.ts +1 -0
  240. package/dist/test/factories/factories.test.js +101 -0
  241. package/dist/test/factories/index.d.ts +4 -0
  242. package/dist/test/factories/index.js +4 -0
  243. package/dist/test/factories/planFactory.d.ts +15 -0
  244. package/dist/test/factories/planFactory.js +14 -0
  245. package/dist/test/factories/taskFactory.d.ts +22 -0
  246. package/dist/test/factories/taskFactory.js +44 -0
  247. package/dist/test/multiAgentDemo.d.ts +16 -0
  248. package/dist/test/multiAgentDemo.js +20 -0
  249. package/dist/test/multiAgentDemo.test.d.ts +1 -0
  250. package/dist/test/multiAgentDemo.test.js +14 -0
  251. package/dist/test/setup.d.ts +9 -0
  252. package/dist/test/setup.js +50 -0
  253. package/dist/utils/index.d.ts +5 -0
  254. package/dist/utils/index.js +5 -0
  255. package/dist/utils/math.d.ts +6 -0
  256. package/dist/utils/math.js +10 -0
  257. package/dist/utils/math.test.d.ts +1 -0
  258. package/dist/utils/math.test.js +26 -0
  259. package/dist/utils/string.d.ts +11 -0
  260. package/dist/utils/string.js +17 -0
  261. package/dist/utils/string.test.d.ts +1 -0
  262. package/dist/utils/string.test.js +30 -0
  263. package/dist/watcher/index.d.ts +1 -0
  264. package/dist/watcher/index.js +1 -0
  265. package/dist/watcher/planWatcher.d.ts +31 -0
  266. package/dist/watcher/planWatcher.js +171 -0
  267. package/dist/worktrees/getAllWorktrees.d.ts +6 -0
  268. package/dist/worktrees/getAllWorktrees.js +10 -0
  269. package/dist/worktrees/getWorktreeById.d.ts +6 -0
  270. package/dist/worktrees/getWorktreeById.js +7 -0
  271. package/dist/worktrees/getWorktreeByPath.d.ts +6 -0
  272. package/dist/worktrees/getWorktreeByPath.js +7 -0
  273. package/dist/worktrees/index.d.ts +9 -0
  274. package/dist/worktrees/index.js +13 -0
  275. package/dist/worktrees/registerWorktree.d.ts +6 -0
  276. package/dist/worktrees/registerWorktree.js +28 -0
  277. package/dist/worktrees/removeWorktree.d.ts +6 -0
  278. package/dist/worktrees/removeWorktree.js +9 -0
  279. package/dist/worktrees/syncWorktreesFromGit.d.ts +7 -0
  280. package/dist/worktrees/syncWorktreesFromGit.js +51 -0
  281. package/dist/worktrees/types.d.ts +29 -0
  282. package/dist/worktrees/types.js +1 -0
  283. package/dist/worktrees/updateWorktreeCommit.d.ts +5 -0
  284. package/dist/worktrees/updateWorktreeCommit.js +13 -0
  285. package/dist/worktrees/updateWorktreeSeen.d.ts +5 -0
  286. package/dist/worktrees/updateWorktreeSeen.js +13 -0
  287. package/package.json +58 -0
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Task status values
3
+ */
4
+ export type TaskStatus = 'pending' | 'claimed' | 'in_progress' | 'blocked' | 'done';
5
+ /**
6
+ * Task record as stored in DB
7
+ */
8
+ export type Task = {
9
+ id: string;
10
+ plan_hex: string;
11
+ seq: string;
12
+ label: string | null;
13
+ plan_id: string;
14
+ title: string;
15
+ description: string | null;
16
+ status: TaskStatus;
17
+ branch: string | null;
18
+ worktree_id: string | null;
19
+ claimed_by: string | null;
20
+ claimed_at: string | null;
21
+ completed_at: string | null;
22
+ outcome: string | null;
23
+ parent_task_id: string | null;
24
+ };
25
+ /**
26
+ * Input for creating a task
27
+ */
28
+ export type CreateTaskInput = {
29
+ plan_id: string;
30
+ title: string;
31
+ description?: string;
32
+ branch?: string;
33
+ worktree_id?: string;
34
+ parent_task_id?: string;
35
+ label?: string;
36
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ /**
3
+ * Unclaim a task (release it back to pending)
4
+ */
5
+ export declare function unclaimTask(db: Database, taskId: string): boolean;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Unclaim a task (release it back to pending)
3
+ */
4
+ export function unclaimTask(db, taskId) {
5
+ const stmt = db.prepare(`
6
+ UPDATE tasks
7
+ SET status = 'pending', claimed_by = NULL, claimed_at = NULL
8
+ WHERE id = ? AND status IN ('claimed', 'in_progress', 'blocked')
9
+ `);
10
+ const result = stmt.run(taskId);
11
+ return result.changes > 0;
12
+ }
@@ -0,0 +1,13 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import type { Agent } from '../../agents/types';
3
+ export type AgentOverrides = {
4
+ label?: string;
5
+ context_summary?: string;
6
+ pid?: number;
7
+ session_id?: string;
8
+ worktree_id?: string;
9
+ };
10
+ export type BuildAgentResult = {
11
+ agent: Agent;
12
+ };
13
+ export declare function buildAgent(db: Database, overrides?: AgentOverrides): BuildAgentResult;
@@ -0,0 +1,5 @@
1
+ import { registerAgent } from '../../agents/registerAgent';
2
+ export function buildAgent(db, overrides = {}) {
3
+ const agent = registerAgent(db, overrides);
4
+ return { agent };
5
+ }
@@ -0,0 +1,20 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import type { Event, EventType } from '../../events/types';
3
+ import type { Agent } from '../../agents/types';
4
+ import type { Plan } from '../../plans/types';
5
+ import type { Task } from '../../tasks/types';
6
+ export type EventOverrides = {
7
+ type?: EventType;
8
+ content?: string;
9
+ agent?: Agent;
10
+ plan?: Plan;
11
+ task?: Task;
12
+ branch?: string;
13
+ worktree_id?: string;
14
+ metadata?: Record<string, unknown>;
15
+ };
16
+ export type BuildEventResult = {
17
+ event: Event;
18
+ agent: Agent;
19
+ };
20
+ export declare function buildEvent(db: Database, overrides?: EventOverrides): BuildEventResult;
@@ -0,0 +1,16 @@
1
+ import { emit } from '../../events/emit';
2
+ import { buildAgent } from './agentFactory';
3
+ export function buildEvent(db, overrides = {}) {
4
+ const agent = overrides.agent ?? buildAgent(db).agent;
5
+ const event = emit(db, {
6
+ agent_id: agent.id,
7
+ type: overrides.type ?? 'note',
8
+ content: overrides.content ?? 'Test event',
9
+ plan_id: overrides.plan?.id,
10
+ task_id: overrides.task?.id,
11
+ worktree_id: overrides.worktree_id,
12
+ branch: overrides.branch,
13
+ metadata: overrides.metadata,
14
+ });
15
+ return { event, agent };
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect, beforeEach, afterEach, afterAll } from 'bun:test';
2
+ import { createTestDb, cleanupAllTestDbs } from '../setup';
3
+ import { buildAgent } from './agentFactory';
4
+ import { buildPlan } from './planFactory';
5
+ import { buildTask } from './taskFactory';
6
+ import { buildEvent } from './eventFactory';
7
+ describe('Test Factories', () => {
8
+ let testDb;
9
+ beforeEach(() => {
10
+ testDb = createTestDb();
11
+ });
12
+ afterEach(() => {
13
+ testDb.cleanup();
14
+ });
15
+ afterAll(() => {
16
+ cleanupAllTestDbs();
17
+ });
18
+ describe('buildAgent', () => {
19
+ it('creates agent with defaults', () => {
20
+ const { agent } = buildAgent(testDb.db);
21
+ expect(agent.id).toMatch(/^agt_[a-f0-9]{6}$/);
22
+ expect(agent.status).toBe('active');
23
+ });
24
+ it('creates agent with label', () => {
25
+ const { agent } = buildAgent(testDb.db, { label: 'worker' });
26
+ expect(agent.id).toMatch(/^agt_[a-f0-9]{6}_worker$/);
27
+ expect(agent.label).toBe('worker');
28
+ });
29
+ });
30
+ describe('buildPlan', () => {
31
+ it('creates plan and agent', () => {
32
+ const { plan, agent } = buildPlan(testDb.db);
33
+ expect(plan.id).toMatch(/^pln_[a-f0-9]{6}$/);
34
+ expect(plan.title).toBe('Test Plan');
35
+ expect(plan.created_by).toBe(agent.id);
36
+ });
37
+ it('uses existing agent', () => {
38
+ const { agent: existingAgent } = buildAgent(testDb.db, { label: 'lead' });
39
+ const { plan, agent } = buildPlan(testDb.db, { agent: existingAgent });
40
+ expect(plan.created_by).toBe(existingAgent.id);
41
+ expect(agent.id).toBe(existingAgent.id);
42
+ });
43
+ it('accepts custom title', () => {
44
+ const { plan } = buildPlan(testDb.db, { title: 'Auth Feature' });
45
+ expect(plan.title).toBe('Auth Feature');
46
+ });
47
+ });
48
+ describe('buildTask', () => {
49
+ it('creates task with plan and agent', () => {
50
+ const { task, plan, agent } = buildTask(testDb.db);
51
+ expect(task.id).toMatch(/^tsk_[a-f0-9]{6}_001$/);
52
+ expect(task.plan_id).toBe(plan.id);
53
+ expect(task.status).toBe('pending');
54
+ expect(plan.created_by).toBe(agent.id);
55
+ });
56
+ it('uses existing plan', () => {
57
+ const { plan: existingPlan, agent: existingAgent } = buildPlan(testDb.db, { title: 'My Plan' });
58
+ const { task, plan, agent } = buildTask(testDb.db, { plan: existingPlan });
59
+ expect(task.plan_id).toBe(existingPlan.id);
60
+ expect(plan.id).toBe(existingPlan.id);
61
+ expect(agent.id).toBe(existingAgent.id);
62
+ });
63
+ it('creates claimed task', () => {
64
+ const { agent: claimer } = buildAgent(testDb.db, { label: 'claimer' });
65
+ const { task } = buildTask(testDb.db, {
66
+ status: 'claimed',
67
+ claimed_by: claimer,
68
+ });
69
+ expect(task.status).toBe('claimed');
70
+ expect(task.claimed_by).toBe(claimer.id);
71
+ });
72
+ });
73
+ describe('buildEvent', () => {
74
+ it('creates event with agent', () => {
75
+ const { event, agent } = buildEvent(testDb.db);
76
+ expect(event.id).toMatch(/^evt_[a-f0-9]{6}_\d+$/);
77
+ expect(event.agent_id).toBe(agent.id);
78
+ expect(event.event_type).toBe('note');
79
+ expect(event.content).toBe('Test event');
80
+ });
81
+ it('uses existing agent', () => {
82
+ const { agent: existingAgent } = buildAgent(testDb.db, { label: 'emitter' });
83
+ const { event, agent } = buildEvent(testDb.db, { agent: existingAgent });
84
+ expect(event.agent_id).toBe(existingAgent.id);
85
+ expect(agent.id).toBe(existingAgent.id);
86
+ });
87
+ it('creates event with plan and task', () => {
88
+ const { task, plan, agent } = buildTask(testDb.db);
89
+ const { event } = buildEvent(testDb.db, {
90
+ agent,
91
+ plan,
92
+ task,
93
+ type: 'task:start',
94
+ content: 'Starting work',
95
+ });
96
+ expect(event.plan_id).toBe(plan.id);
97
+ expect(event.task_id).toBe(task.id);
98
+ expect(event.event_type).toBe('task:start');
99
+ });
100
+ });
101
+ });
@@ -0,0 +1,4 @@
1
+ export { buildAgent, type AgentOverrides, type BuildAgentResult } from './agentFactory';
2
+ export { buildPlan, type PlanOverrides, type BuildPlanResult } from './planFactory';
3
+ export { buildTask, type TaskOverrides, type BuildTaskResult } from './taskFactory';
4
+ export { buildEvent, type EventOverrides, type BuildEventResult } from './eventFactory';
@@ -0,0 +1,4 @@
1
+ export { buildAgent } from './agentFactory';
2
+ export { buildPlan } from './planFactory';
3
+ export { buildTask } from './taskFactory';
4
+ export { buildEvent } from './eventFactory';
@@ -0,0 +1,15 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import type { Plan } from '../../plans/types';
3
+ import type { Agent } from '../../agents/types';
4
+ export type PlanOverrides = {
5
+ title?: string;
6
+ label?: string;
7
+ description?: string;
8
+ branch?: string;
9
+ agent?: Agent;
10
+ };
11
+ export type BuildPlanResult = {
12
+ plan: Plan;
13
+ agent: Agent;
14
+ };
15
+ export declare function buildPlan(db: Database, overrides?: PlanOverrides): BuildPlanResult;
@@ -0,0 +1,14 @@
1
+ import { createPlan } from '../../plans/createPlan';
2
+ import { buildAgent } from './agentFactory';
3
+ export function buildPlan(db, overrides = {}) {
4
+ const { agent: existingAgent, ...planOverrides } = overrides;
5
+ const agent = existingAgent ?? buildAgent(db).agent;
6
+ const plan = createPlan(db, {
7
+ title: planOverrides.title ?? 'Test Plan',
8
+ label: planOverrides.label,
9
+ description: planOverrides.description,
10
+ branch: planOverrides.branch,
11
+ created_by: agent.id,
12
+ });
13
+ return { plan, agent };
14
+ }
@@ -0,0 +1,22 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import type { Task, TaskStatus } from '../../tasks/types';
3
+ import type { Plan } from '../../plans/types';
4
+ import type { Agent } from '../../agents/types';
5
+ export type TaskOverrides = {
6
+ title?: string;
7
+ description?: string;
8
+ status?: TaskStatus;
9
+ claimed_by?: Agent;
10
+ plan?: Plan;
11
+ agent?: Agent;
12
+ branch?: string;
13
+ worktree_id?: string;
14
+ parent_task_id?: string;
15
+ label?: string;
16
+ };
17
+ export type BuildTaskResult = {
18
+ task: Task;
19
+ plan: Plan;
20
+ agent: Agent;
21
+ };
22
+ export declare function buildTask(db: Database, overrides?: TaskOverrides): BuildTaskResult;
@@ -0,0 +1,44 @@
1
+ import { createTask } from '../../tasks/createTask';
2
+ import { buildPlan } from './planFactory';
3
+ export function buildTask(db, overrides = {}) {
4
+ let plan;
5
+ let agent;
6
+ if (overrides.plan) {
7
+ plan = overrides.plan;
8
+ const agentRow = db.prepare(`SELECT * FROM agents WHERE id = ?`).get(plan.created_by);
9
+ agent = overrides.agent ?? agentRow ?? buildPlan(db).agent;
10
+ }
11
+ else {
12
+ const result = buildPlan(db, { agent: overrides.agent });
13
+ plan = result.plan;
14
+ agent = result.agent;
15
+ }
16
+ const task = createTask(db, {
17
+ plan_id: plan.id,
18
+ title: overrides.title ?? 'Test Task',
19
+ description: overrides.description,
20
+ branch: overrides.branch,
21
+ worktree_id: overrides.worktree_id,
22
+ parent_task_id: overrides.parent_task_id,
23
+ label: overrides.label,
24
+ });
25
+ // Handle status and claimed_by if provided
26
+ if (overrides.status || overrides.claimed_by) {
27
+ const updates = [];
28
+ const values = [];
29
+ if (overrides.status) {
30
+ updates.push('status = ?');
31
+ values.push(overrides.status);
32
+ }
33
+ if (overrides.claimed_by) {
34
+ updates.push('claimed_by = ?', 'claimed_at = ?');
35
+ values.push(overrides.claimed_by.id, new Date().toISOString());
36
+ }
37
+ if (updates.length > 0) {
38
+ values.push(task.id);
39
+ db.prepare(`UPDATE tasks SET ${updates.join(', ')} WHERE id = ?`).run(...values);
40
+ }
41
+ }
42
+ const finalTask = db.prepare(`SELECT * FROM tasks WHERE id = ?`).get(task.id);
43
+ return { task: finalTask, plan, agent };
44
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Multi-agent coordination demo
3
+ *
4
+ * Task 001 (agt_c88d5b): greeting function
5
+ * Task 002 (agt_4564e7): farewell function
6
+ */
7
+ /**
8
+ * Returns a greeting message from Agent 1
9
+ * @returns A friendly hello message
10
+ */
11
+ export declare function greeting(): string;
12
+ /**
13
+ * Returns a farewell message from Agent 2
14
+ * @returns A friendly goodbye message
15
+ */
16
+ export declare function farewell(): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Multi-agent coordination demo
3
+ *
4
+ * Task 001 (agt_c88d5b): greeting function
5
+ * Task 002 (agt_4564e7): farewell function
6
+ */
7
+ /**
8
+ * Returns a greeting message from Agent 1
9
+ * @returns A friendly hello message
10
+ */
11
+ export function greeting() {
12
+ return "Hello from Agent 1";
13
+ }
14
+ /**
15
+ * Returns a farewell message from Agent 2
16
+ * @returns A friendly goodbye message
17
+ */
18
+ export function farewell() {
19
+ return "Goodbye from Agent 2";
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { describe, it, expect } from 'bun:test';
2
+ import { greeting, farewell } from './multiAgentDemo';
3
+ describe('Multi-Agent Demo', () => {
4
+ it('greeting returns correct message', () => {
5
+ expect(greeting()).toBe('Hello from Agent 1');
6
+ });
7
+ it('farewell returns correct message', () => {
8
+ expect(farewell()).toBe('Goodbye from Agent 2');
9
+ });
10
+ it('both functions work together', () => {
11
+ const conversation = `${greeting()} ... ${farewell()}`;
12
+ expect(conversation).toBe('Hello from Agent 1 ... Goodbye from Agent 2');
13
+ });
14
+ });
@@ -0,0 +1,9 @@
1
+ import { Database } from 'bun:sqlite';
2
+ export type TestDb = {
3
+ db: Database;
4
+ path: string;
5
+ cleanup: () => void;
6
+ clearAllTables: () => void;
7
+ };
8
+ export declare function createTestDb(): TestDb;
9
+ export declare function cleanupAllTestDbs(): void;
@@ -0,0 +1,50 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { readFileSync } from 'fs';
3
+ import { join, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { mkdirSync, rmSync, existsSync } from 'fs';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const TEST_DB_DIR = join(__dirname, '../../.test-db');
8
+ let testDbCounter = 0;
9
+ export function createTestDb() {
10
+ testDbCounter++;
11
+ const dbPath = join(TEST_DB_DIR, `test-${Date.now()}-${testDbCounter}.sqlite`);
12
+ if (!existsSync(TEST_DB_DIR)) {
13
+ mkdirSync(TEST_DB_DIR, { recursive: true });
14
+ }
15
+ const db = new Database(dbPath);
16
+ db.exec('PRAGMA journal_mode = WAL');
17
+ db.exec('PRAGMA busy_timeout = 5000');
18
+ db.exec('PRAGMA foreign_keys = ON');
19
+ const schemaPath = join(__dirname, '../db/schema.sql');
20
+ const schema = readFileSync(schemaPath, 'utf-8');
21
+ db.exec(schema);
22
+ const clearAllTables = () => {
23
+ // Order matters due to FK constraints - delete children first
24
+ db.exec('DELETE FROM events');
25
+ db.exec('DELETE FROM tasks');
26
+ db.exec('DELETE FROM plans');
27
+ db.exec('DELETE FROM agents');
28
+ db.exec('DELETE FROM worktrees');
29
+ // Reset sequence counter
30
+ db.exec("UPDATE sequences SET value = 0 WHERE name = 'events'");
31
+ };
32
+ const cleanup = () => {
33
+ db.close();
34
+ if (existsSync(dbPath)) {
35
+ rmSync(dbPath, { force: true });
36
+ }
37
+ if (existsSync(`${dbPath}-wal`)) {
38
+ rmSync(`${dbPath}-wal`, { force: true });
39
+ }
40
+ if (existsSync(`${dbPath}-shm`)) {
41
+ rmSync(`${dbPath}-shm`, { force: true });
42
+ }
43
+ };
44
+ return { db, path: dbPath, cleanup, clearAllTables };
45
+ }
46
+ export function cleanupAllTestDbs() {
47
+ if (existsSync(TEST_DB_DIR)) {
48
+ rmSync(TEST_DB_DIR, { recursive: true, force: true });
49
+ }
50
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Utility exports - multi-agent coordination test
3
+ */
4
+ export { add, subtract } from "./math";
5
+ export { capitalize, reverse } from "./string";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Utility exports - multi-agent coordination test
3
+ */
4
+ export { add, subtract } from "./math";
5
+ export { capitalize, reverse } from "./string";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Math utilities for hivemind multi-agent test
3
+ * Created by Agent 1 (agt_b6aca9)
4
+ */
5
+ export declare function add(a: number, b: number): number;
6
+ export declare function subtract(a: number, b: number): number;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Math utilities for hivemind multi-agent test
3
+ * Created by Agent 1 (agt_b6aca9)
4
+ */
5
+ export function add(a, b) {
6
+ return a + b;
7
+ }
8
+ export function subtract(a, b) {
9
+ return a - b;
10
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { add, subtract } from "./math";
3
+ describe("math utilities", () => {
4
+ describe("add", () => {
5
+ test("adds two positive numbers", () => {
6
+ expect(add(2, 3)).toBe(5);
7
+ });
8
+ test("adds negative numbers", () => {
9
+ expect(add(-1, -2)).toBe(-3);
10
+ });
11
+ test("adds zero", () => {
12
+ expect(add(5, 0)).toBe(5);
13
+ });
14
+ });
15
+ describe("subtract", () => {
16
+ test("subtracts two positive numbers", () => {
17
+ expect(subtract(5, 3)).toBe(2);
18
+ });
19
+ test("subtracts resulting in negative", () => {
20
+ expect(subtract(3, 5)).toBe(-2);
21
+ });
22
+ test("subtracts zero", () => {
23
+ expect(subtract(5, 0)).toBe(5);
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * String utility functions
3
+ */
4
+ /**
5
+ * Capitalizes the first letter of a string
6
+ */
7
+ export declare function capitalize(str: string): string;
8
+ /**
9
+ * Reverses a string
10
+ */
11
+ export declare function reverse(str: string): string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * String utility functions
3
+ */
4
+ /**
5
+ * Capitalizes the first letter of a string
6
+ */
7
+ export function capitalize(str) {
8
+ if (!str)
9
+ return str;
10
+ return str.charAt(0).toUpperCase() + str.slice(1);
11
+ }
12
+ /**
13
+ * Reverses a string
14
+ */
15
+ export function reverse(str) {
16
+ return str.split("").reverse().join("");
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { capitalize, reverse } from "./string";
3
+ describe("capitalize", () => {
4
+ test("capitalizes first letter", () => {
5
+ expect(capitalize("hello")).toBe("Hello");
6
+ });
7
+ test("handles already capitalized", () => {
8
+ expect(capitalize("Hello")).toBe("Hello");
9
+ });
10
+ test("handles empty string", () => {
11
+ expect(capitalize("")).toBe("");
12
+ });
13
+ test("handles single character", () => {
14
+ expect(capitalize("a")).toBe("A");
15
+ });
16
+ });
17
+ describe("reverse", () => {
18
+ test("reverses a string", () => {
19
+ expect(reverse("hello")).toBe("olleh");
20
+ });
21
+ test("handles empty string", () => {
22
+ expect(reverse("")).toBe("");
23
+ });
24
+ test("handles palindrome", () => {
25
+ expect(reverse("radar")).toBe("radar");
26
+ });
27
+ test("handles single character", () => {
28
+ expect(reverse("x")).toBe("x");
29
+ });
30
+ });
@@ -0,0 +1 @@
1
+ export { startPlanWatcher, syncPlanFile, initialPlanSync } from './planWatcher';
@@ -0,0 +1 @@
1
+ export { startPlanWatcher, syncPlanFile, initialPlanSync } from './planWatcher';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Plan Watcher - watches ~/.claude/plans/ for plan mode files
3
+ *
4
+ * When Claude enters plan mode, it creates markdown files like:
5
+ * ~/.claude/plans/purrfect-watching-lamport.md
6
+ *
7
+ * This watcher detects new/changed plans and syncs them to hivemind.
8
+ * Uses LLM (Claude CLI) to extract tasks from markdown.
9
+ */
10
+ /**
11
+ * Sync a single plan file to hivemind
12
+ * Uses LLM to extract tasks, then reconciles with DB
13
+ */
14
+ export declare function syncPlanFile(project: string, filename: string): Promise<{
15
+ success: boolean;
16
+ planId?: string;
17
+ message: string;
18
+ }>;
19
+ /**
20
+ * Initial sync - scan existing plan files
21
+ */
22
+ export declare function initialPlanSync(project: string): Promise<void>;
23
+ /**
24
+ * Start watching the plans directory
25
+ */
26
+ export declare function startPlanWatcher(options: {
27
+ project: string;
28
+ verbose?: boolean;
29
+ }): {
30
+ stop: () => void;
31
+ };