@songsid/agend 2.1.0-beta.27 → 2.1.0-beta.29
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/classic-channel-manager.d.ts +4 -0
- package/dist/classic-channel-manager.js +15 -0
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +15 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +12 -0
- package/dist/daemon.js +40 -20
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +21 -2
- package/dist/fleet-manager.js +132 -10
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +1 -0
- package/dist/instance-lifecycle.js +27 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/pause-marker.d.ts +5 -0
- package/dist/pause-marker.js +36 -0
- package/dist/pause-marker.js.map +1 -0
- package/dist/settings-api.d.ts +1 -0
- package/dist/settings-api.js +12 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/ui/settings.html +98 -21
- package/package.json +1 -1
package/dist/ui/settings.html
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
.item .del-btn { visibility: hidden; }
|
|
33
33
|
.item:hover .del-btn { visibility: visible; }
|
|
34
34
|
.dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; background: #9ca3af; }
|
|
35
|
-
.dot.running { background: var(--green); } .dot.paused { background:#f59e0b; } .dot.crashed { background: var(--red); } .dot.stopped { background: #9ca3af; }
|
|
35
|
+
.dot.running, .dot.idle { background: var(--green); } .dot.working { background:var(--accent); } .dot.paused { background:#f59e0b; } .dot.crashed, .dot.stuck { background: var(--red); } .dot.stopped { background: #9ca3af; }
|
|
36
36
|
.name { font-weight: 600; }
|
|
37
37
|
.tag { font-size: 12px; color: var(--muted); background: #eef2ff; color: #3730a3; padding: 1px 7px; border-radius: 10px; }
|
|
38
38
|
.tag.persona { background: #fdf2f8; color: #9d174d; }
|
|
@@ -306,7 +306,7 @@
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
// ── State ──
|
|
309
|
-
const state = { fleet: {}, classic: {}, classicStatus: {}, live: {}, fleetUp: false, advFmt: "yaml", advEdit: false, collapsedGroups: new Set(), version: "", newAgentOpen: false, newBotOpen: false, pending: new Map() };
|
|
309
|
+
const state = { fleet: {}, classic: {}, classicStatus: {}, classicLive: {}, live: {}, fleetUp: false, advFmt: "yaml", advEdit: false, collapsedGroups: new Set(), version: "", newAgentOpen: false, newBotOpen: false, pending: new Map() };
|
|
310
310
|
const channels = () => state.fleet.channels || (state.fleet.channel ? [state.fleet.channel] : []);
|
|
311
311
|
const channelIds = () => channels().map(c => c.id || c.type).filter(Boolean);
|
|
312
312
|
const chLabel = (i) => i === 0 ? "primary" : "persona";
|
|
@@ -383,6 +383,7 @@
|
|
|
383
383
|
// Display name: profile display_name → else strip the -t<topicId> suffix.
|
|
384
384
|
const shortName = (name, inst) => (inst && inst.display_name) || name.replace(/-t\d+$/, "");
|
|
385
385
|
const STATUS_TEXT = { running: "🟢 Running", paused: "⏸ Paused", crashed: "🔴 Crashed", stopped: "⚪ Stopped" };
|
|
386
|
+
const EXECUTION_TEXT = { idle: "🟢 Idle", working: "🔵 Working", stuck: "🔴 Stuck", paused: "⏸ Paused", crashed: "🔴 Crashed", stopped: "⚪ Stopped", running: "🟢 Running" };
|
|
386
387
|
const STATUS_ORDER = { running: 0, paused: 1, crashed: 2, stopped: 3 };
|
|
387
388
|
const groupOf = (inst) => (inst.tags && inst.tags[0]) || "Other";
|
|
388
389
|
function compactRow(name, inst) {
|
|
@@ -628,6 +629,78 @@
|
|
|
628
629
|
}
|
|
629
630
|
|
|
630
631
|
// ── ClassicBot Channels ──
|
|
632
|
+
let editingClassic = null;
|
|
633
|
+
function classicRuntime(instanceName) {
|
|
634
|
+
const live = state.classicLive[instanceName] || {};
|
|
635
|
+
const status = live.status || state.classicStatus[instanceName] || "stopped";
|
|
636
|
+
const execution = status === "paused" ? "paused" : (live.state || status);
|
|
637
|
+
return { status, execution };
|
|
638
|
+
}
|
|
639
|
+
function classicEditForm(c) {
|
|
640
|
+
const box = el("div", { class: "edit" });
|
|
641
|
+
const classicDefaults = state.classic?.defaults || {};
|
|
642
|
+
const fleetDefaults = state.fleet?.defaults || {};
|
|
643
|
+
const inheritedBackend = classicDefaults.backend || fleetDefaults.backend || "claude-code";
|
|
644
|
+
const inheritedModel = classicDefaults.model || fleetDefaults.model || "";
|
|
645
|
+
const inheritedAutoPause = classicDefaults.auto_pause_after ?? fleetDefaults.auto_pause_after ?? 0;
|
|
646
|
+
const runtime = classicRuntime(c.instanceName);
|
|
647
|
+
const fBackend = select(c.backend || inheritedBackend, BACKENDS.filter(value => value !== "gemini-cli"));
|
|
648
|
+
const fModel = el("input", { type: "text", value: c.model || "", placeholder: inheritedModel || "(inherit default)" });
|
|
649
|
+
const auto = overrideControl(c, "auto_pause_after", el("input", { type: "number", min: "0", step: "1", value: c.auto_pause_after ?? inheritedAutoPause, placeholder: "0 = disabled" }), inheritedAutoPause);
|
|
650
|
+
const fCollab = el("input", { type: "checkbox" }); fCollab.checked = !!c.collab;
|
|
651
|
+
const fContext = el("input", { type: "number", min: "0", step: "1", value: c.context_lines ?? classicDefaults.context_lines ?? 5 });
|
|
652
|
+
const autoFeedback = el("div", { class: "feedback" });
|
|
653
|
+
const contextFeedback = el("div", { class: "feedback" });
|
|
654
|
+
const saveBtn = el("button", { class: "primary sm" }, t("save"));
|
|
655
|
+
const validate = () => {
|
|
656
|
+
const autoValue = Number(auto.input.value);
|
|
657
|
+
const contextValue = Number(fContext.value);
|
|
658
|
+
const validAuto = setValidation(auto.input, autoFeedback, !auto.toggle.checked && (!Number.isFinite(autoValue) || autoValue < 0) ? "Must be 0 or greater" : "");
|
|
659
|
+
const validContext = setValidation(fContext, contextFeedback, !Number.isInteger(contextValue) || contextValue < 0 ? "Must be a non-negative integer" : "");
|
|
660
|
+
saveBtn.disabled = !(validAuto && validContext);
|
|
661
|
+
return !saveBtn.disabled;
|
|
662
|
+
};
|
|
663
|
+
for (const input of [fBackend, fModel, auto.input, auto.toggle, fCollab, fContext]) {
|
|
664
|
+
input.addEventListener("input", validate); input.addEventListener("change", validate);
|
|
665
|
+
}
|
|
666
|
+
saveBtn.onclick = () => {
|
|
667
|
+
if (!validate()) return;
|
|
668
|
+
const patch = {
|
|
669
|
+
backend: fBackend.value,
|
|
670
|
+
model: fModel.value.trim() || null,
|
|
671
|
+
auto_pause_after: auto.toggle.checked ? null : Number(auto.input.value),
|
|
672
|
+
collab: fCollab.checked,
|
|
673
|
+
context_lines: Number(fContext.value),
|
|
674
|
+
};
|
|
675
|
+
state.classic.channels[c.key] = { ...state.classic.channels[c.key], ...patch };
|
|
676
|
+
if (patch.model === null) delete state.classic.channels[c.key].model;
|
|
677
|
+
if (patch.auto_pause_after === null) delete state.classic.channels[c.key].auto_pause_after;
|
|
678
|
+
stageChange(`classic:${c.key}`, {
|
|
679
|
+
label: `Update ${c.name || c.instanceName}`,
|
|
680
|
+
impact: "instance",
|
|
681
|
+
apply: () => api(`/api/settings/classic/channels/${encodeURIComponent(c.key)}`, { method: "PATCH", body: JSON.stringify(patch) }),
|
|
682
|
+
});
|
|
683
|
+
editingClassic = null;
|
|
684
|
+
renderClassic();
|
|
685
|
+
};
|
|
686
|
+
box.append(
|
|
687
|
+
el("div", { class: "sub", style: "margin:0 0 8px" }, `ID: ${c.instanceName} · ${EXECUTION_TEXT[runtime.execution] || runtime.execution}`),
|
|
688
|
+
el("div", { class: "grid2" },
|
|
689
|
+
el("div", {}, el("label", {}, t("backend"), impact("instance")), fBackend),
|
|
690
|
+
el("div", {}, el("label", {}, t("model"), impact("instance")), fModel),
|
|
691
|
+
el("div", {}, el("label", {}, `${t("autoPause")} (${t("minutes")})`, impact("instance")), auto.row, autoFeedback),
|
|
692
|
+
el("div", {}, el("label", { style: "display:flex;align-items:center;gap:8px;cursor:pointer;margin-top:28px" }, fCollab, el("span", {}, "Collaboration mode"), impact("instance")))),
|
|
693
|
+
el("div", { class: "advanced-only" },
|
|
694
|
+
el("label", {}, "Context lines", impact("instance")), fContext, contextFeedback),
|
|
695
|
+
el("div", { class: "actions" },
|
|
696
|
+
saveBtn,
|
|
697
|
+
runtime.status === "running" ? el("button", { class: "sm", onclick: () => pauseWakeAgent(c.instanceName, "pause") }, t("pause")) : null,
|
|
698
|
+
runtime.status === "paused" ? el("button", { class: "sm", onclick: () => pauseWakeAgent(c.instanceName, "wake") }, t("wake")) : null,
|
|
699
|
+
el("button", { class: "sm ghost", onclick: () => { editingClassic = null; renderClassic(); } }, t("cancel"))),
|
|
700
|
+
);
|
|
701
|
+
validate();
|
|
702
|
+
return box;
|
|
703
|
+
}
|
|
631
704
|
function renderClassic() {
|
|
632
705
|
const host = $("classicList"); if (!host) return; host.innerHTML = "";
|
|
633
706
|
const chans = Object.entries(state.classic?.channels || {}).map(([key, channel]) => ({ key, ...channel }));
|
|
@@ -638,29 +711,29 @@
|
|
|
638
711
|
if (!list.length) { host.className = "card empty"; host.textContent = "—"; return; }
|
|
639
712
|
host.className = "card";
|
|
640
713
|
list.sort((a, b) => {
|
|
641
|
-
const sa = STATUS_ORDER[
|
|
714
|
+
const sa = STATUS_ORDER[classicRuntime(a.instanceName).status] ?? 9;
|
|
715
|
+
const sb = STATUS_ORDER[classicRuntime(b.instanceName).status] ?? 9;
|
|
642
716
|
return sa !== sb ? sa - sb : String(a.name || "").localeCompare(String(b.name || ""));
|
|
643
717
|
});
|
|
644
718
|
for (const c of list) {
|
|
645
|
-
const
|
|
719
|
+
const runtime = classicRuntime(c.instanceName);
|
|
720
|
+
const st = runtime.status;
|
|
646
721
|
const adapter = c.adapterId || "discord";
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
const value = backend.value;
|
|
651
|
-
state.classic.channels[c.key].backend = value;
|
|
652
|
-
stageChange(`classic:${c.key}`, {
|
|
653
|
-
label: `Change ${c.name || c.instanceName} backend`, impact: "instance",
|
|
654
|
-
apply: () => api(`/api/settings/classic/channels/${encodeURIComponent(c.key)}`, { method: "PATCH", body: JSON.stringify({ backend: value }) }),
|
|
655
|
-
});
|
|
656
|
-
};
|
|
657
|
-
host.append(el("div", { class: "item" }, el("div", { class: "item-row" },
|
|
658
|
-
el("span", { class: "dot " + st, title: STATUS_TEXT[st] || st }),
|
|
722
|
+
const item = el("div", { class: "item" });
|
|
723
|
+
item.append(el("div", { class: "item-row" },
|
|
724
|
+
el("span", { class: "dot " + runtime.execution, title: EXECUTION_TEXT[runtime.execution] || runtime.execution }),
|
|
659
725
|
el("span", { class: "name", title: c.instanceName || "" }, c.name || c.instanceName || "?"),
|
|
660
|
-
backend,
|
|
726
|
+
el("span", { class: "sub", style: "margin:0" }, c.backend || state.classic?.defaults?.backend || state.fleet?.defaults?.backend || "claude-code"),
|
|
661
727
|
el("span", { class: "tag" + (adapter !== "discord" ? " persona" : "") }, adapter),
|
|
662
728
|
c.collab ? el("span", { class: "tag", style: "background:#ecfdf5;color:#065f46" }, "collab") : null,
|
|
663
|
-
|
|
729
|
+
el("span", { class: "spacer" }),
|
|
730
|
+
el("span", { class: "tag", title: STATUS_TEXT[st] || st }, EXECUTION_TEXT[runtime.execution] || runtime.execution),
|
|
731
|
+
el("button", { class: "sm ghost", onclick: () => { editingClassic = editingClassic === c.key ? null : c.key; renderClassic(); } }, editingClassic === c.key ? t("close") : t("edit")),
|
|
732
|
+
st === "running" ? el("button", { class: "sm", onclick: () => pauseWakeAgent(c.instanceName, "pause") }, t("pause")) : null,
|
|
733
|
+
st === "paused" ? el("button", { class: "sm", onclick: () => pauseWakeAgent(c.instanceName, "wake") }, t("wake")) : null,
|
|
734
|
+
));
|
|
735
|
+
if (editingClassic === c.key) item.append(classicEditForm(c));
|
|
736
|
+
host.append(item);
|
|
664
737
|
}
|
|
665
738
|
}
|
|
666
739
|
|
|
@@ -872,9 +945,13 @@
|
|
|
872
945
|
async function reloadLive() {
|
|
873
946
|
const f = await api("/api/fleet");
|
|
874
947
|
state.fleetUp = f.ok;
|
|
875
|
-
state.live = {};
|
|
876
|
-
|
|
877
|
-
|
|
948
|
+
state.live = {}; state.classicLive = {};
|
|
949
|
+
if (f.ok && f.body?.instances) for (const i of f.body.instances) {
|
|
950
|
+
state.live[i.name] = { status: i.status, state: i.state };
|
|
951
|
+
if (i.classic) state.classicLive[i.name] = { status: i.status, state: i.state };
|
|
952
|
+
}
|
|
953
|
+
// /api/fleet carries live tri-state for Classic instances. Profiles remain
|
|
954
|
+
// a fallback roster for a daemon that has not yet appeared in live status.
|
|
878
955
|
const pr = await api("/api/profiles");
|
|
879
956
|
state.classicStatus = {}; if (pr.ok && Array.isArray(pr.body)) for (const r of pr.body) state.classicStatus[r.instance_name] = r.status;
|
|
880
957
|
if (f.ok && f.body?.version) { state.version = f.body.version; $("verBadge").textContent = "v" + state.version; }
|