@compilr-dev/agents 0.3.8 → 0.3.9

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.
@@ -22,7 +22,7 @@ export type { GlobInput } from './glob.js';
22
22
  export { editTool, createEditTool } from './edit.js';
23
23
  export type { EditInput } from './edit.js';
24
24
  export { todoWriteTool, todoReadTool, createTodoTools, TodoStore, resetDefaultTodoStore, getDefaultTodoStore, createIsolatedTodoStore, cleanupTodoContextMessages, getTodoContextStats, } from './todo.js';
25
- export type { TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, } from './todo.js';
25
+ export type { TodoWriteInput, TodoReadInput, TodoClaimInput, TodoHandoffInput, TodoItem, TodoStatus, TodoContextCleanupOptions, } from './todo.js';
26
26
  export { createTaskTool, defaultAgentTypes } from './task.js';
27
27
  export type { TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, } from './task.js';
28
28
  export { webFetchTool, createWebFetchTool } from './web-fetch.js';
@@ -33,6 +33,11 @@ export interface TodoItem {
33
33
  * Optional priority (higher = more important)
34
34
  */
35
35
  priority?: number;
36
+ /**
37
+ * Owner agent ID (e.g., 'pm', 'arch', 'dev')
38
+ * If undefined/null, the task is unassigned
39
+ */
40
+ owner?: string;
36
41
  /**
37
42
  * Creation timestamp
38
43
  */
@@ -54,6 +59,7 @@ export interface TodoWriteInput {
54
59
  status: TodoStatus;
55
60
  activeForm?: string;
56
61
  priority?: number;
62
+ owner?: string;
57
63
  }>;
58
64
  }
59
65
  /**
@@ -68,6 +74,13 @@ export interface TodoReadInput {
68
74
  * Include completed tasks (default: true)
69
75
  */
70
76
  includeCompleted?: boolean;
77
+ /**
78
+ * Filter by owner (optional)
79
+ * - Specific agent ID: Return only tasks owned by that agent
80
+ * - 'unassigned': Return only tasks without an owner
81
+ * - undefined: Return all tasks (no filter)
82
+ */
83
+ owner?: string;
71
84
  }
72
85
  /**
73
86
  * TodoStore manages the in-memory task list
@@ -83,6 +96,11 @@ export declare class TodoStore {
83
96
  * Get todos filtered by status
84
97
  */
85
98
  getByStatus(status: TodoStatus): TodoItem[];
99
+ /**
100
+ * Get todos filtered by owner
101
+ * @param owner - Agent ID, or 'unassigned' for tasks without owner
102
+ */
103
+ getByOwner(owner: string): TodoItem[];
86
104
  /**
87
105
  * Replace all todos with a new list
88
106
  */
@@ -91,6 +109,7 @@ export declare class TodoStore {
91
109
  status: TodoStatus;
92
110
  activeForm?: string;
93
111
  priority?: number;
112
+ owner?: string;
94
113
  }>): void;
95
114
  /**
96
115
  * Add a single todo
@@ -100,6 +119,7 @@ export declare class TodoStore {
100
119
  status: TodoStatus;
101
120
  activeForm?: string;
102
121
  priority?: number;
122
+ owner?: string;
103
123
  }): TodoItem;
104
124
  /**
105
125
  * Update a todo by ID
@@ -117,6 +137,12 @@ export declare class TodoStore {
117
137
  * Get count by status
118
138
  */
119
139
  getCounts(): Record<TodoStatus, number>;
140
+ /**
141
+ * Get counts by owner
142
+ * Returns a map of owner ID to count
143
+ * 'unassigned' key contains count of todos without owner
144
+ */
145
+ getCountsByOwner(): Record<string, number>;
120
146
  }
121
147
  /**
122
148
  * TodoWrite tool - Update the task list
@@ -126,12 +152,44 @@ export declare const todoWriteTool: Tool<TodoWriteInput>;
126
152
  * TodoRead tool - Get the current task list
127
153
  */
128
154
  export declare const todoReadTool: Tool<TodoReadInput>;
