@task-mcp/cli 1.0.10 → 1.0.11
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/package.json +1 -1
- package/src/ansi.ts +3 -3
- package/src/commands/dashboard.ts +58 -17
package/package.json
CHANGED
package/src/ansi.ts
CHANGED
|
@@ -136,7 +136,7 @@ export function box(content: string, options: {
|
|
|
136
136
|
const { padding = 1, borderColor = "cyan", title, rounded = true } = options;
|
|
137
137
|
|
|
138
138
|
const lines = content.split("\n");
|
|
139
|
-
const maxLen = Math.max(...lines.map(l => stripAnsi(l)
|
|
139
|
+
const maxLen = Math.max(...lines.map(l => displayWidth(stripAnsi(l))), title ? title.length + 2 : 0);
|
|
140
140
|
const innerWidth = maxLen + padding * 2;
|
|
141
141
|
|
|
142
142
|
const tl = rounded ? BOX.rTopLeft : BOX.topLeft;
|
|
@@ -166,8 +166,8 @@ export function box(content: string, options: {
|
|
|
166
166
|
|
|
167
167
|
// Content lines
|
|
168
168
|
const contentLines = lines.map(line => {
|
|
169
|
-
const
|
|
170
|
-
const padRight = innerWidth -
|
|
169
|
+
const lineWidth = displayWidth(stripAnsi(line));
|
|
170
|
+
const padRight = innerWidth - lineWidth - padding;
|
|
171
171
|
return applyBorder(v) + " ".repeat(padding) + line + " ".repeat(Math.max(0, padRight)) + applyBorder(v);
|
|
172
172
|
});
|
|
173
173
|
|
|
@@ -113,55 +113,89 @@ function renderStatusWidget(tasks: Task[], projects: Project[]): string {
|
|
|
113
113
|
|
|
114
114
|
async function renderActionsWidget(tasks: Task[]): Promise<string> {
|
|
115
115
|
const nextTask = suggestNextTask(tasks);
|
|
116
|
-
const pendingItems = await listInboxItems("pending");
|
|
117
116
|
|
|
118
117
|
const lines: string[] = [];
|
|
119
118
|
|
|
120
|
-
// Next tasks (top
|
|
119
|
+
// Next tasks (top 3 suggestions)
|
|
121
120
|
const readyTasks = tasks
|
|
122
121
|
.filter(t => t.status === "pending" && (!t.dependencies || t.dependencies.length === 0))
|
|
123
122
|
.sort((a, b) => {
|
|
124
123
|
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
125
124
|
return (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2);
|
|
126
125
|
})
|
|
127
|
-
.slice(0,
|
|
126
|
+
.slice(0, 4);
|
|
128
127
|
|
|
129
128
|
if (readyTasks.length > 0) {
|
|
130
129
|
for (const task of readyTasks) {
|
|
131
130
|
const deps = task.dependencies?.length ?? 0;
|
|
132
131
|
const depsInfo = deps > 0 ? `${deps} deps` : c.green("ready");
|
|
133
|
-
lines.push(`${c.cyan("→")} ${truncate(task.title,
|
|
132
|
+
lines.push(`${c.cyan("→")} ${truncate(task.title, 24)}`);
|
|
134
133
|
lines.push(` ${formatPriority(task.priority)}, ${depsInfo}`);
|
|
135
134
|
}
|
|
136
135
|
} else if (nextTask) {
|
|
137
136
|
const deps = nextTask.dependencies?.length ?? 0;
|
|
138
137
|
const depsInfo = deps > 0 ? `${deps} deps` : c.green("ready");
|
|
139
|
-
lines.push(`${c.cyan("→")} ${truncate(nextTask.title,
|
|
138
|
+
lines.push(`${c.cyan("→")} ${truncate(nextTask.title, 24)}`);
|
|
140
139
|
lines.push(` ${formatPriority(nextTask.priority)}, ${depsInfo}`);
|
|
141
140
|
} else {
|
|
142
141
|
lines.push(c.dim("No tasks ready"));
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
|
|
144
|
+
return box(lines.join("\n"), {
|
|
145
|
+
title: "Next Actions",
|
|
146
|
+
borderColor: "green",
|
|
147
|
+
padding: 1,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// =============================================================================
|
|
152
|
+
// Widget: Inbox
|
|
153
|
+
// =============================================================================
|
|
154
|
+
|
|
155
|
+
async function renderInboxWidget(): Promise<string | null> {
|
|
156
|
+
const pendingItems = await listInboxItems("pending");
|
|
157
|
+
|
|
158
|
+
if (pendingItems.length === 0) {
|
|
159
|
+
return null; // Don't show if empty
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const lines: string[] = [];
|
|
163
|
+
lines.push(`${c.yellow("Pending")}: ${pendingItems.length} items`);
|
|
146
164
|
lines.push("");
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
165
|
+
|
|
166
|
+
// Show up to 3 items
|
|
167
|
+
for (const item of pendingItems.slice(0, 3)) {
|
|
168
|
+
const date = new Date(item.capturedAt);
|
|
169
|
+
const ago = getTimeAgo(date);
|
|
170
|
+
const tags = item.tags?.length ? c.dim(` #${item.tags[0]}`) : "";
|
|
171
|
+
lines.push(`${c.yellow("○")} ${truncate(item.content, 40)}${tags}`);
|
|
172
|
+
lines.push(` ${c.dim(ago)}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (pendingItems.length > 3) {
|
|
176
|
+
lines.push(c.gray(`+${pendingItems.length - 3} more`));
|
|
156
177
|
}
|
|
157
178
|
|
|
158
179
|
return box(lines.join("\n"), {
|
|
159
|
-
title: "
|
|
160
|
-
borderColor: "
|
|
180
|
+
title: "Inbox",
|
|
181
|
+
borderColor: "yellow",
|
|
161
182
|
padding: 1,
|
|
162
183
|
});
|
|
163
184
|
}
|
|
164
185
|
|
|
186
|
+
function getTimeAgo(date: Date): string {
|
|
187
|
+
const now = new Date();
|
|
188
|
+
const diffMs = now.getTime() - date.getTime();
|
|
189
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
190
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
191
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
192
|
+
|
|
193
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
194
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
195
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
196
|
+
return date.toLocaleDateString();
|
|
197
|
+
}
|
|
198
|
+
|
|
165
199
|
// =============================================================================
|
|
166
200
|
// Projects Table
|
|
167
201
|
// =============================================================================
|
|
@@ -265,6 +299,13 @@ export async function dashboard(projectId?: string): Promise<void> {
|
|
|
265
299
|
console.log(sideBySide([statusWidget, actionsWidget], 2));
|
|
266
300
|
console.log();
|
|
267
301
|
|
|
302
|
+
// Inbox widget (if there are pending items)
|
|
303
|
+
const inboxWidget = await renderInboxWidget();
|
|
304
|
+
if (inboxWidget) {
|
|
305
|
+
console.log(inboxWidget);
|
|
306
|
+
console.log();
|
|
307
|
+
}
|
|
308
|
+
|
|
268
309
|
// Projects table (only if showing all projects)
|
|
269
310
|
if (!project && projects.length > 1) {
|
|
270
311
|
console.log(c.bold("Projects"));
|