@vheins/local-memory-mcp 0.2.1 → 0.3.14
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/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +16 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/dashboard/public/app.js +475 -32
- package/dist/dashboard/public/index.html +137 -7
- package/dist/dashboard/server.js +137 -16
- package/dist/dashboard/server.js.map +1 -1
- package/dist/prompts/registry.d.ts +112 -0
- package/dist/prompts/registry.d.ts.map +1 -1
- package/dist/prompts/registry.js +172 -0
- package/dist/prompts/registry.js.map +1 -1
- package/dist/resources/index.test.js +2 -0
- package/dist/resources/index.test.js.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +3 -0
- package/dist/router.js.map +1 -1
- package/dist/storage/sqlite.d.ts +7 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +105 -13
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/storage/sqlite.test.js +2 -0
- package/dist/storage/sqlite.test.js.map +1 -1
- package/dist/tasks.bulk.test.d.ts +2 -0
- package/dist/tasks.bulk.test.d.ts.map +1 -0
- package/dist/tasks.bulk.test.js +49 -0
- package/dist/tasks.bulk.test.js.map +1 -0
- package/dist/tools/memory.store.d.ts.map +1 -1
- package/dist/tools/memory.store.js +2 -0
- package/dist/tools/memory.store.js.map +1 -1
- package/dist/tools/memory.update.d.ts.map +1 -1
- package/dist/tools/memory.update.js +6 -0
- package/dist/tools/memory.update.js.map +1 -1
- package/dist/tools/schemas.d.ts +183 -1
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/schemas.js +82 -2
- package/dist/tools/schemas.js.map +1 -1
- package/dist/tools/task.bulk-manage.d.ts +9 -0
- package/dist/tools/task.bulk-manage.d.ts.map +1 -0
- package/dist/tools/task.bulk-manage.js +49 -0
- package/dist/tools/task.bulk-manage.js.map +1 -0
- package/dist/tools/task.manage.d.ts.map +1 -1
- package/dist/tools/task.manage.js +15 -2
- package/dist/tools/task.manage.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/logger.test.js +19 -27
- package/dist/utils/logger.test.js.map +1 -1
- package/dist/v2-features.test.js +2 -0
- package/dist/v2-features.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;CAoBxB,CAAC"}
|
package/dist/capabilities.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { fileURLToPath } from "url";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const pkgPath = path.join(__dirname, "../package.json");
|
|
6
|
+
let pkgVersion = "0.1.0";
|
|
7
|
+
try {
|
|
8
|
+
if (fs.existsSync(pkgPath)) {
|
|
9
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
10
|
+
pkgVersion = pkg.version;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
// Fallback to default version if reading fails
|
|
15
|
+
}
|
|
1
16
|
// MCP Server Capabilities
|
|
2
17
|
export const CAPABILITIES = {
|
|
3
18
|
serverInfo: {
|
|
4
19
|
name: "mcp-memory-local",
|
|
5
|
-
version:
|
|
20
|
+
version: pkgVersion
|
|
6
21
|
},
|
|
7
22
|
capabilities: {
|
|
8
23
|
resources: {
|
package/dist/capabilities.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU,EAAE;QACV,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;AACxD,IAAI,UAAU,GAAG,OAAO,CAAC;AAEzB,IAAI,CAAC;IACH,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACzD,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;IAC3B,CAAC;AACH,CAAC;AAAC,OAAO,CAAC,EAAE,CAAC;IACX,+CAA+C;AACjD,CAAC;AAED,0BAA0B;AAC1B,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU,EAAE;QACV,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,UAAU;KACpB;IACD,YAAY,EAAE;QACZ,SAAS,EAAE;YACT,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,IAAI;SAChB;QACD,KAAK,EAAE;YACL,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,IAAI;SACX;QACD,OAAO,EAAE;YACP,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,IAAI;SACV;KACF;CACF,CAAC"}
|
|
@@ -6,6 +6,11 @@ let totalPages = 1;
|
|
|
6
6
|
let totalItems = 0;
|
|
7
7
|
let selectedIds = new Set();
|
|
8
8
|
let currentPaginatedData = [];
|
|
9
|
+
let taskPagination = {
|
|
10
|
+
todo: { page: 1, pageSize: 20, hasMore: true, loading: false },
|
|
11
|
+
in_progress: { page: 1, pageSize: 20, hasMore: true, loading: false },
|
|
12
|
+
completed: { page: 1, pageSize: 20, hasMore: true, loading: false }
|
|
13
|
+
};
|
|
9
14
|
let charts = {};
|
|
10
15
|
let lastSyncTime = Date.now();
|
|
11
16
|
let countdownSeconds = 30;
|
|
@@ -428,6 +433,11 @@ async function setCurrentRepo(repo) {
|
|
|
428
433
|
currentPage = 1;
|
|
429
434
|
recentActionsPage = 1;
|
|
430
435
|
selectedIds.clear();
|
|
436
|
+
|
|
437
|
+
// Clear search input on repo change
|
|
438
|
+
const taskSearch = document.getElementById('taskSearchInput');
|
|
439
|
+
if (taskSearch) taskSearch.value = '';
|
|
440
|
+
|
|
431
441
|
localStorage.setItem('selectedRepo', currentRepo);
|
|
432
442
|
renderRepoSidebar();
|
|
433
443
|
closeRepoSidebarDrawer();
|
|
@@ -435,6 +445,7 @@ async function setCurrentRepo(repo) {
|
|
|
435
445
|
loadStats(),
|
|
436
446
|
loadMemories(),
|
|
437
447
|
loadRecentActions(),
|
|
448
|
+
loadTasks()
|
|
438
449
|
]);
|
|
439
450
|
syncStickyOffsets();
|
|
440
451
|
}
|
|
@@ -600,6 +611,21 @@ async function loadStats() {
|
|
|
600
611
|
document.getElementById('mistakeCount').textContent = data.byType?.mistake || 0;
|
|
601
612
|
document.getElementById('patternCount').textContent = data.byType?.pattern || 0;
|
|
602
613
|
|
|
614
|
+
// Fill Task stats
|
|
615
|
+
if (data.taskStats) {
|
|
616
|
+
document.getElementById('totalTasks').textContent = data.taskStats.total || 0;
|
|
617
|
+
document.getElementById('todoTasksCount').textContent = data.taskStats.todo || 0;
|
|
618
|
+
document.getElementById('inProgressTasksCount').textContent = data.taskStats.inProgress || 0;
|
|
619
|
+
document.getElementById('completedTasksCount').textContent = data.taskStats.completed || 0;
|
|
620
|
+
|
|
621
|
+
document.getElementById('todoStatCount').textContent = data.taskStats.todo || 0;
|
|
622
|
+
document.getElementById('inProgressStatCount').textContent = data.taskStats.inProgress || 0;
|
|
623
|
+
document.getElementById('completedStatCount').textContent = data.taskStats.completed || 0;
|
|
624
|
+
document.getElementById('blockedStatCount').textContent = data.taskStats.blocked || 0;
|
|
625
|
+
|
|
626
|
+
updateTaskStatusChart(data.taskStats);
|
|
627
|
+
}
|
|
628
|
+
|
|
603
629
|
updateTypeChart(data.byType);
|
|
604
630
|
updateTimeSeriesChart(data.timeSeries || {});
|
|
605
631
|
updateScatterChart(data.scatterData || []);
|
|
@@ -655,6 +681,51 @@ function updateTypeChart(byType) {
|
|
|
655
681
|
});
|
|
656
682
|
}
|
|
657
683
|
|
|
684
|
+
function updateTaskStatusChart(taskStats) {
|
|
685
|
+
const ctx = document.getElementById('taskStatusChart');
|
|
686
|
+
if (!window.Chart || !ctx) return;
|
|
687
|
+
if (charts.taskStatusChart) charts.taskStatusChart.destroy();
|
|
688
|
+
|
|
689
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
690
|
+
const counts = [
|
|
691
|
+
taskStats?.todo || 0,
|
|
692
|
+
taskStats?.inProgress || 0,
|
|
693
|
+
taskStats?.completed || 0,
|
|
694
|
+
taskStats?.blocked || 0
|
|
695
|
+
];
|
|
696
|
+
|
|
697
|
+
charts.taskStatusChart = new Chart(ctx, {
|
|
698
|
+
type: 'doughnut',
|
|
699
|
+
data: {
|
|
700
|
+
labels: ['To Do', 'In Progress', 'Completed', 'Blocked'],
|
|
701
|
+
datasets: [{
|
|
702
|
+
data: counts,
|
|
703
|
+
backgroundColor: ['#94a3b8', '#38bdf8', '#10b981', '#fb7185'],
|
|
704
|
+
borderWidth: 2,
|
|
705
|
+
borderColor: isDark ? '#1e293b' : '#ffffff',
|
|
706
|
+
hoverOffset: 12
|
|
707
|
+
}]
|
|
708
|
+
},
|
|
709
|
+
options: {
|
|
710
|
+
responsive: true,
|
|
711
|
+
maintainAspectRatio: false,
|
|
712
|
+
cutout: '68%',
|
|
713
|
+
plugins: {
|
|
714
|
+
legend: { display: false },
|
|
715
|
+
tooltip: {
|
|
716
|
+
backgroundColor: isDark ? '#1e293b' : '#ffffff',
|
|
717
|
+
titleColor: isDark ? '#f8fafc' : '#1e293b',
|
|
718
|
+
bodyColor: isDark ? '#94a3b8' : '#64748b',
|
|
719
|
+
borderColor: isDark ? '#334155' : '#e2e8f0',
|
|
720
|
+
borderWidth: 1,
|
|
721
|
+
padding: 10,
|
|
722
|
+
cornerRadius: 10
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
|
|
658
729
|
function updateTopMemoriesChart(memories = []) {
|
|
659
730
|
const ctx = document.getElementById('topMemoriesChart');
|
|
660
731
|
if (!window.Chart) {
|
|
@@ -1089,6 +1160,7 @@ function renderTable(memories) {
|
|
|
1089
1160
|
<td class="p-3">
|
|
1090
1161
|
<div class="flex flex-col">
|
|
1091
1162
|
<span class="text-[10px] font-bold text-sky-600 dark:text-sky-400 truncate max-w-[100px]" title="${m.agent || 'unknown'}">${m.agent || 'unknown'}</span>
|
|
1163
|
+
<span class="text-[9px] font-medium text-slate-500 dark:text-slate-400 truncate max-w-[100px]" title="${m.role || 'unknown'}">${m.role || 'unknown'}</span>
|
|
1092
1164
|
<span class="text-[9px] text-gray-400 dark:text-gray-500 truncate max-w-[100px]" title="${m.model || 'unknown'}">${m.model || 'unknown'}</span>
|
|
1093
1165
|
</div>
|
|
1094
1166
|
</td>
|
|
@@ -1589,47 +1661,103 @@ let currentTasks = [];
|
|
|
1589
1661
|
|
|
1590
1662
|
async function loadTasks() {
|
|
1591
1663
|
if (!currentRepo) return;
|
|
1664
|
+
|
|
1665
|
+
// Reset pagination
|
|
1666
|
+
taskPagination.todo = { page: 1, pageSize: 20, hasMore: true, loading: false };
|
|
1667
|
+
taskPagination.in_progress = { page: 1, pageSize: 20, hasMore: true, loading: false };
|
|
1668
|
+
taskPagination.completed = { page: 1, pageSize: 20, hasMore: true, loading: false };
|
|
1669
|
+
|
|
1670
|
+
// Clear containers
|
|
1671
|
+
document.getElementById('todoTasks').innerHTML = '';
|
|
1672
|
+
document.getElementById('inProgressTasks').innerHTML = '';
|
|
1673
|
+
document.getElementById('completedTasks').innerHTML = '';
|
|
1674
|
+
|
|
1675
|
+
await Promise.all([
|
|
1676
|
+
loadTaskCategory('pending,blocked,canceled'),
|
|
1677
|
+
loadTaskCategory('in_progress'),
|
|
1678
|
+
loadTaskCategory('completed')
|
|
1679
|
+
]);
|
|
1680
|
+
|
|
1681
|
+
setupTaskScrollListeners();
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
async function loadTaskCategory(status) {
|
|
1685
|
+
const category = (status.includes('pending') || status.includes('blocked') || status.includes('canceled')) ? 'todo' : (status === 'in_progress' ? 'in_progress' : 'completed');
|
|
1686
|
+
const pag = taskPagination[category];
|
|
1687
|
+
|
|
1688
|
+
if (!pag.hasMore || pag.loading) return;
|
|
1689
|
+
|
|
1690
|
+
pag.loading = true;
|
|
1691
|
+
const containerId = { todo: 'todoTasks', in_progress: 'inProgressTasks', completed: 'completedTasks' }[category];
|
|
1692
|
+
const container = document.getElementById(containerId);
|
|
1693
|
+
|
|
1694
|
+
// Show loading indicator
|
|
1695
|
+
const loadingId = `loading-${category}`;
|
|
1696
|
+
if (!document.getElementById(loadingId)) {
|
|
1697
|
+
const loader = document.createElement('div');
|
|
1698
|
+
loader.id = loadingId;
|
|
1699
|
+
loader.className = 'py-4 text-center text-gray-400 text-[10px] animate-pulse w-full';
|
|
1700
|
+
loader.textContent = 'Loading more...';
|
|
1701
|
+
container.appendChild(loader);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1592
1704
|
try {
|
|
1593
|
-
const
|
|
1705
|
+
const searchInput = document.getElementById('taskSearchInput');
|
|
1706
|
+
const searchTerm = searchInput ? encodeURIComponent(searchInput.value.trim()) : '';
|
|
1707
|
+
const response = await fetch(`/api/tasks?repo=${encodeURIComponent(currentRepo)}&status=${status}&page=${pag.page}&pageSize=${pag.pageSize}&search=${searchTerm}`);
|
|
1594
1708
|
const data = await response.json();
|
|
1595
|
-
|
|
1596
|
-
|
|
1709
|
+
|
|
1710
|
+
const tasks = data.tasks || [];
|
|
1711
|
+
|
|
1712
|
+
// Remove loader
|
|
1713
|
+
const loader = document.getElementById(loadingId);
|
|
1714
|
+
if (loader) loader.remove();
|
|
1715
|
+
|
|
1716
|
+
if (tasks.length < pag.pageSize) {
|
|
1717
|
+
pag.hasMore = false;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
renderTaskCards(containerId, tasks, pag.page === 1);
|
|
1721
|
+
pag.page++;
|
|
1597
1722
|
} catch (err) {
|
|
1598
|
-
console.error(
|
|
1723
|
+
console.error(`Failed to load ${category} tasks:`, err);
|
|
1724
|
+
} finally {
|
|
1725
|
+
pag.loading = false;
|
|
1599
1726
|
}
|
|
1600
1727
|
}
|
|
1601
1728
|
|
|
1602
|
-
function
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
renderTaskColumn('completedTasks', completedTasks);
|
|
1729
|
+
function setupTaskScrollListeners() {
|
|
1730
|
+
['todoTasks', 'inProgressTasks', 'completedTasks'].forEach(id => {
|
|
1731
|
+
const el = document.getElementById(id);
|
|
1732
|
+
if (!el) return;
|
|
1733
|
+
|
|
1734
|
+
el.onscroll = () => {
|
|
1735
|
+
if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {
|
|
1736
|
+
const category = id === 'todoTasks' ? 'todo' : (id === 'inProgressTasks' ? 'in_progress' : 'completed');
|
|
1737
|
+
const status = category === 'todo' ? 'pending,blocked,canceled' : (category === 'in_progress' ? 'in_progress' : 'completed');
|
|
1738
|
+
loadTaskCategory(status);
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
});
|
|
1616
1742
|
}
|
|
1617
1743
|
|
|
1618
|
-
function
|
|
1619
|
-
const container = document.getElementById(
|
|
1744
|
+
function renderTaskCards(containerId, tasks, clear = false) {
|
|
1745
|
+
const container = document.getElementById(containerId);
|
|
1620
1746
|
if (!container) return;
|
|
1621
|
-
|
|
1622
|
-
if (!tasks || tasks.length === 0) {
|
|
1747
|
+
|
|
1748
|
+
if (clear && (!tasks || tasks.length === 0)) {
|
|
1623
1749
|
container.innerHTML = '<div class="text-center py-8 text-gray-400 text-xs italic bg-gray-50/50 dark:bg-gray-900/20 rounded-xl border border-dashed border-gray-200 dark:border-gray-700">No tasks</div>';
|
|
1624
1750
|
return;
|
|
1625
1751
|
}
|
|
1626
1752
|
|
|
1627
|
-
|
|
1628
|
-
<div class="bg-white dark:bg-gray-700 p-4 rounded-xl shadow-sm border border-gray-100 dark:border-gray-600 hover:shadow-md transition-all group">
|
|
1753
|
+
const html = tasks.map(t => `
|
|
1754
|
+
<div onclick="showTaskDetail('${t.id}')" class="bg-white dark:bg-gray-700 p-4 rounded-xl shadow-sm border border-gray-100 dark:border-gray-600 hover:shadow-md transition-all group cursor-pointer">
|
|
1629
1755
|
<div class="flex items-center justify-between mb-2">
|
|
1630
1756
|
<div class="flex items-center gap-2">
|
|
1631
1757
|
<span class="px-1.5 py-0.5 rounded bg-gray-100 dark:bg-gray-800 text-[10px] font-bold text-gray-600 dark:text-gray-400 font-mono border border-gray-200 dark:border-gray-700">${t.task_code}</span>
|
|
1632
1758
|
<span class="text-[10px] font-bold uppercase tracking-wider text-gray-400">${t.phase}</span>
|
|
1759
|
+
${t.status === 'blocked' ? '<span class="px-1 py-0.5 rounded bg-red-500 text-white text-[8px] font-bold uppercase">Blocked</span>' : ''}
|
|
1760
|
+
${t.status === 'canceled' ? '<span class="px-1 py-0.5 rounded bg-slate-500 text-white text-[8px] font-bold uppercase">Canceled</span>' : ''}
|
|
1633
1761
|
</div>
|
|
1634
1762
|
<div class="flex items-center gap-1">
|
|
1635
1763
|
${t.priority >= 4 ? '<span class="w-2 h-2 rounded-full bg-red-500 animate-pulse"></span>' : ''}
|
|
@@ -1637,7 +1765,25 @@ function renderTaskColumn(id, tasks) {
|
|
|
1637
1765
|
</div>
|
|
1638
1766
|
</div>
|
|
1639
1767
|
<h4 class="font-bold text-sm text-gray-900 dark:text-gray-100 mb-1">${escapeHtml(t.title)}</h4>
|
|
1640
|
-
<p class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mb-
|
|
1768
|
+
<p class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mb-2">${escapeHtml(t.description || '')}</p>
|
|
1769
|
+
|
|
1770
|
+
${t.doc_path ? `
|
|
1771
|
+
<div class="mb-3" onclick="event.stopPropagation()">
|
|
1772
|
+
<a href="${t.doc_path.startsWith('http') ? t.doc_path : '#'}" target="_blank" class="inline-flex items-center gap-1.5 px-2 py-1 rounded bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 text-[10px] text-slate-500 dark:text-gray-400 hover:text-sky-600 transition-colors">
|
|
1773
|
+
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg>
|
|
1774
|
+
<span class="truncate max-w-[150px]">${escapeHtml(t.doc_path)}</span>
|
|
1775
|
+
</a>
|
|
1776
|
+
</div>
|
|
1777
|
+
` : ''}
|
|
1778
|
+
|
|
1779
|
+
<div class="flex items-center gap-2 mb-3">
|
|
1780
|
+
<div class="px-1.5 py-0.5 rounded bg-sky-50 dark:bg-sky-900/30 border border-sky-100 dark:border-sky-800 flex items-center gap-1">
|
|
1781
|
+
<span class="text-[9px] font-bold text-sky-600 dark:text-sky-400">${escapeHtml(t.agent || 'unknown')}</span>
|
|
1782
|
+
<span class="text-[8px] text-sky-400 dark:text-sky-600">|</span>
|
|
1783
|
+
<span class="text-[9px] font-medium text-sky-500 dark:text-sky-500">${escapeHtml(t.role || 'unknown')}</span>
|
|
1784
|
+
</div>
|
|
1785
|
+
</div>
|
|
1786
|
+
|
|
1641
1787
|
${t.depends_on ? `
|
|
1642
1788
|
<div class="mt-2 pt-2 border-t border-gray-50 dark:border-gray-600 flex items-center gap-1.5">
|
|
1643
1789
|
<svg class="w-3 h-3 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path></svg>
|
|
@@ -1646,10 +1792,117 @@ function renderTaskColumn(id, tasks) {
|
|
|
1646
1792
|
` : ''}
|
|
1647
1793
|
<div class="mt-3 flex items-center justify-between">
|
|
1648
1794
|
<span class="text-[10px] font-mono text-gray-400">${t.id.substring(0, 8)}</span>
|
|
1649
|
-
<span class="text-[10px] text-gray-400">${formatDate(t.created_at)}</span>
|
|
1795
|
+
<span class="text-[10px] text-gray-400">${t.status === 'completed' && t.finished_at ? 'Done ' + formatDate(t.finished_at) : formatDate(t.created_at)}</span>
|
|
1650
1796
|
</div>
|
|
1651
1797
|
</div>
|
|
1652
1798
|
`).join('');
|
|
1799
|
+
|
|
1800
|
+
if (clear) {
|
|
1801
|
+
container.innerHTML = html;
|
|
1802
|
+
} else {
|
|
1803
|
+
container.insertAdjacentHTML('beforeend', html);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
async function showTaskDetail(id) {
|
|
1808
|
+
const drawer = document.getElementById('memoryDrawer');
|
|
1809
|
+
const title = document.getElementById('drawerTitle');
|
|
1810
|
+
const body = document.getElementById('drawerBody');
|
|
1811
|
+
|
|
1812
|
+
title.textContent = 'Loading Task...';
|
|
1813
|
+
body.innerHTML = `
|
|
1814
|
+
<div class="space-y-4">
|
|
1815
|
+
<div class="skeleton h-20 w-full"></div>
|
|
1816
|
+
<div class="grid gap-4 md:grid-cols-2">
|
|
1817
|
+
<div class="skeleton h-36 w-full"></div>
|
|
1818
|
+
<div class="skeleton h-36 w-full"></div>
|
|
1819
|
+
</div>
|
|
1820
|
+
<div class="skeleton h-64 w-full"></div>
|
|
1821
|
+
</div>
|
|
1822
|
+
`;
|
|
1823
|
+
|
|
1824
|
+
drawer.classList.remove('hidden');
|
|
1825
|
+
document.body.classList.add('drawer-open');
|
|
1826
|
+
|
|
1827
|
+
// Trigger slide-in animation
|
|
1828
|
+
setTimeout(() => {
|
|
1829
|
+
const aside = document.getElementById('drawerAside');
|
|
1830
|
+
if (aside) {
|
|
1831
|
+
aside.classList.remove('translate-x-full');
|
|
1832
|
+
aside.classList.add('translate-x-0');
|
|
1833
|
+
}
|
|
1834
|
+
}, 10);
|
|
1835
|
+
|
|
1836
|
+
try {
|
|
1837
|
+
const response = await fetch(`/api/tasks/${id}?repo=${encodeURIComponent(currentRepo)}`);
|
|
1838
|
+
const task = await response.json();
|
|
1839
|
+
if (!response.ok) throw new Error(task.error || 'Failed to load task');
|
|
1840
|
+
|
|
1841
|
+
title.textContent = `Task: ${task.task_code}`;
|
|
1842
|
+
|
|
1843
|
+
body.innerHTML = `
|
|
1844
|
+
<div class="space-y-6">
|
|
1845
|
+
<div class="p-5 bg-slate-50 dark:bg-slate-900/50 rounded-2xl border border-slate-100 dark:border-slate-800 shadow-sm">
|
|
1846
|
+
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-3">Title</div>
|
|
1847
|
+
<h3 class="text-xl font-bold text-slate-900 dark:text-white leading-tight">${escapeHtml(task.title)}</h3>
|
|
1848
|
+
</div>
|
|
1849
|
+
|
|
1850
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
1851
|
+
<div class="p-4 bg-white dark:bg-slate-800/40 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
1852
|
+
<div class="text-[10px] font-bold text-slate-400 uppercase mb-2">Status & Priority</div>
|
|
1853
|
+
<div class="flex flex-wrap gap-2">
|
|
1854
|
+
<span class="px-2 py-1 rounded-lg bg-sky-500/10 text-sky-600 dark:text-sky-400 text-xs font-bold border border-sky-500/20 capitalize">${task.status}</span>
|
|
1855
|
+
<span class="px-2 py-1 rounded-lg bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 text-xs font-bold border border-indigo-500/20">P${task.priority}</span>
|
|
1856
|
+
<span class="px-2 py-1 rounded-lg bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 text-xs font-bold border border-slate-200 dark:border-slate-700 uppercase">${task.phase}</span>
|
|
1857
|
+
</div>
|
|
1858
|
+
</div>
|
|
1859
|
+
<div class="p-4 bg-white dark:bg-slate-800/40 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
1860
|
+
<div class="text-[10px] font-bold text-slate-400 uppercase mb-2">Owner</div>
|
|
1861
|
+
<div class="flex items-center gap-2">
|
|
1862
|
+
<div class="w-8 h-8 rounded-full bg-gradient-to-tr from-sky-400 to-indigo-500 flex items-center justify-center text-white text-[10px] font-bold">
|
|
1863
|
+
${getRepoInitials(task.agent || 'UK')}
|
|
1864
|
+
</div>
|
|
1865
|
+
<div>
|
|
1866
|
+
<div class="text-xs font-bold">${escapeHtml(task.agent || 'unknown')}</div>
|
|
1867
|
+
<div class="text-[10px] text-slate-500 dark:text-slate-400">${escapeHtml(task.role || 'unknown')}</div>
|
|
1868
|
+
</div>
|
|
1869
|
+
</div>
|
|
1870
|
+
</div>
|
|
1871
|
+
</div>
|
|
1872
|
+
|
|
1873
|
+
<div class="p-5 bg-white dark:bg-slate-800/40 rounded-2xl border border-slate-100 dark:border-slate-800">
|
|
1874
|
+
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-3">Description</div>
|
|
1875
|
+
<div class="text-sm text-slate-600 dark:text-slate-300 leading-relaxed markdown-body">
|
|
1876
|
+
${task.description ? renderMarkdown(task.description) : '<span class="italic opacity-50">No description provided</span>'}
|
|
1877
|
+
</div>
|
|
1878
|
+
</div>
|
|
1879
|
+
|
|
1880
|
+
${task.doc_path ? `
|
|
1881
|
+
<div class="p-4 bg-sky-500/5 dark:bg-sky-500/10 rounded-xl border border-sky-500/20">
|
|
1882
|
+
<div class="text-[10px] font-bold text-sky-600/60 dark:text-sky-400/60 uppercase mb-2">Documentation</div>
|
|
1883
|
+
<a href="${task.doc_path.startsWith('http') ? task.doc_path : '#'}" target="_blank" class="flex items-center gap-2 text-sky-600 dark:text-sky-400 hover:underline" onclick="event.stopPropagation()">
|
|
1884
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
|
|
1885
|
+
<span class="text-sm font-medium truncate">${escapeHtml(task.doc_path)}</span>
|
|
1886
|
+
</a>
|
|
1887
|
+
</div>
|
|
1888
|
+
` : ''}
|
|
1889
|
+
|
|
1890
|
+
<div class="pt-4 border-t border-slate-100 dark:border-slate-800 grid grid-cols-2 gap-4">
|
|
1891
|
+
<div>
|
|
1892
|
+
<div class="text-[9px] font-bold text-slate-400 uppercase">Created</div>
|
|
1893
|
+
<div class="text-[11px] text-slate-500">${new Date(task.created_at).toLocaleString()}</div>
|
|
1894
|
+
</div>
|
|
1895
|
+
<div>
|
|
1896
|
+
<div class="text-[9px] font-bold text-slate-400 uppercase">Updated</div>
|
|
1897
|
+
<div class="text-[11px] text-slate-500">${new Date(task.updated_at).toLocaleString()}</div>
|
|
1898
|
+
</div>
|
|
1899
|
+
</div>
|
|
1900
|
+
</div>
|
|
1901
|
+
`;
|
|
1902
|
+
} catch (err) {
|
|
1903
|
+
showToast('Failed to load task: ' + err.message, 'error');
|
|
1904
|
+
closeDrawer();
|
|
1905
|
+
}
|
|
1653
1906
|
}
|
|
1654
1907
|
|
|
1655
1908
|
function getPriorityColor(p) {
|
|
@@ -1665,25 +1918,27 @@ function switchTab(tab) {
|
|
|
1665
1918
|
const dashTab = document.getElementById('dashboardTabBtn');
|
|
1666
1919
|
const memTab = document.getElementById('memoriesTabBtn');
|
|
1667
1920
|
const taskTab = document.getElementById('tasksTabBtn');
|
|
1921
|
+
const refTab = document.getElementById('referenceTabBtn');
|
|
1668
1922
|
const indicator = document.getElementById('tabIndicator');
|
|
1669
|
-
|
|
1923
|
+
|
|
1670
1924
|
const dashContent = document.getElementById('dashboardContent');
|
|
1671
1925
|
const memContent = document.getElementById('memoriesContent');
|
|
1672
1926
|
const taskContent = document.getElementById('tasksContent');
|
|
1927
|
+
const refContent = document.getElementById('referenceContent');
|
|
1673
1928
|
|
|
1674
1929
|
currentTab = tab;
|
|
1675
1930
|
localStorage.setItem('activeTab', tab);
|
|
1676
1931
|
|
|
1677
|
-
const tabs = [dashTab, memTab, taskTab];
|
|
1678
|
-
const contents = [dashContent, memContent, taskContent];
|
|
1679
|
-
const targetId = tab + 'TabBtn';
|
|
1932
|
+
const tabs = [dashTab, memTab, taskTab, refTab];
|
|
1933
|
+
const contents = [dashContent, memContent, taskContent, refContent]; const targetId = tab + 'TabBtn';
|
|
1680
1934
|
const targetContentId = tab + 'Content';
|
|
1681
1935
|
|
|
1682
1936
|
// Update indicator
|
|
1683
1937
|
if (indicator) {
|
|
1684
1938
|
if (tab === 'dashboard') indicator.style.transform = 'translateX(0)';
|
|
1685
|
-
|
|
1686
|
-
|
|
1939
|
+
if (tab === 'memories') indicator.style.transform = 'translateX(100%)';
|
|
1940
|
+
if (tab === 'tasks') indicator.style.transform = 'translateX(200%)';
|
|
1941
|
+
if (tab === 'reference') indicator.style.transform = 'translateX(300%)';
|
|
1687
1942
|
}
|
|
1688
1943
|
|
|
1689
1944
|
// Update button states
|
|
@@ -1714,6 +1969,8 @@ function switchTab(tab) {
|
|
|
1714
1969
|
if (tab === 'tasks') loadTasks();
|
|
1715
1970
|
if (tab === 'dashboard') loadStats();
|
|
1716
1971
|
if (tab === 'memories') loadMemories();
|
|
1972
|
+
if (tab === 'reference') loadCapabilities();
|
|
1973
|
+
syncStickyOffsets();
|
|
1717
1974
|
}
|
|
1718
1975
|
|
|
1719
1976
|
window.loadTasks = loadTasks;
|
|
@@ -1765,8 +2022,194 @@ safeAddEventListener('repoCollapsedSummaryButton', 'click', () => {
|
|
|
1765
2022
|
}
|
|
1766
2023
|
});
|
|
1767
2024
|
|
|
2025
|
+
safeAddEventListener('taskSearchInput', 'input', () => {
|
|
2026
|
+
if (window.taskSearchDebounce) clearTimeout(window.taskSearchDebounce);
|
|
2027
|
+
window.taskSearchDebounce = setTimeout(() => {
|
|
2028
|
+
loadTasks();
|
|
2029
|
+
}, 300);
|
|
2030
|
+
});
|
|
2031
|
+
|
|
1768
2032
|
window.addEventListener('resize', syncStickyOffsets);
|
|
1769
2033
|
|
|
2034
|
+
let currentCapabilities = { tools: [], resources: [], prompts: [] };
|
|
2035
|
+
|
|
2036
|
+
async function loadCapabilities() {
|
|
2037
|
+
const toolsList = document.getElementById('toolsList');
|
|
2038
|
+
const resourcesList = document.getElementById('resourcesList');
|
|
2039
|
+
const promptsList = document.getElementById('promptsList');
|
|
2040
|
+
|
|
2041
|
+
if (!toolsList) return;
|
|
2042
|
+
|
|
2043
|
+
toolsList.innerHTML = '<div class="text-center py-4 text-gray-400 text-xs">Loading capabilities...</div>';
|
|
2044
|
+
|
|
2045
|
+
try {
|
|
2046
|
+
const response = await fetch('/api/capabilities');
|
|
2047
|
+
const data = await response.json();
|
|
2048
|
+
|
|
2049
|
+
currentCapabilities.tools = Array.isArray(data.tools) ? data.tools : [];
|
|
2050
|
+
currentCapabilities.resources = Array.isArray(data.resources) ? data.resources : [];
|
|
2051
|
+
currentCapabilities.prompts = Array.isArray(data.prompts) ? data.prompts : [];
|
|
2052
|
+
|
|
2053
|
+
toolsList.innerHTML = currentCapabilities.tools.map(t => `
|
|
2054
|
+
<div onclick="showCapabilityDetail('tools', '${t.name}')" class="p-3 bg-slate-50 dark:bg-slate-900/50 border border-slate-100 dark:border-slate-800 rounded-lg cursor-pointer hover:border-sky-500/50 transition-all group">
|
|
2055
|
+
<div class="font-bold text-xs text-sky-600 dark:text-sky-400 mb-1 group-hover:text-sky-500">${escapeHtml(t.name)}</div>
|
|
2056
|
+
<p class="text-[10px] text-gray-500 dark:text-gray-400 line-clamp-2">${escapeHtml(t.description)}</p>
|
|
2057
|
+
</div>
|
|
2058
|
+
`).join('') || '<div class="text-center py-4 text-gray-400 text-xs">No tools available</div>';
|
|
2059
|
+
|
|
2060
|
+
resourcesList.innerHTML = currentCapabilities.resources.map(r => `
|
|
2061
|
+
<div onclick="showCapabilityDetail('resources', '${r.name}')" class="p-3 bg-slate-50 dark:bg-slate-900/50 border border-slate-100 dark:border-slate-800 rounded-lg cursor-pointer hover:border-indigo-500/50 transition-all group">
|
|
2062
|
+
<div class="font-bold text-xs text-indigo-600 dark:text-indigo-400 mb-1 group-hover:text-indigo-500">${escapeHtml(r.name)}</div>
|
|
2063
|
+
<p class="text-[10px] text-gray-500 dark:text-gray-400 line-clamp-2">${escapeHtml(r.description || 'No description')}</p>
|
|
2064
|
+
<div class="text-[8px] font-mono text-gray-400 mt-1 truncate">${escapeHtml(r.uri)}</div>
|
|
2065
|
+
</div>
|
|
2066
|
+
`).join('') || '<div class="text-center py-4 text-gray-400 text-xs">No resources available</div>';
|
|
2067
|
+
|
|
2068
|
+
promptsList.innerHTML = currentCapabilities.prompts.map(p => `
|
|
2069
|
+
<div onclick="showCapabilityDetail('prompts', '${p.name}')" class="p-3 bg-slate-50 dark:bg-slate-900/50 border border-slate-100 dark:border-slate-800 rounded-lg cursor-pointer hover:border-emerald-500/50 transition-all group">
|
|
2070
|
+
<div class="font-bold text-xs text-emerald-600 dark:text-emerald-400 mb-1 group-hover:text-emerald-500">${escapeHtml(p.name)}</div>
|
|
2071
|
+
<p class="text-[10px] text-gray-500 dark:text-gray-400 line-clamp-2">${escapeHtml(p.description || 'No description')}</p>
|
|
2072
|
+
</div>
|
|
2073
|
+
`).join('') || '<div class="text-center py-4 text-gray-400 text-xs">No prompts available</div>';
|
|
2074
|
+
|
|
2075
|
+
} catch (err) {
|
|
2076
|
+
console.error('Failed to load capabilities:', err);
|
|
2077
|
+
toolsList.innerHTML = `<div class="text-center py-4 text-red-400 text-xs">Error: ${err.message}</div>`;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
async function handleCsvImport(event) {
|
|
2082
|
+
const file = event.target.files[0];
|
|
2083
|
+
if (!file || !currentRepo) return;
|
|
2084
|
+
|
|
2085
|
+
const reader = new FileReader();
|
|
2086
|
+
reader.onload = async (e) => {
|
|
2087
|
+
const csvData = e.target.result;
|
|
2088
|
+
try {
|
|
2089
|
+
const response = await fetch('/api/tasks/import-csv', {
|
|
2090
|
+
method: 'POST',
|
|
2091
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2092
|
+
body: JSON.stringify({ repo: currentRepo, csvData })
|
|
2093
|
+
});
|
|
2094
|
+
const result = await response.json();
|
|
2095
|
+
if (result.success) {
|
|
2096
|
+
showToast(`Successfully imported ${result.count} tasks`, 'success');
|
|
2097
|
+
loadTasks();
|
|
2098
|
+
loadStats();
|
|
2099
|
+
} else {
|
|
2100
|
+
showToast(result.error || 'Failed to import CSV', 'error');
|
|
2101
|
+
}
|
|
2102
|
+
} catch (err) {
|
|
2103
|
+
showToast('Import failed: ' + err.message, 'error');
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
reader.readAsText(file);
|
|
2107
|
+
event.target.value = '';
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
function downloadCsvTemplate() {
|
|
2111
|
+
const headers = "task_code,phase,title,description,priority,status,agent,role,doc_path";
|
|
2112
|
+
const example = "TASK-001,research,Integrate CSV,Add import feature to dashboard,4,pending,Gemini CLI,expert,docs/tasks.md";
|
|
2113
|
+
const csv = `${headers}\n${example}`;
|
|
2114
|
+
|
|
2115
|
+
const blob = new Blob([csv], { type: 'text/csv' });
|
|
2116
|
+
const url = window.URL.createObjectURL(blob);
|
|
2117
|
+
const a = document.createElement('a');
|
|
2118
|
+
a.setAttribute('hidden', '');
|
|
2119
|
+
a.setAttribute('href', url);
|
|
2120
|
+
a.setAttribute('download', 'task_template.csv');
|
|
2121
|
+
document.body.appendChild(a);
|
|
2122
|
+
a.click();
|
|
2123
|
+
document.body.removeChild(a);
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
function showCapabilityDetail(type, name) {
|
|
2127
|
+
const item = currentCapabilities[type].find(i => i.name === name);
|
|
2128
|
+
if (!item) return;
|
|
2129
|
+
|
|
2130
|
+
const drawer = document.getElementById('memoryDrawer');
|
|
2131
|
+
const title = document.getElementById('drawerTitle');
|
|
2132
|
+
const body = document.getElementById('drawerBody');
|
|
2133
|
+
|
|
2134
|
+
title.textContent = `${type.charAt(0).toUpperCase() + type.slice(1)}: ${name}`;
|
|
2135
|
+
|
|
2136
|
+
let contentHtml = `
|
|
2137
|
+
<div class="space-y-6">
|
|
2138
|
+
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
2139
|
+
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">Description</h4>
|
|
2140
|
+
<p class="text-sm text-slate-600 dark:text-slate-300">${escapeHtml(item.description || 'No description')}</p>
|
|
2141
|
+
</div>
|
|
2142
|
+
`;
|
|
2143
|
+
|
|
2144
|
+
if (type === 'tools' && item.inputSchema) {
|
|
2145
|
+
contentHtml += `
|
|
2146
|
+
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
2147
|
+
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">Input Schema</h4>
|
|
2148
|
+
<pre class="text-[10px] font-mono text-sky-600 dark:text-sky-400 overflow-x-auto">${JSON.stringify(item.inputSchema, null, 2)}</pre>
|
|
2149
|
+
</div>
|
|
2150
|
+
`;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
if (type === 'resources' && item.uri) {
|
|
2154
|
+
contentHtml += `
|
|
2155
|
+
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
2156
|
+
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">URI</h4>
|
|
2157
|
+
<code class="text-xs font-mono text-indigo-600 dark:text-indigo-400">${escapeHtml(item.uri)}</code>
|
|
2158
|
+
</div>
|
|
2159
|
+
`;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if (type === 'prompts' && item.arguments) {
|
|
2163
|
+
contentHtml += `
|
|
2164
|
+
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
2165
|
+
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">Arguments</h4>
|
|
2166
|
+
<div class="space-y-3">
|
|
2167
|
+
${item.arguments.map(arg => `
|
|
2168
|
+
<div class="border-l-2 border-emerald-500 pl-3 py-1">
|
|
2169
|
+
<div class="text-xs font-bold text-emerald-600 dark:text-emerald-400">${escapeHtml(arg.name)} ${arg.required ? '<span class="text-[8px] bg-emerald-500 text-white px-1 rounded">REQUIRED</span>' : ''}</div>
|
|
2170
|
+
<div class="text-[10px] text-gray-500 dark:text-gray-400">${escapeHtml(arg.description || '')}</div>
|
|
2171
|
+
</div>
|
|
2172
|
+
`).join('')}
|
|
2173
|
+
</div>
|
|
2174
|
+
</div>
|
|
2175
|
+
`;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
if (type === 'prompts' && item.messages) {
|
|
2179
|
+
contentHtml += `
|
|
2180
|
+
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-100 dark:border-slate-800">
|
|
2181
|
+
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">Instructions</h4>
|
|
2182
|
+
<div class="space-y-4">
|
|
2183
|
+
${item.messages.map(msg => {
|
|
2184
|
+
const rawContent = typeof msg.content === 'string' ? msg.content : (msg.content?.text || '');
|
|
2185
|
+
const renderedMarkdown = window.marked ? window.marked.parse(rawContent) : escapeHtml(rawContent);
|
|
2186
|
+
return `
|
|
2187
|
+
<div class="space-y-1">
|
|
2188
|
+
<div class="text-[10px] font-bold uppercase tracking-wider text-slate-400">${escapeHtml(msg.role)}</div>
|
|
2189
|
+
<div class="p-4 bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 rounded-lg text-sm markdown-body">
|
|
2190
|
+
${renderedMarkdown}
|
|
2191
|
+
</div>
|
|
2192
|
+
</div>
|
|
2193
|
+
`;
|
|
2194
|
+
}).join('')}
|
|
2195
|
+
</div>
|
|
2196
|
+
</div>
|
|
2197
|
+
`;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
contentHtml += `</div>`;
|
|
2201
|
+
body.innerHTML = contentHtml;
|
|
2202
|
+
|
|
2203
|
+
drawer.classList.remove('hidden');
|
|
2204
|
+
document.body.classList.add('drawer-open');
|
|
2205
|
+
setTimeout(() => document.getElementById('drawerAside').classList.remove('translate-x-full'), 10);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
window.handleCsvImport = handleCsvImport;
|
|
2209
|
+
window.downloadCsvTemplate = downloadCsvTemplate;
|
|
2210
|
+
window.loadCapabilities = loadCapabilities;
|
|
2211
|
+
window.showCapabilityDetail = showCapabilityDetail;
|
|
2212
|
+
|
|
1770
2213
|
initTheme();
|
|
1771
2214
|
initRepoSidebarState();
|
|
1772
2215
|
initPinnedRepos();
|