@cmgmyr/hive 1.2.1 → 1.3.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.
@@ -201,6 +201,12 @@ const completeTodo = db.transaction((projectId, todoId, completed) => {
201
201
  export function registerTodos(server) {
202
202
  server.registerTool("todo_create", {
203
203
  description: "Create a project-scoped todo. Pass a short slug to have it render beside the id wherever this todo is listed; left unset, those surfaces fall back to the title instead (truncated in the dashboard). Optionally pass blocked_by todo ids to encode ordering. Returns a slim receipt.",
204
+ annotations: {
205
+ readOnlyHint: false,
206
+ destructiveHint: false,
207
+ idempotentHint: false,
208
+ openWorldHint: false,
209
+ },
204
210
  inputSchema: {
205
211
  title: z.string(),
206
212
  body: z.string().optional().describe("Objective, owned files, acceptance criteria."),
@@ -225,6 +231,12 @@ export function registerTodos(server) {
225
231
  }));
226
232
  server.registerTool("todo_list", {
227
233
  description: "List todo summaries. is_blocked=false finds dispatchable work. query matches title, body, and slug. Archived todos are excluded by default; include_archived=true retrieves them too.",
234
+ annotations: {
235
+ readOnlyHint: false,
236
+ destructiveHint: false,
237
+ idempotentHint: true,
238
+ openWorldHint: false,
239
+ },
228
240
  inputSchema: {
229
241
  status: statusParam.optional(),
230
242
  is_blocked: z.boolean().optional(),
@@ -256,6 +268,12 @@ export function registerTodos(server) {
256
268
  }));
257
269
  server.registerTool("todo_get", {
258
270
  description: "Read one todo in full: body, blockers, what it blocks, and optionally comments.",
271
+ annotations: {
272
+ readOnlyHint: false,
273
+ destructiveHint: false,
274
+ idempotentHint: true,
275
+ openWorldHint: false,
276
+ },
259
277
  inputSchema: {
260
278
  todo_id: idParam,
261
279
  include_comments: z.boolean().optional(),
@@ -267,6 +285,12 @@ export function registerTodos(server) {
267
285
  }));
268
286
  server.registerTool("todo_update", {
269
287
  description: "Update todo fields. Omitted fields are preserved. Returns a slim receipt.",
288
+ annotations: {
289
+ readOnlyHint: false,
290
+ destructiveHint: true,
291
+ idempotentHint: false,
292
+ openWorldHint: false,
293
+ },
270
294
  inputSchema: {
271
295
  todo_id: idParam,
272
296
  title: z.string().optional(),
@@ -292,6 +316,12 @@ export function registerTodos(server) {
292
316
  }));
293
317
  server.registerTool("todo_archive", {
294
318
  description: "Archive a todo (or unarchive with archived=false), mirroring pad_archive. Archived todos are excluded from todo_list by default; todo_get always reaches them by id. Refuses when this todo still blocks another todo that is not completed.",
319
+ annotations: {
320
+ readOnlyHint: false,
321
+ destructiveHint: true,
322
+ idempotentHint: false,
323
+ openWorldHint: false,
324
+ },
295
325
  inputSchema: {
296
326
  todo_id: idParam,
297
327
  archived: z.boolean().optional().describe("Default true. Pass false to unarchive."),
@@ -305,6 +335,12 @@ export function registerTodos(server) {
305
335
  }));
306
336
  server.registerTool("todo_complete", {
307
337
  description: "Mark a todo complete (or reopen with completed=false). Returns todo ids that this completion newly unblocked.",
338
+ annotations: {
339
+ readOnlyHint: false,
340
+ destructiveHint: true,
341
+ idempotentHint: false,
342
+ openWorldHint: false,
343
+ },
308
344
  inputSchema: {
309
345
  todo_id: idParam,
310
346
  completed: z.boolean().optional().describe("Defaults to true."),
@@ -323,6 +359,12 @@ export function registerTodos(server) {
323
359
  }));
324
360
  server.registerTool("todo_comment", {
325
361
  description: "Add a comment to a todo. Use for handoffs: changed files, tests run, decisions, remaining risk.",
362
+ annotations: {
363
+ readOnlyHint: false,
364
+ destructiveHint: false,
365
+ idempotentHint: false,
366
+ openWorldHint: false,
367
+ },
326
368
  inputSchema: {
327
369
  todo_id: idParam,
328
370
  body: z.string(),
@@ -340,6 +382,12 @@ export function registerTodos(server) {
340
382
  }));
341
383
  server.registerTool("todo_block", {
342
384
  description: "Add a blocker: todo_id cannot start until blocker_id completes. Cycles are rejected.",
385
+ annotations: {
386
+ readOnlyHint: false,
387
+ destructiveHint: false,
388
+ idempotentHint: false,
389
+ openWorldHint: false,
390
+ },
343
391
  inputSchema: {
344
392
  todo_id: idParam,
345
393
  blocker_id: idParam,
@@ -354,6 +402,12 @@ export function registerTodos(server) {
354
402
  }));
355
403
  server.registerTool("todo_unblock", {
356
404
  description: "Remove one blocker relationship from a todo.",
405
+ annotations: {
406
+ readOnlyHint: false,
407
+ destructiveHint: true,
408
+ idempotentHint: false,
409
+ openWorldHint: false,
410
+ },
357
411
  inputSchema: {
358
412
  todo_id: idParam,
359
413
  blocker_id: idParam,
@@ -179,6 +179,12 @@ export function registerWakes(server) {
179
179
  "instead of polling. Write the body self-contained: ids, context, next action - it may arrive in " +
180
180
  "a session that has none of this conversation. Delivering to your OWN lead pane, where the " +
181
181
  "context is already there, prefer the action, the ids, and a pointer to where the detail lives.",
182
+ annotations: {
183
+ readOnlyHint: false,
184
+ destructiveHint: false,
185
+ idempotentHint: false,
186
+ openWorldHint: false,
187
+ },
182
188
  inputSchema: {
183
189
  delay_seconds: z.number().int().positive(),
184
190
  body: z.string(),
@@ -210,6 +216,12 @@ export function registerWakes(server) {
210
216
  }));
211
217
  server.registerTool("wake_when_idle", {
212
218
  description: "Wake up when watched agents go idle (exact state from Claude Code hooks) or max_wait_seconds passes - except delivery HOLDS past that bound instead, for as long as the target pane is on a dialog or has unsubmitted human text in it, rather than pasting the wake body into either (.claude/rules/tmux-and-panes.md). Two shapes, and you pass EXACTLY ONE of them. agents=[...] is a ONE-SHOT over a named list: mode=any fires on the first fresh idle transition, mode=all fires when every watched agent is idle (returns already_satisfied without scheduling anything if they all are now), and either way it stops watching once it fires. scope=\"project\" is a STANDING WATCH over the crew you spawn in this project, including workers spawned later: it never stops watching, and on each finish it delivers a roster naming who finished and who is still going, until max_wait_seconds runs out or you wake_cancel it. You may hold ONE standing watch per project: a second call is refused and names the one already running, since two would report every finish twice. Use the standing watch when you are running more than one worker - a one-shot leaves every other worker unwatched from the moment it fires. Use either instead of polling. Refuses a lead target: a lead has no idle/working state channel.",
219
+ annotations: {
220
+ readOnlyHint: false,
221
+ destructiveHint: false,
222
+ idempotentHint: false,
223
+ openWorldHint: false,
224
+ },
213
225
  inputSchema: {
214
226
  agents: z
215
227
  .array(agentRefParam)
@@ -322,6 +334,12 @@ export function registerWakes(server) {
322
334
  description: "Read one wake-up by id, in this project, with its UNTRUNCATED body. wake_list truncates " +
323
335
  "body at 120 chars; use this to see exactly what a wake will say, or to confirm what " +
324
336
  "wake_update just changed.",
337
+ annotations: {
338
+ readOnlyHint: false,
339
+ destructiveHint: false,
340
+ idempotentHint: true,
341
+ openWorldHint: false,
342
+ },
325
343
  inputSchema: { wake_id: idParam, project_id: projectIdParam },
326
344
  }, (args) => run(() => {
327
345
  const projectId = effectiveProjectId(args.project_id);
@@ -352,6 +370,12 @@ export function registerWakes(server) {
352
370
  "delay_seconds and repeat_every_seconds only apply to a delay wake (from wake_set) - an idle " +
353
371
  "wake (from wake_when_idle) fires on watched-agent state and max_wait_seconds instead, so " +
354
372
  "only body can be edited on one.",
373
+ annotations: {
374
+ readOnlyHint: false,
375
+ destructiveHint: true,
376
+ idempotentHint: false,
377
+ openWorldHint: false,
378
+ },
355
379
  inputSchema: {
356
380
  wake_id: idParam,
357
381
  delay_seconds: z.number().int().positive().optional(),
@@ -409,6 +433,12 @@ export function registerWakes(server) {
409
433
  "per-worker block notice (a crew member stopped on a dialog): that carries no parent link, so one " +
410
434
  "already filed still delivers, and it may still be true - the worker is probably still on that " +
411
435
  "dialog - but it no longer claims anything about the watch's own liveness, deliberately.",
436
+ annotations: {
437
+ readOnlyHint: false,
438
+ destructiveHint: true,
439
+ idempotentHint: true,
440
+ openWorldHint: false,
441
+ },
412
442
  inputSchema: { wake_id: idParam, project_id: projectIdParam },
413
443
  outputSchema: {
414
444
  wake_id: idParam,
@@ -441,6 +471,12 @@ export function registerWakes(server) {
441
471
  "state (typed_at, held_at/held_reason, confirmation). A one-shot wake leaves the " +
442
472
  "pending list the moment it fires; recently_delivered is where to check whether it " +
443
473
  "was actually typed and, if its target has a confirmation channel, acknowledged.",
474
+ annotations: {
475
+ readOnlyHint: false,
476
+ destructiveHint: false,
477
+ idempotentHint: true,
478
+ openWorldHint: false,
479
+ },
444
480
  inputSchema: { project_id: projectIdParam },
445
481
  }, (args) => run(() => {
446
482
  const projectId = effectiveProjectId(args.project_id);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cmgmyr/hive",
3
- "version": "1.2.1",
4
- "description": "Shared memory and coordination for Claude Code sessions: one lead, many tmux workers, one project-scoped store.",
3
+ "version": "1.3.0",
4
+ "description": "Run a crew of Claude Code and Codex workers from one lead session: visible tmux panes, exact state from hooks, one local SQLite store.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "hive": "dist/cli.js",