agentopia 1.0.0 → 1.1.1
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/.claude/settings.local.json +2 -2
- package/README.md +284 -0
- package/bin/agentopia.js +2 -0
- package/dist/app.js +2 -2
- package/dist/app.js.map +1 -1
- package/dist/config.js +4 -4
- package/dist/config.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/middleware/auth.js +13 -13
- package/dist/middleware/auth.js.map +1 -1
- package/dist/routes/agents.js +1 -1
- package/dist/routes/agents.js.map +1 -1
- package/dist/services/agent-issue-batch.js +1 -1
- package/dist/services/agent-issue-batch.js.map +1 -1
- package/dist/services/process-manager.js +13 -13
- package/dist/services/process-manager.js.map +1 -1
- package/dist/services/scheduler.js +3 -3
- package/dist/services/scheduler.js.map +1 -1
- package/dist/services/system-prompt.js +2 -2
- package/package.json +10 -1
- package/public/admin-users.html +3 -3
- package/public/agent.html +3 -3
- package/public/index.html +3 -3
- package/public/issue.html +3 -3
- package/public/js/common.js +10 -10
- package/public/js/dashboard.js +1 -1
- package/public/js/files-panel.js +1 -1
- package/public/js/interactive-terminal.js +1 -1
- package/public/js/issue.js +1 -1
- package/public/js/project.js +71 -56
- package/public/js/terminal.js +1 -1
- package/public/project.html +3 -3
- package/public/terminal.html +2 -2
- package/send_message_and_update_issue.js +1 -1
- package/update_round2_and_create_round3.js +1 -1
package/public/admin-users.html
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - User Management</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<div class="overlay" id="overlay" onclick="closeDrawer()"></div>
|
|
11
11
|
<div class="drawer" id="drawer">
|
|
12
12
|
<div class="drawer-header">
|
|
13
|
-
<h3><span style="color:var(--accent)">
|
|
13
|
+
<h3><span style="color:var(--accent)">Agentopia</span></h3>
|
|
14
14
|
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
|
15
15
|
</div>
|
|
16
16
|
<div class="drawer-content">
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<button class="menu-btn" onclick="toggleDrawer()">
|
|
43
43
|
<span></span><span></span><span></span>
|
|
44
44
|
</button>
|
|
45
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
45
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
46
46
|
<div class="breadcrumb" style="margin-left:12px">
|
|
47
47
|
<a href="/">Home</a> / <span>User Management</span>
|
|
48
48
|
</div>
|
package/public/agent.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - Agent Terminal</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
<link rel="stylesheet" href="/public/vendor/xterm.css">
|
|
9
9
|
</head>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<div class="overlay" id="overlay" onclick="closeDrawer()"></div>
|
|
12
12
|
<div class="drawer" id="drawer">
|
|
13
13
|
<div class="drawer-header">
|
|
14
|
-
<h3><span style="color:var(--accent)">
|
|
14
|
+
<h3><span style="color:var(--accent)">Agentopia</span></h3>
|
|
15
15
|
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
|
16
16
|
</div>
|
|
17
17
|
<div class="drawer-content">
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
<button class="menu-btn" onclick="toggleDrawer()">
|
|
56
56
|
<span></span><span></span><span></span>
|
|
57
57
|
</button>
|
|
58
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
58
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
59
59
|
<div class="breadcrumb" style="margin-left:12px">
|
|
60
60
|
<a href="/">Projects</a> / <a id="project-link" href="#">Project</a> / <span id="agent-name">Agent</span>
|
|
61
61
|
</div>
|
package/public/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - Multi-Agent Platform</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
<link rel="stylesheet" href="/public/css/issues.css">
|
|
9
9
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<!-- Drawer -->
|
|
16
16
|
<div class="drawer" id="drawer">
|
|
17
17
|
<div class="drawer-header">
|
|
18
|
-
<h3><span style="color:var(--accent)">
|
|
18
|
+
<h3><span style="color:var(--accent)">Agentopia</span></h3>
|
|
19
19
|
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="drawer-content">
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
<button class="menu-btn" onclick="toggleDrawer()">
|
|
61
61
|
<span></span><span></span><span></span>
|
|
62
62
|
</button>
|
|
63
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
63
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
64
64
|
<div class="header-right">
|
|
65
65
|
<button class="btn btn-primary btn-sm" onclick="showCreateModal()">+ New Project</button>
|
|
66
66
|
</div>
|
package/public/issue.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - Issue</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
<link rel="stylesheet" href="/public/css/issues.css">
|
|
9
9
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<div class="overlay" id="overlay" onclick="closeDrawer()"></div>
|
|
13
13
|
<div class="drawer" id="drawer">
|
|
14
14
|
<div class="drawer-header">
|
|
15
|
-
<h3><span style="color:var(--accent)">
|
|
15
|
+
<h3><span style="color:var(--accent)">Agentopia</span></h3>
|
|
16
16
|
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
|
17
17
|
</div>
|
|
18
18
|
<div class="drawer-content">
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
<button class="menu-btn" onclick="toggleDrawer()">
|
|
57
57
|
<span></span><span></span><span></span>
|
|
58
58
|
</button>
|
|
59
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
59
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
60
60
|
<div class="breadcrumb" style="margin-left:12px">
|
|
61
61
|
<a href="/">Projects</a> / <a id="project-link" href="#">Project</a> / <a id="issues-link" href="#">Issues</a> / <span id="issue-title-breadcrumb">Issue</span>
|
|
62
62
|
</div>
|
package/public/js/common.js
CHANGED
|
@@ -6,13 +6,13 @@ async function initUserMenu() {
|
|
|
6
6
|
try {
|
|
7
7
|
const res = await fetch('/api/auth/me', { cache: 'no-cache' });
|
|
8
8
|
if (!res.ok) {
|
|
9
|
-
console.warn('[
|
|
9
|
+
console.warn('[Agentopia] initUserMenu: /api/auth/me returned', res.status, '— avatar will not show');
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
_currentUser = await res.json();
|
|
13
|
-
window.dispatchEvent(new CustomEvent('
|
|
13
|
+
window.dispatchEvent(new CustomEvent('agentopia:user-ready', { detail: _currentUser }));
|
|
14
14
|
} catch (e) {
|
|
15
|
-
console.warn('[
|
|
15
|
+
console.warn('[Agentopia] initUserMenu: fetch failed —', e.message || e);
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -335,7 +335,7 @@ const themes = {
|
|
|
335
335
|
|
|
336
336
|
function applyTheme(name) {
|
|
337
337
|
// Backward compat: 'nord' was renamed to 'nord-dark'
|
|
338
|
-
if (name === 'nord') { name = 'nord-dark'; localStorage.setItem('
|
|
338
|
+
if (name === 'nord') { name = 'nord-dark'; localStorage.setItem('agentopia-theme', name); }
|
|
339
339
|
const t = themes[name] || themes['github-dark'];
|
|
340
340
|
const r = document.documentElement;
|
|
341
341
|
r.style.setProperty('--bg', t.bg);
|
|
@@ -352,7 +352,7 @@ function applyTheme(name) {
|
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
function changeTheme(name) {
|
|
355
|
-
localStorage.setItem('
|
|
355
|
+
localStorage.setItem('agentopia-theme', name);
|
|
356
356
|
applyTheme(name);
|
|
357
357
|
}
|
|
358
358
|
|
|
@@ -446,7 +446,7 @@ function _playDingSound(ctx) {
|
|
|
446
446
|
|
|
447
447
|
function playNotificationSound() {
|
|
448
448
|
// Check setting
|
|
449
|
-
if (localStorage.getItem('
|
|
449
|
+
if (localStorage.getItem('agentopia-notification-sound') === 'off') return;
|
|
450
450
|
|
|
451
451
|
// Throttle: no more than once per 5 seconds
|
|
452
452
|
var now = Date.now();
|
|
@@ -473,9 +473,9 @@ function playNotificationSound() {
|
|
|
473
473
|
}
|
|
474
474
|
|
|
475
475
|
function toggleNotificationSound() {
|
|
476
|
-
const current = localStorage.getItem('
|
|
476
|
+
const current = localStorage.getItem('agentopia-notification-sound') !== 'off';
|
|
477
477
|
const newVal = current ? 'off' : 'on';
|
|
478
|
-
localStorage.setItem('
|
|
478
|
+
localStorage.setItem('agentopia-notification-sound', newVal);
|
|
479
479
|
// Update all toggles on the page
|
|
480
480
|
document.querySelectorAll('.notif-sound-toggle').forEach(function(el) {
|
|
481
481
|
el.classList.toggle('on', newVal === 'on');
|
|
@@ -484,7 +484,7 @@ function toggleNotificationSound() {
|
|
|
484
484
|
|
|
485
485
|
// Init notification sound toggles on page load
|
|
486
486
|
document.addEventListener('DOMContentLoaded', function() {
|
|
487
|
-
const isOn = localStorage.getItem('
|
|
487
|
+
const isOn = localStorage.getItem('agentopia-notification-sound') !== 'off';
|
|
488
488
|
document.querySelectorAll('.notif-sound-toggle').forEach(function(el) {
|
|
489
489
|
el.classList.toggle('on', isOn);
|
|
490
490
|
});
|
|
@@ -492,7 +492,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
492
492
|
|
|
493
493
|
// Init theme
|
|
494
494
|
(function() {
|
|
495
|
-
const saved = localStorage.getItem('
|
|
495
|
+
const saved = localStorage.getItem('agentopia-theme') || 'solarized-light';
|
|
496
496
|
applyTheme(saved);
|
|
497
497
|
const sel = document.getElementById('theme-select');
|
|
498
498
|
if (sel) sel.value = saved;
|
package/public/js/dashboard.js
CHANGED
|
@@ -701,7 +701,7 @@ loadDashboard();
|
|
|
701
701
|
setInterval(() => { loadDashboardSummary(); loadNotifications(); }, 10000);
|
|
702
702
|
setInterval(loadProjects, 30000);
|
|
703
703
|
setInterval(loadUsageByProject, 60000);
|
|
704
|
-
window.addEventListener('
|
|
704
|
+
window.addEventListener('agentopia:user-ready', () => { loadProjects(); });
|
|
705
705
|
|
|
706
706
|
// ─── Floating Issue Panel ───
|
|
707
707
|
|
package/public/js/files-panel.js
CHANGED
|
@@ -176,7 +176,7 @@ async function loadAgentInfo() {
|
|
|
176
176
|
document.getElementById('agent-name').textContent = agent.name;
|
|
177
177
|
document.getElementById('agent-link').textContent = agent.name;
|
|
178
178
|
document.getElementById('agent-link').href = `/agents/${agentId}`;
|
|
179
|
-
document.title = `
|
|
179
|
+
document.title = `Agentopia - ${agent.name} Terminal`;
|
|
180
180
|
|
|
181
181
|
// Load project info
|
|
182
182
|
const pres = await fetch(`/api/projects/${agent.project_id}`, { headers: apiHeaders() });
|
package/public/js/issue.js
CHANGED
|
@@ -33,7 +33,7 @@ async function loadIssue() {
|
|
|
33
33
|
document.getElementById('issues-link').href = `/projects/${data.project_id}#issues`;
|
|
34
34
|
if (projectRes.status === 'fulfilled' && projectRes.value.ok) { const p = await projectRes.value.json(); document.getElementById('project-link').textContent = p.name; }
|
|
35
35
|
document.getElementById('issue-title-breadcrumb').textContent = `#${data.number} ${data.title}`;
|
|
36
|
-
document.title = `#${data.number} ${data.title} -
|
|
36
|
+
document.title = `#${data.number} ${data.title} - Agentopia`;
|
|
37
37
|
|
|
38
38
|
IssueRenderer.render(issueData, agentsData, document.getElementById('issue-page'), {
|
|
39
39
|
reload: loadIssue,
|
package/public/js/project.js
CHANGED
|
@@ -348,7 +348,7 @@ async function loadProject() {
|
|
|
348
348
|
document.getElementById('project-title').textContent = projectData.name;
|
|
349
349
|
document.getElementById('project-status').textContent = projectData.status;
|
|
350
350
|
document.getElementById('project-status').className = `status-badge status-${projectData.status}`;
|
|
351
|
-
document.title = `
|
|
351
|
+
document.title = `Agentopia - ${projectData.name}`;
|
|
352
352
|
renderProjectAccessSummary();
|
|
353
353
|
applyProjectManageState();
|
|
354
354
|
|
|
@@ -564,7 +564,7 @@ async function loadAgents() {
|
|
|
564
564
|
const key = a.id + ':' + (a.finished_at || '');
|
|
565
565
|
if (!window._notifiedErrors.has(key)) {
|
|
566
566
|
window._notifiedErrors.add(key);
|
|
567
|
-
new Notification('
|
|
567
|
+
new Notification('Agentopia: Agent Error', { body: `${a.name} failed. ${(errorLogs[a.id] || '').slice(0, 100)}`, tag: 'agentopia-error-' + a.id });
|
|
568
568
|
}
|
|
569
569
|
}
|
|
570
570
|
}
|
|
@@ -1537,8 +1537,8 @@ function switchTab(tab) {
|
|
|
1537
1537
|
}
|
|
1538
1538
|
|
|
1539
1539
|
function ensureProjectFilesPanel() {
|
|
1540
|
-
if (projectFilesPanel || !window.
|
|
1541
|
-
projectFilesPanel = window.
|
|
1540
|
+
if (projectFilesPanel || !window.AgentopiaFilesPanel) return;
|
|
1541
|
+
projectFilesPanel = window.AgentopiaFilesPanel.create({
|
|
1542
1542
|
publicApiName: 'ProjectFiles',
|
|
1543
1543
|
shellId: 'project-files-shell',
|
|
1544
1544
|
treeId: 'project-file-tree',
|
|
@@ -1888,79 +1888,92 @@ function renderStarAgentGraph(container, graphContext) {
|
|
|
1888
1888
|
|
|
1889
1889
|
function renderHierarchyAgentGraph(container, graphContext) {
|
|
1890
1890
|
const byId = getAgentMap();
|
|
1891
|
-
const controller = getControllerAgent();
|
|
1892
|
-
const levelMap = new Map();
|
|
1893
1891
|
const visited = new Set();
|
|
1894
|
-
const
|
|
1892
|
+
const childrenMap = new Map(); // parentId -> [agent]
|
|
1895
1893
|
|
|
1896
|
-
|
|
1897
|
-
if (!agent || visited.has(agent.id)) return;
|
|
1898
|
-
visited.add(agent.id);
|
|
1899
|
-
if (!levelMap.has(depth)) levelMap.set(depth, []);
|
|
1900
|
-
levelMap.get(depth).push(agent);
|
|
1901
|
-
|
|
1902
|
-
const children = agentsData.filter((candidate) => getGraphParentId(candidate) === agent.id);
|
|
1903
|
-
children.forEach((child) => {
|
|
1904
|
-
if (!child.parent_agent_id) {
|
|
1905
|
-
syntheticLinks.push(child.id);
|
|
1906
|
-
}
|
|
1907
|
-
walk(child, depth + 1);
|
|
1908
|
-
});
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
const roots = [];
|
|
1912
|
-
if (controller) {
|
|
1913
|
-
roots.push(controller);
|
|
1914
|
-
}
|
|
1894
|
+
// Build children map using only explicit parent_agent_id
|
|
1915
1895
|
agentsData.forEach((agent) => {
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1896
|
+
const pid = agent.parent_agent_id;
|
|
1897
|
+
if (pid && byId.has(pid)) {
|
|
1898
|
+
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
1899
|
+
childrenMap.get(pid).push(agent);
|
|
1920
1900
|
}
|
|
1921
1901
|
});
|
|
1922
1902
|
|
|
1903
|
+
// Identify roots: agents with no explicit parent or whose parent doesn't exist
|
|
1904
|
+
const roots = agentsData.filter((agent) => {
|
|
1905
|
+
const pid = agent.parent_agent_id;
|
|
1906
|
+
return !pid || !byId.has(pid);
|
|
1907
|
+
});
|
|
1908
|
+
|
|
1909
|
+
// Build subtree sizes for proper horizontal spacing
|
|
1910
|
+
const subtreeSize = new Map();
|
|
1911
|
+
function calcSize(agent) {
|
|
1912
|
+
if (subtreeSize.has(agent.id)) return subtreeSize.get(agent.id);
|
|
1913
|
+
const children = childrenMap.get(agent.id) || [];
|
|
1914
|
+
const size = children.length === 0 ? 1 : children.reduce((sum, c) => sum + calcSize(c), 0);
|
|
1915
|
+
subtreeSize.set(agent.id, size);
|
|
1916
|
+
return size;
|
|
1917
|
+
}
|
|
1918
|
+
roots.forEach((r) => calcSize(r));
|
|
1919
|
+
|
|
1920
|
+
// Walk tree to assign depth levels
|
|
1921
|
+
const depthMap = new Map();
|
|
1922
|
+
function walk(agent, depth) {
|
|
1923
|
+
if (!agent || visited.has(agent.id)) return;
|
|
1924
|
+
visited.add(agent.id);
|
|
1925
|
+
depthMap.set(agent.id, depth);
|
|
1926
|
+
(childrenMap.get(agent.id) || []).forEach((child) => walk(child, depth + 1));
|
|
1927
|
+
}
|
|
1923
1928
|
roots.forEach((root) => walk(root, 0));
|
|
1929
|
+
// Safety: visit any unvisited agents as roots
|
|
1924
1930
|
agentsData.forEach((agent) => {
|
|
1925
1931
|
if (!visited.has(agent.id)) walk(agent, 0);
|
|
1926
1932
|
});
|
|
1927
1933
|
|
|
1928
|
-
const
|
|
1929
|
-
.sort((a, b) => a[0] - b[0])
|
|
1930
|
-
.map(([, items]) => items);
|
|
1931
|
-
|
|
1934
|
+
const maxDepth = Math.max(0, ...Array.from(depthMap.values()));
|
|
1932
1935
|
const W = Math.min(Math.max(container.clientWidth || 760, 640), 960);
|
|
1933
1936
|
const levelGap = 112;
|
|
1934
1937
|
const topPadding = 56;
|
|
1935
|
-
const H = Math.max(280, topPadding +
|
|
1938
|
+
const H = Math.max(280, topPadding + maxDepth * levelGap + 96);
|
|
1936
1939
|
const nodeRadius = 28;
|
|
1937
1940
|
const positions = new Map();
|
|
1938
1941
|
|
|
1939
|
-
|
|
1940
|
-
|
|
1942
|
+
// Position nodes: center children under their parent using subtree sizes
|
|
1943
|
+
const totalLeaves = roots.reduce((sum, r) => sum + (subtreeSize.get(r.id) || 1), 0);
|
|
1944
|
+
const leafWidth = W / (totalLeaves + 1);
|
|
1945
|
+
|
|
1946
|
+
let leafCounter = 0;
|
|
1947
|
+
function positionSubtree(agent, depth) {
|
|
1948
|
+
const children = childrenMap.get(agent.id) || [];
|
|
1941
1949
|
const y = topPadding + depth * levelGap;
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1950
|
+
if (children.length === 0) {
|
|
1951
|
+
leafCounter++;
|
|
1952
|
+
positions.set(agent.id, { x: leafCounter * leafWidth, y });
|
|
1953
|
+
} else {
|
|
1954
|
+
children.forEach((child) => positionSubtree(child, depth + 1));
|
|
1955
|
+
// Center parent over its children
|
|
1956
|
+
const childPositions = children.map((c) => positions.get(c.id)).filter(Boolean);
|
|
1957
|
+
const minX = Math.min(...childPositions.map((p) => p.x));
|
|
1958
|
+
const maxX = Math.max(...childPositions.map((p) => p.x));
|
|
1959
|
+
positions.set(agent.id, { x: (minX + maxX) / 2, y });
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
roots.forEach((root) => positionSubtree(root, 0));
|
|
1949
1963
|
|
|
1950
1964
|
let svg = '<svg width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" style="display:block;margin:0 auto">';
|
|
1951
1965
|
|
|
1966
|
+
// Draw edges using only explicit parent_agent_id
|
|
1952
1967
|
agentsData.forEach((agent) => {
|
|
1953
|
-
const
|
|
1954
|
-
if (!
|
|
1955
|
-
const parentPos = positions.get(
|
|
1968
|
+
const pid = agent.parent_agent_id;
|
|
1969
|
+
if (!pid || !byId.has(pid)) return;
|
|
1970
|
+
const parentPos = positions.get(pid);
|
|
1956
1971
|
const childPos = positions.get(agent.id);
|
|
1957
1972
|
if (!parentPos || !childPos) return;
|
|
1958
1973
|
|
|
1959
1974
|
const dispatched = graphContext.dispatchedAgents.has(agent.id);
|
|
1960
|
-
const synthetic = !agent.parent_agent_id;
|
|
1961
1975
|
svg += '<line x1="' + parentPos.x + '" y1="' + (parentPos.y + nodeRadius) + '" x2="' + childPos.x + '" y2="' + (childPos.y - nodeRadius) + '" stroke="' + (dispatched ? 'var(--accent)' : 'var(--border)') + '" stroke-width="' + (dispatched ? 2.2 : 1.2) + '"' +
|
|
1962
|
-
|
|
1963
|
-
' opacity="' + (dispatched ? 0.95 : synthetic ? 0.45 : 0.7) + '"/>';
|
|
1976
|
+
' opacity="' + (dispatched ? 0.95 : 0.7) + '"/>';
|
|
1964
1977
|
|
|
1965
1978
|
if (dispatched) {
|
|
1966
1979
|
const mx = (parentPos.x + childPos.x) / 2;
|
|
@@ -1969,6 +1982,7 @@ function renderHierarchyAgentGraph(container, graphContext) {
|
|
|
1969
1982
|
}
|
|
1970
1983
|
});
|
|
1971
1984
|
|
|
1985
|
+
// Draw nodes
|
|
1972
1986
|
agentsData.forEach((agent) => {
|
|
1973
1987
|
const position = positions.get(agent.id);
|
|
1974
1988
|
if (!position) return;
|
|
@@ -1977,7 +1991,7 @@ function renderHierarchyAgentGraph(container, graphContext) {
|
|
|
1977
1991
|
? '<animate attributeName="r" values="' + nodeRadius + ';' + (nodeRadius + 4) + ';' + nodeRadius + '" dur="2s" repeatCount="indefinite"/>'
|
|
1978
1992
|
: '';
|
|
1979
1993
|
const assignedCount = (window._dashboardIssues || []).filter((issue) => issue.assigned_to === agent.id && ['open', 'in_progress', 'pending'].includes(issue.status)).length;
|
|
1980
|
-
const childCount =
|
|
1994
|
+
const childCount = (childrenMap.get(agent.id) || []).length;
|
|
1981
1995
|
const dispatched = graphContext.dispatchedAgents.has(agent.id);
|
|
1982
1996
|
const reason = graphContext.actionReasonByAgent.get(agent.id);
|
|
1983
1997
|
const statusLabel = agent.paused ? 'paused' : agent.status;
|
|
@@ -1993,13 +2007,14 @@ function renderHierarchyAgentGraph(container, graphContext) {
|
|
|
1993
2007
|
|
|
1994
2008
|
svg += '</svg>';
|
|
1995
2009
|
|
|
1996
|
-
const
|
|
1997
|
-
|
|
1998
|
-
|
|
2010
|
+
const hasOrphans = roots.some((r) => !r.is_controller);
|
|
2011
|
+
const note = hasOrphans
|
|
2012
|
+
? 'Top-level agents (no parent) are shown as independent roots.'
|
|
2013
|
+
: 'Links in the graph follow the configured parent-child hierarchy.';
|
|
1999
2014
|
|
|
2000
2015
|
return {
|
|
2001
2016
|
title: 'Agent Collaboration · Tree',
|
|
2002
|
-
note
|
|
2017
|
+
note,
|
|
2003
2018
|
svg,
|
|
2004
2019
|
};
|
|
2005
2020
|
}
|
|
@@ -2389,7 +2404,7 @@ loadProject();
|
|
|
2389
2404
|
loadAgents();
|
|
2390
2405
|
loadDashboard();
|
|
2391
2406
|
loadCostChart();
|
|
2392
|
-
window.addEventListener('
|
|
2407
|
+
window.addEventListener('agentopia:user-ready', () => { renderProjectAccessSummary(); });
|
|
2393
2408
|
|
|
2394
2409
|
// Slow fallback polling (WS handles real-time)
|
|
2395
2410
|
setInterval(loadAgents, 30000);
|
package/public/js/terminal.js
CHANGED
|
@@ -250,7 +250,7 @@ async function loadAgentInfo() {
|
|
|
250
250
|
document.getElementById('agent-started').textContent = formatLocalDateTime(agent.started_at);
|
|
251
251
|
document.getElementById('agent-status').textContent = agent.status;
|
|
252
252
|
document.getElementById('agent-status').className = `status-badge status-${agent.status}`;
|
|
253
|
-
document.title = `
|
|
253
|
+
document.title = `Agentopia - ${agent.name}`;
|
|
254
254
|
window.currentAgentState = agent;
|
|
255
255
|
if (window.AgentFiles && typeof window.AgentFiles.setAgent === 'function') {
|
|
256
256
|
window.AgentFiles.setAgent(agent);
|
package/public/project.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - Project</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
<link rel="stylesheet" href="/public/css/issues.css">
|
|
9
9
|
</head>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<div class="overlay" id="overlay" onclick="closeDrawer()"></div>
|
|
12
12
|
<div class="drawer" id="drawer">
|
|
13
13
|
<div class="drawer-header">
|
|
14
|
-
<h3><span style="color:var(--accent)">
|
|
14
|
+
<h3><span style="color:var(--accent)">Agentopia</span></h3>
|
|
15
15
|
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
|
16
16
|
</div>
|
|
17
17
|
<div class="drawer-content">
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
<button class="menu-btn" onclick="toggleDrawer()">
|
|
56
56
|
<span></span><span></span><span></span>
|
|
57
57
|
</button>
|
|
58
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
58
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
59
59
|
<div class="breadcrumb" style="margin-left:12px">
|
|
60
60
|
<a href="/">Projects</a> / <a id="project-name" href="#" onclick="switchTab('overview');return false" style="color:var(--link);text-decoration:none">Loading...</a><span id="breadcrumb-section"></span>
|
|
61
61
|
</div>
|
package/public/terminal.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agentopia - Terminal</title>
|
|
7
7
|
<link rel="stylesheet" href="/public/css/style.css">
|
|
8
8
|
<link rel="stylesheet" href="/public/vendor/xterm.css">
|
|
9
9
|
<style>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<button class="menu-btn" onclick="history.back()">
|
|
27
27
|
<span></span><span></span><span></span>
|
|
28
28
|
</button>
|
|
29
|
-
<h1><a href="/" style="color:var(--accent);text-decoration:none">
|
|
29
|
+
<h1><a href="/" style="color:var(--accent);text-decoration:none">Agentopia</a></h1>
|
|
30
30
|
<div class="breadcrumb" style="margin-left:12px">
|
|
31
31
|
<a href="/">Projects</a> / <a id="project-link" href="#">Project</a> / <a id="agent-link" href="#">Agent</a> / <span>Terminal</span>
|
|
32
32
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const Database = require('better-sqlite3');
|
|
2
2
|
const { v4: uuidv4 } = require('uuid');
|
|
3
3
|
|
|
4
|
-
const db = new Database('/misc/projdata11/info_fil/zhfu/lin/argus/data/
|
|
4
|
+
const db = new Database('/misc/projdata11/info_fil/zhfu/lin/argus/data/agentopia.db');
|
|
5
5
|
|
|
6
6
|
const AGENT_ID = 'db9e98bf-91b1-4bdd-97ea-ca56cd3c9f48';
|
|
7
7
|
const PROJECT_ID = 'ebf157ab-5cc9-49d2-9ff2-508652b7632c';
|