claude-code-kanban 1.16.0 → 1.17.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/package.json +1 -1
- package/public/index.html +43 -7
- package/server.js +5 -0
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -2361,7 +2361,7 @@
|
|
|
2361
2361
|
try {
|
|
2362
2362
|
const res = await fetch('/api/tasks/all');
|
|
2363
2363
|
const allTasks = await res.json();
|
|
2364
|
-
let activeTasks = allTasks.filter(t => t.status === 'in_progress');
|
|
2364
|
+
let activeTasks = allTasks.filter(t => t.status === 'in_progress' && !isInternalTask(t));
|
|
2365
2365
|
if (filterProject) {
|
|
2366
2366
|
activeTasks = activeTasks.filter(t => matchesProjectFilter(t.project));
|
|
2367
2367
|
}
|
|
@@ -2457,8 +2457,9 @@
|
|
|
2457
2457
|
sessionView.classList.add('visible');
|
|
2458
2458
|
document.getElementById('owner-filter-bar').classList.remove('visible');
|
|
2459
2459
|
|
|
2460
|
-
const
|
|
2461
|
-
const
|
|
2460
|
+
const visibleTasks = currentTasks.filter(t => !isInternalTask(t));
|
|
2461
|
+
const totalTasks = visibleTasks.length;
|
|
2462
|
+
const completed = visibleTasks.filter(t => t.status === 'completed').length;
|
|
2462
2463
|
const percent = totalTasks > 0 ? Math.round((completed / totalTasks) * 100) : 0;
|
|
2463
2464
|
|
|
2464
2465
|
const isFiltered = filterProject && filterProject !== '__recent__';
|
|
@@ -2674,7 +2675,7 @@
|
|
|
2674
2675
|
}
|
|
2675
2676
|
|
|
2676
2677
|
function renderKanban() {
|
|
2677
|
-
let filtered = currentTasks;
|
|
2678
|
+
let filtered = currentTasks.filter(t => !isInternalTask(t));
|
|
2678
2679
|
if (ownerFilter) {
|
|
2679
2680
|
filtered = filtered.filter(t => t.owner === ownerFilter);
|
|
2680
2681
|
}
|
|
@@ -3429,6 +3430,10 @@
|
|
|
3429
3430
|
debouncedRefresh(data.sessionId, data.type === 'metadata-update');
|
|
3430
3431
|
}
|
|
3431
3432
|
|
|
3433
|
+
if (data.type === 'plan-update') {
|
|
3434
|
+
refreshOpenPlan();
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3432
3437
|
if (data.type === 'team-update') {
|
|
3433
3438
|
console.log('[SSE] Team update:', data.teamName);
|
|
3434
3439
|
debouncedRefresh(data.teamName, false);
|
|
@@ -3470,6 +3475,10 @@
|
|
|
3470
3475
|
{ bg: 'rgba(99, 102, 241, 0.14)', color: '#4f46e5' }, // indigo
|
|
3471
3476
|
];
|
|
3472
3477
|
const ownerColorCache = {};
|
|
3478
|
+
function isInternalTask(task) {
|
|
3479
|
+
return task.metadata && task.metadata._internal === true;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3473
3482
|
function getOwnerColor(name) {
|
|
3474
3483
|
if (ownerColorCache[name]) return ownerColorCache[name];
|
|
3475
3484
|
let hash = 5381;
|
|
@@ -3665,7 +3674,13 @@
|
|
|
3665
3674
|
|
|
3666
3675
|
await Promise.all(promises);
|
|
3667
3676
|
|
|
3668
|
-
|
|
3677
|
+
let tasks = currentSessionId === sessionId ? currentTasks : [];
|
|
3678
|
+
if (tasks.length === 0) {
|
|
3679
|
+
try {
|
|
3680
|
+
const r = await fetch(`/api/sessions/${sessionId}`);
|
|
3681
|
+
if (r.ok) tasks = await r.json();
|
|
3682
|
+
} catch {}
|
|
3683
|
+
}
|
|
3669
3684
|
_planSessionId = sessionId;
|
|
3670
3685
|
showInfoModal(session, teamConfig, tasks, planContent);
|
|
3671
3686
|
}
|
|
@@ -3723,8 +3738,13 @@
|
|
|
3723
3738
|
// Team info section
|
|
3724
3739
|
if (teamConfig) {
|
|
3725
3740
|
const ownerCounts = {};
|
|
3741
|
+
const memberDescriptions = {};
|
|
3726
3742
|
tasks.forEach(t => {
|
|
3727
|
-
if (t
|
|
3743
|
+
if (isInternalTask(t) && t.subject) {
|
|
3744
|
+
memberDescriptions[t.subject] = t.description;
|
|
3745
|
+
} else if (t.owner) {
|
|
3746
|
+
ownerCounts[t.owner] = (ownerCounts[t.owner] || 0) + 1;
|
|
3747
|
+
}
|
|
3728
3748
|
});
|
|
3729
3749
|
|
|
3730
3750
|
const members = teamConfig.members || [];
|
|
@@ -3739,11 +3759,13 @@
|
|
|
3739
3759
|
|
|
3740
3760
|
members.forEach(member => {
|
|
3741
3761
|
const taskCount = ownerCounts[member.name] || 0;
|
|
3762
|
+
const memberDesc = memberDescriptions[member.name];
|
|
3742
3763
|
html += `
|
|
3743
3764
|
<div class="team-member-card">
|
|
3744
3765
|
<div class="member-name">🟢 ${escapeHtml(member.name)}</div>
|
|
3745
3766
|
<div class="member-detail">Role: ${escapeHtml(member.agentType || 'unknown')}</div>
|
|
3746
3767
|
${member.model ? `<div class="member-detail">Model: ${escapeHtml(member.model)}</div>` : ''}
|
|
3768
|
+
${memberDesc ? `<div class="member-detail" style="margin-top: 4px; font-style: italic; color: var(--text-secondary);">${escapeHtml(memberDesc.split('\n')[0])}</div>` : ''}
|
|
3747
3769
|
<div class="member-tasks">Tasks: ${taskCount} assigned</div>
|
|
3748
3770
|
</div>
|
|
3749
3771
|
`;
|
|
@@ -3784,6 +3806,20 @@
|
|
|
3784
3806
|
|
|
3785
3807
|
let _planSessionId = null;
|
|
3786
3808
|
|
|
3809
|
+
function refreshOpenPlan() {
|
|
3810
|
+
if (!_planSessionId || !document.getElementById('plan-modal').classList.contains('visible')) return;
|
|
3811
|
+
fetch(`/api/sessions/${_planSessionId}/plan`)
|
|
3812
|
+
.then(r => r.ok ? r.json() : null)
|
|
3813
|
+
.then(data => {
|
|
3814
|
+
if (data?.content) {
|
|
3815
|
+
_pendingPlanContent = data.content;
|
|
3816
|
+
const body = document.getElementById('plan-modal-body');
|
|
3817
|
+
body.innerHTML = DOMPurify.sanitize(marked.parse(_pendingPlanContent));
|
|
3818
|
+
}
|
|
3819
|
+
})
|
|
3820
|
+
.catch(() => {});
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3787
3823
|
function openPlanForSession(sid) {
|
|
3788
3824
|
fetch(`/api/sessions/${sid}/plan`).then(r => r.ok ? r.json() : null).catch(() => null)
|
|
3789
3825
|
.then(data => {
|
|
@@ -3832,7 +3868,7 @@
|
|
|
3832
3868
|
}
|
|
3833
3869
|
|
|
3834
3870
|
bar.classList.add('visible');
|
|
3835
|
-
const owners = [...new Set(currentTasks.map(t => t.owner).filter(Boolean))].sort();
|
|
3871
|
+
const owners = [...new Set(currentTasks.filter(t => !isInternalTask(t)).map(t => t.owner).filter(Boolean))].sort();
|
|
3836
3872
|
select.innerHTML = '<option value="">All Members</option>' +
|
|
3837
3873
|
owners.map(o => {
|
|
3838
3874
|
const c = getOwnerColor(o);
|
package/server.js
CHANGED
|
@@ -294,6 +294,7 @@ app.get('/api/sessions', async (req, res) => {
|
|
|
294
294
|
try {
|
|
295
295
|
const taskPath = path.join(sessionPath, file);
|
|
296
296
|
const task = JSON.parse(readFileSync(taskPath, 'utf8'));
|
|
297
|
+
if (task.metadata && task.metadata._internal) continue;
|
|
297
298
|
if (task.status === 'completed') completed++;
|
|
298
299
|
else if (task.status === 'in_progress') inProgress++;
|
|
299
300
|
else pending++;
|
|
@@ -706,6 +707,10 @@ plansWatcher.on('all', (event, filePath) => {
|
|
|
706
707
|
if ((event === 'add' || event === 'change' || event === 'unlink') && filePath.endsWith('.md')) {
|
|
707
708
|
lastMetadataRefresh = 0;
|
|
708
709
|
broadcast({ type: 'metadata-update' });
|
|
710
|
+
if (event === 'change') {
|
|
711
|
+
const slug = path.basename(filePath, '.md');
|
|
712
|
+
broadcast({ type: 'plan-update', slug });
|
|
713
|
+
}
|
|
709
714
|
}
|
|
710
715
|
});
|
|
711
716
|
|