agent-tasks 1.7.1 → 1.9.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/README.md +17 -15
- package/dist/domain/agent-bridge.d.ts.map +1 -1
- package/dist/domain/agent-bridge.js +22 -2
- package/dist/domain/agent-bridge.js.map +1 -1
- package/dist/domain/approvals.d.ts.map +1 -1
- package/dist/domain/approvals.js +4 -1
- package/dist/domain/approvals.js.map +1 -1
- package/dist/domain/cleanup.d.ts.map +1 -1
- package/dist/domain/cleanup.js +8 -3
- package/dist/domain/cleanup.js.map +1 -1
- package/dist/domain/rules.js +11 -10
- package/dist/domain/rules.js.map +1 -1
- package/dist/domain/task-validator.d.ts +9 -0
- package/dist/domain/task-validator.d.ts.map +1 -0
- package/dist/domain/task-validator.js +70 -0
- package/dist/domain/task-validator.js.map +1 -0
- package/dist/domain/tasks.d.ts +13 -9
- package/dist/domain/tasks.d.ts.map +1 -1
- package/dist/domain/tasks.js +165 -111
- package/dist/domain/tasks.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/storage/database.js +4 -2
- package/dist/storage/database.js.map +1 -1
- package/dist/transport/mcp-handlers.d.ts +30 -0
- package/dist/transport/mcp-handlers.d.ts.map +1 -0
- package/dist/transport/mcp-handlers.js +408 -0
- package/dist/transport/mcp-handlers.js.map +1 -0
- package/dist/transport/mcp.d.ts.map +1 -1
- package/dist/transport/mcp.js +196 -656
- package/dist/transport/mcp.js.map +1 -1
- package/dist/transport/rest.d.ts.map +1 -1
- package/dist/transport/rest.js +4 -1
- package/dist/transport/rest.js.map +1 -1
- package/dist/transport/ws.d.ts.map +1 -1
- package/dist/transport/ws.js +6 -4
- package/dist/transport/ws.js.map +1 -1
- package/dist/ui/app.js +186 -1608
- package/dist/ui/board.js +401 -0
- package/dist/ui/drag.js +143 -0
- package/dist/ui/index.html +5 -0
- package/dist/ui/inline-edit.js +242 -0
- package/dist/ui/panel.js +574 -0
- package/dist/ui/styles.css +109 -0
- package/dist/ui/ui-utils.js +323 -0
- package/package.json +1 -1
- package/dist/db.d.ts +0 -10
- package/dist/db.d.ts.map +0 -1
- package/dist/db.js +0 -112
- package/dist/db.js.map +0 -1
- package/dist/event-bus.d.ts +0 -10
- package/dist/event-bus.d.ts.map +0 -1
- package/dist/event-bus.js +0 -38
- package/dist/event-bus.js.map +0 -1
- package/dist/session.d.ts +0 -7
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -11
- package/dist/session.js.map +0 -1
- package/dist/tasks.d.ts +0 -32
- package/dist/tasks.d.ts.map +0 -1
- package/dist/tasks.js +0 -410
- package/dist/tasks.js.map +0 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// agent-tasks — Inline Edit Module
|
|
3
|
+
//
|
|
4
|
+
// Inline task creation, inline title editing, priority cycling, assignee
|
|
5
|
+
// dropdown, task update API calls.
|
|
6
|
+
// =============================================================================
|
|
7
|
+
|
|
8
|
+
window.TaskBoard = window.TaskBoard || {};
|
|
9
|
+
|
|
10
|
+
var activeInlineCreate = null;
|
|
11
|
+
var activeDropdown = null;
|
|
12
|
+
|
|
13
|
+
// ---- Inline Task Creation ----
|
|
14
|
+
|
|
15
|
+
function showInlineCreate(stage) {
|
|
16
|
+
dismissInlineCreate();
|
|
17
|
+
|
|
18
|
+
const col = document.querySelector(`.kanban-column[data-stage="${stage}"]`);
|
|
19
|
+
if (!col) return;
|
|
20
|
+
|
|
21
|
+
const addBtn = col.querySelector('.column-add-btn');
|
|
22
|
+
if (addBtn) addBtn.style.display = 'none';
|
|
23
|
+
|
|
24
|
+
const form = document.createElement('div');
|
|
25
|
+
form.className = 'inline-create-form';
|
|
26
|
+
form.innerHTML = `<div class="inline-create-card">
|
|
27
|
+
<input class="inline-create-input" type="text" placeholder="Task title..." autofocus />
|
|
28
|
+
<div class="inline-create-hint">
|
|
29
|
+
<span><kbd>Enter</kbd> to create</span>
|
|
30
|
+
<span><kbd>Esc</kbd> to cancel</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>`;
|
|
33
|
+
|
|
34
|
+
col.appendChild(form);
|
|
35
|
+
activeInlineCreate = { stage, form, col };
|
|
36
|
+
|
|
37
|
+
const input = form.querySelector('.inline-create-input');
|
|
38
|
+
input.focus();
|
|
39
|
+
|
|
40
|
+
input.addEventListener('keydown', (e) => {
|
|
41
|
+
if (e.key === 'Enter' && input.value.trim()) {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
createTaskInline(input.value.trim(), stage);
|
|
44
|
+
dismissInlineCreate();
|
|
45
|
+
} else if (e.key === 'Escape') {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
dismissInlineCreate();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
input.addEventListener('blur', () => {
|
|
52
|
+
setTimeout(() => dismissInlineCreate(), 150);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function dismissInlineCreate() {
|
|
57
|
+
if (!activeInlineCreate) return;
|
|
58
|
+
const { form, col } = activeInlineCreate;
|
|
59
|
+
if (form && form.parentNode) form.remove();
|
|
60
|
+
const addBtn = col.querySelector('.column-add-btn');
|
|
61
|
+
if (addBtn) addBtn.style.display = '';
|
|
62
|
+
activeInlineCreate = null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function createTaskInline(title, stage) {
|
|
66
|
+
var showToast = TaskBoard.showToast;
|
|
67
|
+
fetch('/api/tasks', {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
body: JSON.stringify({ title, stage, created_by: 'dashboard' }),
|
|
71
|
+
})
|
|
72
|
+
.then((r) => r.json())
|
|
73
|
+
.then((result) => {
|
|
74
|
+
if (result.error) {
|
|
75
|
+
showToast('Create failed', result.error, 'error');
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.catch(() => showToast('Create failed', 'Network error', 'error'));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ---- Inline Title Editing ----
|
|
82
|
+
|
|
83
|
+
function startInlineEdit(titleEl) {
|
|
84
|
+
var state = TaskBoard.state;
|
|
85
|
+
const taskId = parseInt(titleEl.dataset.taskId, 10);
|
|
86
|
+
const task = state.tasks.find((t) => t.id === taskId);
|
|
87
|
+
if (!task) return;
|
|
88
|
+
|
|
89
|
+
titleEl.setAttribute('contenteditable', 'true');
|
|
90
|
+
titleEl.focus();
|
|
91
|
+
|
|
92
|
+
const range = document.createRange();
|
|
93
|
+
range.selectNodeContents(titleEl);
|
|
94
|
+
const sel = window.getSelection();
|
|
95
|
+
sel.removeAllRanges();
|
|
96
|
+
sel.addRange(range);
|
|
97
|
+
|
|
98
|
+
const finish = () => {
|
|
99
|
+
titleEl.removeAttribute('contenteditable');
|
|
100
|
+
const newTitle = titleEl.textContent.trim();
|
|
101
|
+
if (newTitle && newTitle !== task.title) {
|
|
102
|
+
updateTask(taskId, { title: newTitle });
|
|
103
|
+
} else {
|
|
104
|
+
titleEl.textContent = task.title;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
titleEl.addEventListener('blur', finish, { once: true });
|
|
109
|
+
titleEl.addEventListener(
|
|
110
|
+
'keydown',
|
|
111
|
+
(e) => {
|
|
112
|
+
if (e.key === 'Enter') {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
titleEl.blur();
|
|
115
|
+
} else if (e.key === 'Escape') {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
titleEl.textContent = task.title;
|
|
118
|
+
titleEl.removeAttribute('contenteditable');
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{ once: true },
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---- Priority Cycling ----
|
|
126
|
+
|
|
127
|
+
function cyclePriority(taskId) {
|
|
128
|
+
var state = TaskBoard.state;
|
|
129
|
+
const task = state.tasks.find((t) => t.id === taskId);
|
|
130
|
+
if (!task) return;
|
|
131
|
+
|
|
132
|
+
const levels = [0, 1, 3, 5, 10];
|
|
133
|
+
const current = levels.indexOf(task.priority);
|
|
134
|
+
const next = levels[(current + 1) % levels.length];
|
|
135
|
+
updateTask(taskId, { priority: next });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---- Assignee Dropdown ----
|
|
139
|
+
|
|
140
|
+
function showAssigneeDropdown(taskId, anchor) {
|
|
141
|
+
dismissDropdown();
|
|
142
|
+
|
|
143
|
+
var state = TaskBoard.state;
|
|
144
|
+
var esc = TaskBoard.esc;
|
|
145
|
+
var renderAvatar = TaskBoard.renderAvatar;
|
|
146
|
+
const task = state.tasks.find((t) => t.id === taskId);
|
|
147
|
+
if (!task) return;
|
|
148
|
+
|
|
149
|
+
const assignees = [...new Set(state.tasks.map((t) => t.assigned_to).filter(Boolean))].sort();
|
|
150
|
+
if (!assignees.length) return;
|
|
151
|
+
|
|
152
|
+
const dropdown = document.createElement('div');
|
|
153
|
+
dropdown.className = 'inline-dropdown';
|
|
154
|
+
|
|
155
|
+
dropdown.innerHTML =
|
|
156
|
+
`<div class="inline-dropdown-item${!task.assigned_to ? ' active' : ''}" data-value="">
|
|
157
|
+
<span style="color:var(--text-dim)">Unassigned</span>
|
|
158
|
+
</div>` +
|
|
159
|
+
assignees
|
|
160
|
+
.map(
|
|
161
|
+
(a) =>
|
|
162
|
+
`<div class="inline-dropdown-item${task.assigned_to === a ? ' active' : ''}" data-value="${esc(a)}">
|
|
163
|
+
${renderAvatar(a, 'avatar-sm')}
|
|
164
|
+
<span>${esc(a)}</span>
|
|
165
|
+
</div>`,
|
|
166
|
+
)
|
|
167
|
+
.join('');
|
|
168
|
+
|
|
169
|
+
const rect = anchor.getBoundingClientRect();
|
|
170
|
+
dropdown.style.position = 'fixed';
|
|
171
|
+
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
172
|
+
dropdown.style.left = `${Math.max(8, rect.left - 100)}px`;
|
|
173
|
+
|
|
174
|
+
document.body.appendChild(dropdown);
|
|
175
|
+
activeDropdown = dropdown;
|
|
176
|
+
|
|
177
|
+
dropdown.addEventListener('click', (e) => {
|
|
178
|
+
const item = e.target.closest('.inline-dropdown-item');
|
|
179
|
+
if (item) {
|
|
180
|
+
const value = item.dataset.value || null;
|
|
181
|
+
updateTask(taskId, { assigned_to: value });
|
|
182
|
+
dismissDropdown();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
document.addEventListener('click', dismissDropdownOnOutsideClick, { once: true });
|
|
188
|
+
}, 0);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function dismissDropdown() {
|
|
192
|
+
if (activeDropdown) {
|
|
193
|
+
activeDropdown.remove();
|
|
194
|
+
activeDropdown = null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function dismissDropdownOnOutsideClick(e) {
|
|
199
|
+
if (activeDropdown && !activeDropdown.contains(e.target)) {
|
|
200
|
+
dismissDropdown();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---- Task update API ----
|
|
205
|
+
|
|
206
|
+
function updateTask(taskId, updates) {
|
|
207
|
+
var showToast = TaskBoard.showToast;
|
|
208
|
+
fetch(`/api/tasks/${taskId}`, {
|
|
209
|
+
method: 'PUT',
|
|
210
|
+
headers: { 'Content-Type': 'application/json' },
|
|
211
|
+
body: JSON.stringify(updates),
|
|
212
|
+
})
|
|
213
|
+
.then((r) => r.json())
|
|
214
|
+
.then((result) => {
|
|
215
|
+
if (result.error) {
|
|
216
|
+
showToast('Update failed', result.error, 'error');
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
.catch(() => showToast('Update failed', 'Network error', 'error'));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ---- Getters for keyboard handler ----
|
|
223
|
+
|
|
224
|
+
function getActiveInlineCreate() {
|
|
225
|
+
return activeInlineCreate;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function getActiveDropdown() {
|
|
229
|
+
return activeDropdown;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---- Register on namespace ----
|
|
233
|
+
|
|
234
|
+
TaskBoard.showInlineCreate = showInlineCreate;
|
|
235
|
+
TaskBoard.dismissInlineCreate = dismissInlineCreate;
|
|
236
|
+
TaskBoard.startInlineEdit = startInlineEdit;
|
|
237
|
+
TaskBoard.cyclePriority = cyclePriority;
|
|
238
|
+
TaskBoard.showAssigneeDropdown = showAssigneeDropdown;
|
|
239
|
+
TaskBoard.dismissDropdown = dismissDropdown;
|
|
240
|
+
TaskBoard.updateTask = updateTask;
|
|
241
|
+
TaskBoard.getActiveInlineCreate = getActiveInlineCreate;
|
|
242
|
+
TaskBoard.getActiveDropdown = getActiveDropdown;
|