155
+ /**
156
+ * Input for TodoClaim tool
157
+ */
158
+ export interface TodoClaimInput {
159
+ /**
160
+ * The todo ID to claim
161
+ */
162
+ todoId: string;
163
+ /**
164
+ * The agent ID claiming the todo
165
+ */
166
+ agentId: string;
167
+ }
168
+ /**
169
+ * Input for TodoHandoff tool
170
+ */
171
+ export interface TodoHandoffInput {
172
+ /**
173
+ * The todo ID to hand off
174
+ */
175
+ todoId: string;
176
+ /**
177
+ * The agent ID to hand off to
178
+ */
179
+ toAgentId: string;
180
+ /**
181
+ * Optional notes about the handoff
182
+ */
183
+ notes?: string;
184
+ }
129
185
  /**
130
186
  * Factory to create todo tools with a custom store
131
187
  */
132
188
  export declare function createTodoTools(store?: TodoStore): {
133
189
  todoWrite: Tool<TodoWriteInput>;
134
190
  todoRead: Tool<TodoReadInput>;
191
+ todoClaim: Tool<TodoClaimInput>;
192
+ todoHandoff: Tool<TodoHandoffInput>;
135
193
  store: TodoStore;
136
194
  };
137
195
  /**
@@ -39,6 +39,16 @@ export class TodoStore {
39
39
  getByStatus(status) {
40
40
  return this.getAll().filter((t) => t.status === status);
41
41
  }
42
+ /**
43
+ * Get todos filtered by owner
44
+ * @param owner - Agent ID, or 'unassigned' for tasks without owner
45
+ */
46
+ getByOwner(owner) {
47
+ if (owner === 'unassigned') {
48
+ return this.getAll().filter((t) => !t.owner);
49
+ }
50
+ return this.getAll().filter((t) => t.owner === owner);
51
+ }
42
52
  /**
43
53
  * Replace all todos with a new list
44
54
  */
@@ -53,6 +63,7 @@ export class TodoStore {
53
63
  status: todo.status,
54
64
  activeForm: todo.activeForm,
55
65
  priority: todo.priority,
66
+ owner: todo.owner,
56
67
  createdAt: now,
57
68
  updatedAt: now,
58
69
  });
@@ -70,6 +81,7 @@ export class TodoStore {
70
81
  status: todo.status,
71
82
  activeForm: todo.activeForm,
72
83
  priority: todo.priority,
84
+ owner: todo.owner,
73
85
  createdAt: now,
74
86
  updatedAt: now,
75
87
  };
@@ -117,6 +129,23 @@ export class TodoStore {
117
129
  }
118
130
  return counts;
119
131
  }
132
+ /**
133
+ * Get counts by owner
134
+ * Returns a map of owner ID to count
135
+ * 'unassigned' key contains count of todos without owner
136
+ */
137
+ getCountsByOwner() {
138
+ const counts = { unassigned: 0 };
139
+ for (const todo of this.todos.values()) {
140
+ if (todo.owner) {
141
+ counts[todo.owner] = (counts[todo.owner] ?? 0) + 1;
142
+ }
143
+ else {
144
+ counts['unassigned']++;
145
+ }
146
+ }
147
+ return counts;
148
+ }
120
149
  }
121
150
  /**
122
151
  * Global default store (can be overridden with factory functions)
@@ -127,8 +156,9 @@ const defaultStore = new TodoStore();
127
156
  */
