@songsid/agend 2.0.11-beta.29 → 2.0.11-beta.30
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/ui/settings.html +48 -31
- package/package.json +1 -1
package/dist/ui/settings.html
CHANGED
|
@@ -22,9 +22,15 @@
|
|
|
22
22
|
.sec-head .grow { flex: 1; }
|
|
23
23
|
.card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
|
|
24
24
|
.card.empty { padding: 16px; color: var(--muted); }
|
|
25
|
-
.item { padding:
|
|
25
|
+
.item { padding: 9px 16px; border-bottom: 1px solid var(--border); }
|
|
26
26
|
.item:last-child { border-bottom: none; }
|
|
27
|
-
.item-row { display: flex; align-items: center; gap: 10px; }
|
|
27
|
+
.item-row { display: flex; align-items: center; gap: 10px; min-height: 24px; }
|
|
28
|
+
.group-head { display: flex; align-items: center; gap: 8px; padding: 7px 16px; cursor: pointer; font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .3px; background: #f3f4f6; border-bottom: 1px solid var(--border); user-select: none; }
|
|
29
|
+
.group-head:hover { color: var(--fg); }
|
|
30
|
+
.group-head .caret { width: 12px; flex: 0 0 12px; font-size: 10px; }
|
|
31
|
+
.group-head .gcount { color: var(--muted); font-weight: 400; }
|
|
32
|
+
.item .del-btn { visibility: hidden; }
|
|
33
|
+
.item:hover .del-btn { visibility: visible; }
|
|
28
34
|
.dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; background: #9ca3af; }
|
|
29
35
|
.dot.running { background: var(--green); } .dot.crashed { background: var(--red); } .dot.stopped { background: #9ca3af; }
|
|
30
36
|
.name { font-weight: 600; }
|
|
@@ -144,7 +150,7 @@
|
|
|
144
150
|
}
|
|
145
151
|
|
|
146
152
|
// ── State ──
|
|
147
|
-
const state = { fleet: {}, classic: {}, live: {}, fleetUp: false, advFmt: "yaml", advEdit: false };
|
|
153
|
+
const state = { fleet: {}, classic: {}, live: {}, fleetUp: false, advFmt: "yaml", advEdit: false, collapsedGroups: new Set() };
|
|
148
154
|
const channels = () => state.fleet.channels || (state.fleet.channel ? [state.fleet.channel] : []);
|
|
149
155
|
const channelIds = () => channels().map(c => c.id || c.type).filter(Boolean);
|
|
150
156
|
const chLabel = (i) => i === 0 ? "primary" : "persona";
|
|
@@ -174,42 +180,52 @@
|
|
|
174
180
|
const shortName = (name, inst) => (inst && inst.display_name) || name.replace(/-t\d+$/, "");
|
|
175
181
|
const STATUS_TEXT = { running: "🟢 Running", crashed: "🔴 Crashed", stopped: "⚪ Stopped" };
|
|
176
182
|
const STATUS_ORDER = { running: 0, crashed: 1, stopped: 2 };
|
|
183
|
+
const groupOf = (inst) => (inst.tags && inst.tags[0]) || "Other";
|
|
184
|
+
function compactRow(name, inst) {
|
|
185
|
+
const st = state.live[name]?.status || "stopped";
|
|
186
|
+
const running = st === "running";
|
|
187
|
+
const short = shortName(name, inst);
|
|
188
|
+
const chTag = agentChannelLabel(inst);
|
|
189
|
+
const item = el("div", { class: "item" });
|
|
190
|
+
// Single fixed-height line: dot + short name + backend + channel tag + actions.
|
|
191
|
+
// Full ID lives in the tooltip and the Edit form; working dir only in Edit.
|
|
192
|
+
item.append(el("div", { class: "item-row" },
|
|
193
|
+
el("span", { class: "dot " + st, title: STATUS_TEXT[st] || st }),
|
|
194
|
+
el("span", { class: "name", title: name }, short),
|
|
195
|
+
el("span", { class: "sub", style: "margin:0" }, inst.backend || state.fleet.defaults?.backend || "claude-code"),
|
|
196
|
+
chTag ? el("span", { class: "tag" + (chTag.includes("persona") ? " persona" : chTag.includes("telegram") ? " tg" : "") }, chTag) : null,
|
|
197
|
+
el("span", { class: "spacer" }),
|
|
198
|
+
el("button", { class: "sm ghost", onclick: () => { editing = editing === name ? null : name; renderAgents(); } }, editing === name ? "Close" : "Edit"),
|
|
199
|
+
el("button", { class: "sm", onclick: () => toggleAgent(name, running) }, running ? "Stop" : "Start"),
|
|
200
|
+
el("button", { class: "sm danger del-btn", title: "Delete", onclick: () => delAgent(name) }, "🗑️"),
|
|
201
|
+
));
|
|
202
|
+
if (editing === name) item.append(agentEditForm(name, inst));
|
|
203
|
+
return item;
|
|
204
|
+
}
|
|
177
205
|
function renderAgents() {
|
|
178
206
|
const host = $("agents"); host.innerHTML = "";
|
|
179
207
|
const insts = state.fleet.instances || {};
|
|
208
|
+
if (!Object.keys(insts).length) { host.className = "card empty"; host.textContent = "No agents yet — click + New."; return; }
|
|
180
209
|
const filter = ($("agentSearch")?.value || "").trim().toLowerCase();
|
|
181
210
|
let names = Object.keys(insts);
|
|
182
211
|
if (filter) names = names.filter(n => n.toLowerCase().includes(filter) || shortName(n, insts[n]).toLowerCase().includes(filter));
|
|
183
|
-
// Group by status: Running first, then Crashed, then Stopped; name within.
|
|
184
|
-
names.sort((a, b) => {
|
|
185
|
-
const sa = STATUS_ORDER[state.live[a]?.status || "stopped"], sb = STATUS_ORDER[state.live[b]?.status || "stopped"];
|
|
186
|
-
return sa !== sb ? sa - sb : a.localeCompare(b);
|
|
187
|
-
});
|
|
188
|
-
if (!Object.keys(insts).length) { host.className = "card empty"; host.textContent = "No agents yet — click + New."; return; }
|
|
189
212
|
if (!names.length) { host.className = "card empty"; host.textContent = "No agents match \"" + filter + "\"."; return; }
|
|
190
213
|
host.className = "card";
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
el("button", { class: "sm ghost", onclick: () => { editing = editing === name ? null : name; renderAgents(); } }, editing === name ? "Close" : "Edit"),
|
|
207
|
-
el("button", { class: "sm", onclick: () => toggleAgent(name, running) }, running ? "Stop" : "Start"),
|
|
208
|
-
el("button", { class: "sm danger", onclick: () => delAgent(name) }, "🗑️"),
|
|
209
|
-
));
|
|
210
|
-
if (inst.working_directory) item.append(el("div", { class: "sub" }, inst.working_directory));
|
|
211
|
-
if (editing === name) item.append(agentEditForm(name, inst));
|
|
212
|
-
host.append(item);
|
|
214
|
+
// Group by first tag; "Other" sorts last. Within a group: Running → Crashed
|
|
215
|
+
// → Stopped, then name.
|
|
216
|
+
const groups = {};
|
|
217
|
+
for (const n of names) (groups[groupOf(insts[n])] ??= []).push(n);
|
|
218
|
+
const gnames = Object.keys(groups).sort((a, b) => a === "Other" ? 1 : b === "Other" ? -1 : a.localeCompare(b));
|
|
219
|
+
for (const g of gnames) {
|
|
220
|
+
const members = groups[g].sort((a, b) => {
|
|
221
|
+
const sa = STATUS_ORDER[state.live[a]?.status || "stopped"], sb = STATUS_ORDER[state.live[b]?.status || "stopped"];
|
|
222
|
+
return sa !== sb ? sa - sb : a.localeCompare(b);
|
|
223
|
+
});
|
|
224
|
+
const collapsed = state.collapsedGroups.has(g) && !filter; // searching expands all
|
|
225
|
+
host.append(el("div", { class: "group-head", onclick: () => { state.collapsedGroups.has(g) ? state.collapsedGroups.delete(g) : state.collapsedGroups.add(g); renderAgents(); } },
|
|
226
|
+
el("span", { class: "caret" }, collapsed ? "▶" : "▼"), el("span", {}, g), el("span", { class: "gcount" }, `(${members.length})`)));
|
|
227
|
+
if (collapsed) continue;
|
|
228
|
+
for (const name of members) host.append(compactRow(name, insts[name]));
|
|
213
229
|
}
|
|
214
230
|
}
|
|
215
231
|
function agentEditForm(name, inst) {
|
|
@@ -224,6 +240,7 @@
|
|
|
224
240
|
const fGeneral = el("input", { type: "checkbox" }); fGeneral.checked = !!inst.general_topic;
|
|
225
241
|
const msg = el("span", { class: "msg" });
|
|
226
242
|
box.append(
|
|
243
|
+
el("div", { class: "sub", style: "margin:0 0 8px" }, "ID: " + name),
|
|
227
244
|
el("div", { class: "grid2" }, el("div", {}, el("label", {}, "Backend"), fBackend), el("div", {}, el("label", {}, "Model"), fModel)),
|
|
228
245
|
el("label", {}, "Working directory"), fWd,
|
|
229
246
|
el("div", { class: "grid2" }, el("div", {}, el("label", {}, "Channel binding"), fChan), el("div", {}, el("label", {}, "Description"), fDesc)),
|