clawdo 1.0.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/dist/errors.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * ClawdoError - Error class with stable error codes for agent error handling.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * throw new ClawdoError(
7
+ * 'TASK_NOT_FOUND',
8
+ * `Task not found: ${id}`,
9
+ * { id, suggestions: findSimilarIds(id) }
10
+ * );
11
+ * ```
12
+ *
13
+ * @example Agent error handling
14
+ * ```typescript
15
+ * try {
16
+ * db.completeTask(id, 'agent');
17
+ * } catch (err) {
18
+ * if (err.code === 'TASK_BLOCKED') {
19
+ * // Handle blocked task
20
+ * } else if (err.code === 'TASK_NOT_CONFIRMED') {
21
+ * // Prompt human to confirm
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ export class ClawdoError extends Error {
27
+ code;
28
+ context;
29
+ constructor(code, message, context) {
30
+ super(message);
31
+ this.code = code;
32
+ this.context = context;
33
+ this.name = 'ClawdoError';
34
+ // Ensure proper prototype chain for instanceof checks
35
+ Object.setPrototypeOf(this, ClawdoError.prototype);
36
+ }
37
+ /**
38
+ * Returns a JSON representation of the error for --json output.
39
+ */
40
+ toJSON() {
41
+ return {
42
+ error: true,
43
+ code: this.code,
44
+ message: this.message,
45
+ context: this.context
46
+ };
47
+ }
48
+ }
package/dist/inbox.js ADDED
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Agent-facing inbox - structured JSON with security wrapper
3
+ */
4
+ import { wrapForLLM } from './sanitize.js';
5
+ export function generateInbox(db) {
6
+ const autoExecutionEnabled = db.getConfig('auto_execution_enabled') === 'true';
7
+ const tasksCompleted4h = db.countCompletedInLast(4);
8
+ // OPTIMIZATION: Single query + JS partitioning (fast for <5k tasks)
9
+ // For >10k tasks, push filtering to SQL with separate queries per category
10
+ // Trade-off: 1 query + N iterations (current) vs N queries + 0 iterations
11
+ const allActiveTasks = db.listTasks({ status: ['todo', 'in_progress', 'proposed'] });
12
+ const now = new Date().toISOString().split('T')[0];
13
+ const staleThreshold = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
14
+ // Partition tasks in a single pass
15
+ const result = {
16
+ meta: {
17
+ autoExecutionEnabled,
18
+ tasksCompleted4h,
19
+ },
20
+ autoReady: [],
21
+ autoNotifyReady: [],
22
+ urgent: [],
23
+ overdue: [],
24
+ proposed: [],
25
+ stale: [],
26
+ blocked: [],
27
+ };
28
+ for (const task of allActiveTasks) {
29
+ // Categorize by status
30
+ if (task.status === 'proposed') {
31
+ result.proposed.push(task);
32
+ }
33
+ // Urgent tasks (any status except archived/done)
34
+ if (task.urgency === 'now' && (task.status === 'todo' || task.status === 'in_progress')) {
35
+ result.urgent.push(task);
36
+ }
37
+ // Overdue tasks
38
+ if (task.dueDate && task.dueDate < now && (task.status === 'todo' || task.status === 'in_progress')) {
39
+ result.overdue.push(task);
40
+ }
41
+ // Blocked tasks
42
+ if (task.blockedBy && (task.status === 'todo' || task.status === 'in_progress')) {
43
+ result.blocked.push(task);
44
+ }
45
+ // Stale tasks (in_progress > 24h)
46
+ if (task.status === 'in_progress' && task.startedAt && task.startedAt < staleThreshold) {
47
+ result.stale.push(task);
48
+ }
49
+ // Auto-ready tasks (todo status, not blocked)
50
+ if (task.status === 'todo' && !task.blockedBy) {
51
+ if (task.autonomy === 'auto') {
52
+ result.autoReady.push(task);
53
+ }
54
+ else if (task.autonomy === 'auto-notify') {
55
+ result.autoNotifyReady.push(task);
56
+ }
57
+ }
58
+ }
59
+ return result;
60
+ }
61
+ export function formatInboxJSON(inbox) {
62
+ const json = JSON.stringify(inbox, null, 2);
63
+ return wrapForLLM(json);
64
+ }
65
+ export function formatInboxMarkdown(inbox) {
66
+ const lines = [];
67
+ lines.push('# Todo Inbox\n');
68
+ lines.push('## Meta');
69
+ lines.push(`- Auto execution: ${inbox.meta.autoExecutionEnabled ? 'enabled' : 'disabled'}`);
70
+ lines.push(`- Tasks completed (4h): ${inbox.meta.tasksCompleted4h}\n`);
71
+ if (inbox.urgent.length > 0) {
72
+ lines.push(`## Urgent (${inbox.urgent.length})`);
73
+ for (const task of inbox.urgent) {
74
+ lines.push(`- [${task.id}] ${task.text} (${task.autonomy})`);
75
+ }
76
+ lines.push('');
77
+ }
78
+ if (inbox.overdue.length > 0) {
79
+ lines.push(`## Overdue (${inbox.overdue.length})`);
80
+ for (const task of inbox.overdue) {
81
+ lines.push(`- [${task.id}] ${task.text} - due ${task.dueDate}`);
82
+ }
83
+ lines.push('');
84
+ }
85
+ if (inbox.autoReady.length > 0) {
86
+ lines.push(`## Auto Ready (${inbox.autoReady.length})`);
87
+ for (const task of inbox.autoReady) {
88
+ lines.push(`- [${task.id}] ${task.text}`);
89
+ }
90
+ lines.push('');
91
+ }
92
+ if (inbox.autoNotifyReady.length > 0) {
93
+ lines.push(`## Auto-Notify Ready (${inbox.autoNotifyReady.length})`);
94
+ for (const task of inbox.autoNotifyReady) {
95
+ lines.push(`- [${task.id}] ${task.text}`);
96
+ }
97
+ lines.push('');
98
+ }
99
+ if (inbox.proposed.length > 0) {
100
+ lines.push(`## Proposed (${inbox.proposed.length})`);
101
+ for (const task of inbox.proposed) {
102
+ lines.push(`- [${task.id}] ${task.text} (${task.urgency})`);
103
+ }
104
+ lines.push('');
105
+ }
106
+ if (inbox.stale.length > 0) {
107
+ lines.push(`## Stale (in progress >24h) (${inbox.stale.length})`);
108
+ for (const task of inbox.stale) {
109
+ const startedAgo = task.startedAt ? `started ${task.startedAt}` : '';
110
+ lines.push(`- [${task.id}] ${task.text} ${startedAgo}`);
111
+ }
112
+ lines.push('');
113
+ }
114
+ if (inbox.blocked.length > 0) {
115
+ lines.push(`## Blocked (${inbox.blocked.length})`);
116
+ for (const task of inbox.blocked) {
117
+ lines.push(`- [${task.id}] ${task.text} - blocked by ${task.blockedBy}`);
118
+ }
119
+ lines.push('');
120
+ }
121
+ return lines.join('\n');
122
+ }