128
157
  export const todoWriteTool = defineTool({
129
158
  name: 'todo_write',
130
- description: 'Update the task list. Provide the complete list of todos. ' +
131
- 'Use this to track progress on multi-step tasks.',
159
+ description: 'Update the SESSION todo list (shown in CLI footer). These are ephemeral tasks for the current session only - ' +
160
+ 'NOT persistent backlog items. For persistent project backlog, use workitem_* tools. ' +
161
+ 'Provide the complete list to replace current todos.',
132
162
  inputSchema: {
133
163
  type: 'object',
134
164
  properties: {
@@ -155,6 +185,10 @@ export const todoWriteTool = defineTool({
155
185
  type: 'number',
156
186
  description: 'Priority (higher = more important)',
157
187
  },
188
+ owner: {
189
+ type: 'string',
190
+ description: 'Owner agent ID (e.g., "dev", "pm", "arch"). Omit for unassigned tasks.',
191
+ },
158
192
  },
159
193
  required: ['content', 'status'],
160
194
  },
@@ -186,7 +220,8 @@ export const todoWriteTool = defineTool({
186
220
  */
187
221
  export const todoReadTool = defineTool({
188
222
  name: 'todo_read',
189
- description: 'Get the current task list. Optionally filter by status.',
223
+ description: 'Get the SESSION todo list (shown in CLI footer). These are ephemeral session tasks - ' +
224
+ 'for persistent project backlog, use workitem_query. Optionally filter by status or owner.',
190
225
  inputSchema: {
191
226
  type: 'object',
192
227
  properties: {
@@ -199,6 +234,10 @@ export const todoReadTool = defineTool({
199
234
  type: 'boolean',
200
235
  description: 'Include completed tasks (default: true)',
201
236
  },
237
+ owner: {
238
+ type: 'string',
239
+ description: 'Filter by owner agent ID, or "unassigned" for tasks without owner (optional)',
240
+ },
202
241
  },
203
242
  },
204
243
  execute: (input) => {
@@ -211,6 +250,15 @@ export const todoReadTool = defineTool({
211
250
  if (input.includeCompleted === false) {
212
251
  todos = todos.filter((t) => t.status !== 'completed');
213
252
  }
253
+ // Filter by owner if specified
254
+ if (input.owner) {
255
+ if (input.owner === 'unassigned') {
256
+ todos = todos.filter((t) => !t.owner);
257
+ }
258
+ else {
259
+ todos = todos.filter((t) => t.owner === input.owner);
260
+ }
261
+ }
214
262
  const counts = defaultStore.getCounts();
215
263
  return Promise.resolve(createSuccessResult({
216
264
  todos: todos.map((t) => ({
@@ -219,6 +267,7 @@ export const todoReadTool = defineTool({
219
267
  status: t.status,
220
268
  activeForm: t.activeForm,
221
269
  priority: t.priority,
270
+ owner: t.owner,
222
271
  })),
223
272
  counts,
224
273
  total: todos.length,
@@ -232,8 +281,8 @@ export function createTodoTools(store) {
232
281
  const todoStore = store ?? new TodoStore();
233
282
  const todoWrite = defineTool({
234
283
  name: 'todo_write',
235
- description: 'Update the task list. Provide the complete list of todos. ' +
236
- 'Use this to track progress on multi-step tasks.',
284
+ description: 'Update the SESSION todo list (shown in CLI footer). These are ephemeral tasks for the current session only - ' +
285
+ 'NOT persistent backlog items. For persistent project backlog, use workitem_* tools.',
237
286
  inputSchema: {
238
287
  type: 'object',
239
288
  properties: {
@@ -247,6 +296,7 @@ export function createTodoTools(store) {
247
296
  status: { type: 'string', enum: ['pending', 'in_progress', 'completed'] },
248
297
  activeForm: { type: 'string' },
249
298
  priority: { type: 'number' },
299
+ owner: { type: 'string' },
250
300
  },
251
301
  required: ['content', 'status'],
252
302
  },
@@ -275,7 +325,8 @@ export function createTodoTools(store) {
275
325
  });
276
326
  const todoRead = defineTool({
277
327
  name: 'todo_read',
278
- description: 'Get the current task list. Optionally filter by status.',
328
+ description: 'Get the SESSION todo list (shown in CLI footer). These are ephemeral session tasks - ' +
329
+ 'for persistent project backlog, use workitem_query.',
279
330
  inputSchema: {
280
331
  type: 'object',
281
332
  properties: {
@@ -286,6 +337,10 @@ export function createTodoTools(store) {
286
337
  includeCompleted: {
287
338
  type: 'boolean',
288
339
  },
340
+ owner: {
341
+ type: 'string',
342
+ description: 'Filter by owner agent ID, or "unassigned" for tasks without owner',
343
+ },
289
344
  },
290
345
  },
291
346
  execute: (input) => {
@@ -296,6 +351,14 @@ export function createTodoTools(store) {
296
351
  if (input.includeCompleted === false) {
297
352
  todos = todos.filter((t) => t.status !== 'completed');
298
353
  }
354
+ if (input.owner) {
355
+ if (input.owner === 'unassigned') {
356
+ todos = todos.filter((t) => !t.owner);
357
+ }
358
+ else {
359
+ todos = todos.filter((t) => t.owner === input.owner);
360
+ }
361
+ }
299
362
  const counts = todoStore.getCounts();
300
363
  return Promise.resolve(createSuccessResult({
301
364
  todos: todos.map((t) => ({
@@ -304,6 +367,7 @@ export function createTodoTools(store) {
304
367
  status: t.status,
305
368
  activeForm: t.activeForm,
306
369
  priority: t.priority,
370
+ owner: t.owner,
307
371
  })),
308
372
  counts,
309
373
  total: todos.length,
@@ -311,7 +375,94 @@ export function createTodoTools(store) {
311
375
  },
312
376
  silent: true,
313
377
  });
314
- return { todoWrite, todoRead, store: todoStore };
378
+ const todoClaim = defineTool({
379
+ name: 'todo_claim',
380
+ description: 'Claim an unassigned SESSION todo (from CLI footer). For persistent backlog items, use workitem_claim.',
381
+ inputSchema: {
382
+ type: 'object',
383
+ properties: {
384
+ todoId: {
385
+ type: 'string',
386
+ description: 'The todo ID to claim',
387
+ },
388
+ agentId: {
389
+ type: 'string',
390
+ description: 'The agent ID claiming the todo',
391
+ },
392
+ },
393
+ required: ['todoId', 'agentId'],
394
+ },
395
+ execute: (input) => {
396
+ const todos = todoStore.getAll();
397
+ const todo = todos.find((t) => t.id === input.todoId);
398
+ if (!todo) {
399
+ return Promise.resolve(createErrorResult(`Todo "${input.todoId}" not found`));
400
+ }
401
+ if (todo.owner) {
402
+ return Promise.resolve(createErrorResult(`Todo "${input.todoId}" is already owned by "${todo.owner}"`));
403
+ }
404
+ const updated = todoStore.update(input.todoId, { owner: input.agentId });
405
+ if (!updated) {
406
+ return Promise.resolve(createErrorResult(`Failed to update todo "${input.todoId}"`));
407
+ }
408
+ return Promise.resolve(createSuccessResult({
409
+ message: `Todo "${input.todoId}" claimed by "${input.agentId}"`,
410
+ todo: {
411
+ id: updated.id,
412
+ content: updated.content,
413
+ status: updated.status,
414
+ owner: updated.owner,
415
+ },
416
+ }));
417
+ },
418
+ });
419
+ const todoHandoff = defineTool({
420
+ name: 'todo_handoff',
421
+ description: 'Hand off a SESSION todo (from CLI footer) to another agent. ' +
422
+ 'For persistent backlog items, use workitem_handoff.',
423
+ inputSchema: {
424
+ type: 'object',
425
+ properties: {
426
+ todoId: {
427
+ type: 'string',
428
+ description: 'The todo ID to hand off',
429
+ },
430
+ toAgentId: {
431
+ type: 'string',
432
+ description: 'The agent ID to hand off to',
433
+ },
434
+ notes: {
435
+ type: 'string',
436
+ description: 'Optional notes about the handoff (context, status, blockers)',
437
+ },
438
+ },
439
+ required: ['todoId', 'toAgentId'],
440
+ },
441
+ execute: (input) => {
442
+ const todos = todoStore.getAll();
443
+ const todo = todos.find((t) => t.id === input.todoId);
444
+ if (!todo) {
445
+ return Promise.resolve(createErrorResult(`Todo "${input.todoId}" not found`));
446
+ }
447
+ const previousOwner = todo.owner;
448
+ const updated = todoStore.update(input.todoId, { owner: input.toAgentId });
449
+ if (!updated) {
450
+ return Promise.resolve(createErrorResult(`Failed to update todo "${input.todoId}"`));
451
+ }
452
+ return Promise.resolve(createSuccessResult({
453
+ message: `Todo "${input.todoId}" handed off from "${previousOwner ?? 'unassigned'}" to "${input.toAgentId}"`,
454
+ todo: {
455
+ id: updated.id,
456
+ content: updated.content,
457
+ status: updated.status,
458
+ owner: updated.owner,
459
+ },
460
+ previousOwner,
461
+ notes: input.notes,
462
+ }));
463
+ },
464
+ });
465
+ return { todoWrite, todoRead, todoClaim, todoHandoff, store: todoStore };
315
466
  }
316
467
  /**
317
468
  * Reset the default store (useful for testing)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/agents",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Lightweight multi-LLM agent library for building CLI AI assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",