@songsid/agend 2.1.0-beta.23 → 2.1.0-beta.4
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/README.md +0 -1
- package/README.zh-TW.md +1 -2
- package/dist/access-path.js +3 -3
- package/dist/access-path.js.map +1 -1
- package/dist/agent-endpoint.d.ts +0 -8
- package/dist/agent-endpoint.js +8 -36
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/backend/antigravity.js +2 -3
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/factory.js +1 -5
- package/dist/backend/factory.js.map +1 -1
- package/dist/backend/kiro.js +2 -3
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +2 -12
- package/dist/backend/types.js +0 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +0 -20
- package/dist/channel/adapters/discord.js +11 -69
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +1 -4
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +1 -6
- package/dist/classic-channel-manager.js +3 -26
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +4 -48
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +1 -50
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -3
- package/dist/config.js +1 -13
- package/dist/config.js.map +1 -1
- package/dist/context-guardian.d.ts +0 -2
- package/dist/context-guardian.js +2 -10
- package/dist/context-guardian.js.map +1 -1
- package/dist/daemon-entry.js +1 -2
- package/dist/daemon-entry.js.map +1 -1
- package/dist/daemon.d.ts +1 -25
- package/dist/daemon.js +30 -156
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-context.d.ts +0 -1
- package/dist/fleet-manager.d.ts +5 -30
- package/dist/fleet-manager.js +106 -312
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -1
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +0 -1
- package/dist/instance-lifecycle.d.ts +1 -2
- package/dist/instance-lifecycle.js +4 -15
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +0 -2
- package/dist/locale.js.map +1 -1
- package/dist/logger.d.ts +0 -6
- package/dist/logger.js +9 -28
- package/dist/logger.js.map +1 -1
- package/dist/outbound-handlers.d.ts +0 -3
- package/dist/outbound-handlers.js +0 -25
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -2
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/settings-api.d.ts +2 -17
- package/dist/settings-api.js +8 -105
- package/dist/settings-api.js.map +1 -1
- package/dist/setup-wizard.js +0 -8
- package/dist/setup-wizard.js.map +1 -1
- package/dist/statusline-watcher.d.ts +1 -1
- package/dist/statusline-watcher.js +2 -3
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/tmux-manager.d.ts +1 -1
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.d.ts +1 -14
- package/dist/topic-commands.js +23 -89
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.js +0 -2
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/types.d.ts +1 -16
- package/dist/ui/dashboard.html +2 -2
- package/dist/ui/settings.html +40 -251
- package/dist/web-api.d.ts +0 -1
- package/dist/web-api.js +15 -24
- package/dist/web-api.js.map +1 -1
- package/package.json +1 -2
- package/dist/backend/grok.d.ts +0 -51
- package/dist/backend/grok.js +0 -280
- package/dist/backend/grok.js.map +0 -1
package/dist/ui/settings.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
9
|
:root {
|
|
10
10
|
--bg:#ffffff; --card:#f9fafb; --border:#e5e7eb; --fg:#111827; --muted:#6b7280;
|
|
11
|
-
--accent:#2563eb; --accent-hover:#1d4ed8; --green:#059669; --red:#dc2626;
|
|
11
|
+
--accent:#2563eb; --accent-hover:#1d4ed8; --green:#059669; --red:#dc2626;
|
|
12
12
|
--radius:8px; --radius-sm:6px;
|
|
13
13
|
}
|
|
14
14
|
body { background: var(--bg); color: var(--fg); font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: 14px; line-height: 1.5; padding-bottom: 60px; }
|
|
@@ -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.
|
|
35
|
+
.dot.running { background: var(--green); } .dot.crashed { 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; }
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
button.danger:hover { background: #fef2f2; }
|
|
50
50
|
button.sm { padding: 4px 9px; font-size: 12px; }
|
|
51
51
|
label { display: block; font-size: 12px; font-weight: 500; color: var(--muted); margin: 10px 0 4px; }
|
|
52
|
-
input[type=text],
|
|
52
|
+
input[type=text], select { width: 100%; font-family: inherit; font-size: 13px; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; color: var(--fg); }
|
|
53
53
|
input:focus, select:focus { outline: 2px solid #bfdbfe; border-color: var(--accent); }
|
|
54
54
|
.edit { padding: 14px 16px; background: #fff; border-top: 1px solid var(--border); }
|
|
55
55
|
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
@@ -63,19 +63,6 @@
|
|
|
63
63
|
.msg { font-size: 12px; margin-left: 4px; }
|
|
64
64
|
.msg .e { color: var(--red); } .msg .w { color: #b45309; } .msg .s { color: var(--green); }
|
|
65
65
|
.hint { font-size: 12px; color: var(--muted); margin-top: 6px; }
|
|
66
|
-
.impact { display:inline-block; font-size:11px; color:var(--muted); margin-left:6px; font-weight:400; }
|
|
67
|
-
.feedback { min-height:17px; font-size:12px; margin-top:3px; }
|
|
68
|
-
.feedback.error { color:var(--red); } .feedback.warning { color:var(--yellow); }
|
|
69
|
-
input.invalid, select.invalid { border-color:var(--red); background:#fef2f2; }
|
|
70
|
-
button:disabled { opacity:.5; cursor:not-allowed; }
|
|
71
|
-
.settings-section { border-bottom:1px solid var(--border); background:#fff; }
|
|
72
|
-
.settings-section:last-child { border-bottom:none; }
|
|
73
|
-
.settings-section > summary { cursor:pointer; list-style:none; padding:12px 16px; font-weight:650; background:#f9fafb; }
|
|
74
|
-
.settings-section > summary::-webkit-details-marker { display:none; }
|
|
75
|
-
.settings-section > summary::before { content:"▶"; display:inline-block; width:18px; color:var(--muted); font-size:10px; }
|
|
76
|
-
.settings-section[open] > summary::before { content:"▼"; }
|
|
77
|
-
.section-body { padding:0 0 2px; }
|
|
78
|
-
.inherit-row { display:flex; gap:8px; align-items:center; margin-top:6px; color:var(--muted); font-size:12px; }
|
|
79
66
|
.adv-body { display: none; padding: 14px 16px; }
|
|
80
67
|
.adv-body.open { display: block; }
|
|
81
68
|
.toolbar { display: flex; gap: 6px; align-items: center; margin-bottom: 8px; flex-wrap: wrap; }
|
|
@@ -97,16 +84,6 @@
|
|
|
97
84
|
.help-panel li { font-size: 13px; margin: 3px 0; }
|
|
98
85
|
.help-panel .close { position: absolute; top: 14px; right: 16px; cursor: pointer; color: var(--muted); font-size: 22px; line-height: 1; background: none; border: none; }
|
|
99
86
|
.help-panel .tip { margin-top: 16px; padding: 10px 12px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 13px; }
|
|
100
|
-
@media (max-width: 640px) {
|
|
101
|
-
header { padding:10px 12px; flex-wrap:wrap; } header h1 { font-size:16px; }
|
|
102
|
-
main { padding:12px 10px; } section { margin-bottom:18px; }
|
|
103
|
-
.grid2 { grid-template-columns:1fr; gap:0; }
|
|
104
|
-
.item { padding:9px 10px; } .item-row { flex-wrap:wrap; }
|
|
105
|
-
.item-row .spacer { flex-basis:100%; height:0; }
|
|
106
|
-
.sub { margin-left:0; } .field { padding:10px 12px; }
|
|
107
|
-
#agentSearch { width:130px !important; margin-right:0 !important; }
|
|
108
|
-
button { min-height:36px; } button.sm { min-height:32px; }
|
|
109
|
-
}
|
|
110
87
|
</style>
|
|
111
88
|
</head>
|
|
112
89
|
<body>
|
|
@@ -164,7 +141,7 @@
|
|
|
164
141
|
const $ = (id) => document.getElementById(id);
|
|
165
142
|
const el = (tag, attrs = {}, ...kids) => { const e = document.createElement(tag); for (const k in attrs) { if (k === "class") e.className = attrs[k]; else if (k === "html") e.innerHTML = attrs[k]; else if (k.startsWith("on")) e.addEventListener(k.slice(2), attrs[k]); else e.setAttribute(k, attrs[k]); } for (const c of kids) if (c != null) e.append(c); return e; };
|
|
166
143
|
const esc = (s) => String(s).replace(/[&<>]/g, c => ({ "&":"&","<":"<",">":">" }[c]));
|
|
167
|
-
const BACKENDS = ["claude-code", "kiro-cli", "codex", "opencode", "gemini-cli", "antigravity"
|
|
144
|
+
const BACKENDS = ["claude-code", "kiro-cli", "codex", "opencode", "gemini-cli", "antigravity"];
|
|
168
145
|
|
|
169
146
|
// ── i18n ──
|
|
170
147
|
const I18N = {
|
|
@@ -175,8 +152,6 @@
|
|
|
175
152
|
edit: "Edit", close: "Close", save: "Save", cancel: "Cancel", create: "Create", start: "Start", stop: "Stop",
|
|
176
153
|
backend: "Backend", model: "Model", workingDir: "Working directory", channelBinding: "Channel binding",
|
|
177
154
|
description: "Description", systemPrompt: "System prompt", tags: "Tags", generalTopicField: "General topic (fleet dispatcher)",
|
|
178
|
-
runtimeResources: "Runtime & Resources", autoPause: "Auto-pause after", minutes: "minutes", inheritDefault: "Inherit from defaults",
|
|
179
|
-
detection: "Detection", startup: "Startup", backendSection: "Backend", advancedSection: "Advanced & Access", hangEnabled: "Hang detector enabled", hangTimeout: "Stuck timeout", agentMode: "Agent mode", toolSet: "Tool set", logLevel: "Log level", concurrency: "Startup concurrency", staggerDelay: "Stagger delay", lightweight: "Lightweight mode", modelFailover: "Fallback model", displayName: "Display name", pause: "Pause", wake: "Wake", accessMode: "Access mode", affected: "Affected instances",
|
|
180
155
|
language: "Language (bot replies)", defaultBackend: "Default backend", defaultModel: "Default model", allowedUsers: "Allowed users (primary bot)",
|
|
181
156
|
classicAdmins: "ClassicBot admins", allowedGuilds: "Allowed guilds", type: "Type", adapterId: "Adapter id",
|
|
182
157
|
tokenEnv: "Bot token env var", groupId: "Group / guild id", nameField: "Name",
|
|
@@ -193,8 +168,6 @@
|
|
|
193
168
|
edit: "編輯", close: "關閉", save: "儲存", cancel: "取消", create: "建立", start: "啟動", stop: "停止",
|
|
194
169
|
backend: "後端", model: "模型", workingDir: "工作目錄", channelBinding: "頻道綁定",
|
|
195
170
|
description: "描述", systemPrompt: "System prompt", tags: "標籤", generalTopicField: "General topic(fleet 分派器)",
|
|
196
|
-
runtimeResources: "執行環境與資源", autoPause: "閒置後自動暫停", minutes: "分鐘", inheritDefault: "沿用全域預設值",
|
|
197
|
-
detection: "偵測", startup: "啟動", backendSection: "後端", advancedSection: "進階與存取", hangEnabled: "啟用卡住偵測", hangTimeout: "卡住逾時", agentMode: "Agent 模式", toolSet: "工具集", logLevel: "Log 等級", concurrency: "啟動併發數", staggerDelay: "錯開延遲", lightweight: "輕量模式", modelFailover: "備援模型", displayName: "顯示名稱", pause: "暫停", wake: "喚醒", accessMode: "存取模式", affected: "受影響 instances",
|
|
198
171
|
language: "語言(bot 回覆)", defaultBackend: "預設後端", defaultModel: "預設模型", allowedUsers: "允許使用者(主 bot)",
|
|
199
172
|
classicAdmins: "ClassicBot 管理員", allowedGuilds: "允許的伺服器", type: "類型", adapterId: "Adapter id",
|
|
200
173
|
tokenEnv: "Bot token 環境變數", groupId: "群組 / guild id", nameField: "名稱",
|
|
@@ -278,14 +251,6 @@
|
|
|
278
251
|
else if (!html) html = `<span class="e">✗ ${esc((b && b.error) || ("HTTP " + res.status))}</span>`;
|
|
279
252
|
elm.innerHTML = html;
|
|
280
253
|
}
|
|
281
|
-
function showBanner(text, error = false) {
|
|
282
|
-
const b = $("banner");
|
|
283
|
-
b.style.display = "block";
|
|
284
|
-
b.style.background = error ? "#fef2f2" : "#ecfdf5";
|
|
285
|
-
b.style.color = error ? "var(--red)" : "var(--green)";
|
|
286
|
-
b.textContent = text;
|
|
287
|
-
setTimeout(() => { b.style.display = "none"; }, 6000);
|
|
288
|
-
}
|
|
289
254
|
|
|
290
255
|
// ── State ──
|
|
291
256
|
const state = { fleet: {}, classic: {}, classicStatus: {}, live: {}, fleetUp: false, advFmt: "yaml", advEdit: false, collapsedGroups: new Set(), version: "", newAgentOpen: false, newBotOpen: false };
|
|
@@ -303,26 +268,7 @@
|
|
|
303
268
|
box.append(chips, el("div", { class: "chip-add" }, inp, el("button", { class: "sm", onclick: add }, "+ Add")));
|
|
304
269
|
redraw(); return box;
|
|
305
270
|
}
|
|
306
|
-
function select(value, options) { const s = el("select"); for (const o of options) { const
|
|
307
|
-
const impact = (kind) => el("span", { class: "impact" }, kind === "now" ? "⚡ immediate" : kind === "fleet" ? "🔄🔄 restart fleet" : "🔄 restart instance");
|
|
308
|
-
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj || {}, key);
|
|
309
|
-
function overrideControl(inst, key, input, inheritedValue, impactKind = "instance") {
|
|
310
|
-
const inherited = !hasOwn(inst, key);
|
|
311
|
-
const toggle = el("input", { type: "checkbox" }); toggle.checked = inherited;
|
|
312
|
-
input.disabled = inherited;
|
|
313
|
-
if (inherited && inheritedValue !== undefined) {
|
|
314
|
-
if (input.type === "checkbox") input.checked = !!inheritedValue;
|
|
315
|
-
else input.value = inheritedValue;
|
|
316
|
-
}
|
|
317
|
-
toggle.onchange = () => { input.disabled = toggle.checked; };
|
|
318
|
-
return { input, toggle, row: el("div", {}, input, el("label", { class: "inherit-row" }, toggle, el("span", {}, t("inheritDefault")), impact(impactKind))) };
|
|
319
|
-
}
|
|
320
|
-
function setValidation(input, feedback, error, warning) {
|
|
321
|
-
input.classList.toggle("invalid", !!error);
|
|
322
|
-
feedback.className = "feedback" + (error ? " error" : warning ? " warning" : "");
|
|
323
|
-
feedback.textContent = error ? `✗ ${error}` : warning ? `⚠ ${warning}` : "";
|
|
324
|
-
return !error;
|
|
325
|
-
}
|
|
271
|
+
function select(value, options) { const s = el("select"); for (const o of options) { const opt = el("option", {}, o); opt.value = o; if (o === value) opt.selected = true; s.append(opt); } return s; }
|
|
326
272
|
|
|
327
273
|
// ── My Agents ──
|
|
328
274
|
let editing = null;
|
|
@@ -335,13 +281,12 @@
|
|
|
335
281
|
}
|
|
336
282
|
// Display name: profile display_name → else strip the -t<topicId> suffix.
|
|
337
283
|
const shortName = (name, inst) => (inst && inst.display_name) || name.replace(/-t\d+$/, "");
|
|
338
|
-
const STATUS_TEXT = { running: "🟢 Running",
|
|
339
|
-
const STATUS_ORDER = { running: 0,
|
|
284
|
+
const STATUS_TEXT = { running: "🟢 Running", crashed: "🔴 Crashed", stopped: "⚪ Stopped" };
|
|
285
|
+
const STATUS_ORDER = { running: 0, crashed: 1, stopped: 2 };
|
|
340
286
|
const groupOf = (inst) => (inst.tags && inst.tags[0]) || "Other";
|
|
341
287
|
function compactRow(name, inst) {
|
|
342
288
|
const st = state.live[name]?.status || "stopped";
|
|
343
289
|
const running = st === "running";
|
|
344
|
-
const paused = st === "paused";
|
|
345
290
|
const short = shortName(name, inst);
|
|
346
291
|
const chTag = agentChannelLabel(inst);
|
|
347
292
|
const item = el("div", { class: "item" });
|
|
@@ -354,9 +299,7 @@
|
|
|
354
299
|
chTag ? el("span", { class: "tag" + (chTag.includes("persona") ? " persona" : chTag.includes("telegram") ? " tg" : "") }, chTag) : null,
|
|
355
300
|
el("span", { class: "spacer" }),
|
|
356
301
|
el("button", { class: "sm ghost", onclick: () => { editing = editing === name ? null : name; renderAgents(); } }, editing === name ? t("close") : t("edit")),
|
|
357
|
-
|
|
358
|
-
paused ? el("button", { class: "sm", onclick: () => pauseWakeAgent(name, "wake") }, t("wake")) : null,
|
|
359
|
-
!paused ? el("button", { class: "sm", onclick: () => toggleAgent(name, running) }, running ? t("stop") : t("start")) : null,
|
|
302
|
+
el("button", { class: "sm", onclick: () => toggleAgent(name, running) }, running ? t("stop") : t("start")),
|
|
360
303
|
el("button", { class: "sm danger del-btn", title: t("close"), onclick: () => delAgent(name) }, "🗑️"),
|
|
361
304
|
));
|
|
362
305
|
if (editing === name) item.append(agentEditForm(name, inst));
|
|
@@ -390,7 +333,6 @@
|
|
|
390
333
|
}
|
|
391
334
|
function agentEditForm(name, inst) {
|
|
392
335
|
const box = el("div", { class: "edit" });
|
|
393
|
-
const defaults = state.fleet.defaults || {};
|
|
394
336
|
const fBackend = select(inst.backend || state.fleet.defaults?.backend || "claude-code", BACKENDS);
|
|
395
337
|
const fModel = el("input", { type: "text", value: inst.model || "", placeholder: "(inherit default)" });
|
|
396
338
|
const fWd = el("input", { type: "text", value: inst.working_directory || "" });
|
|
@@ -399,77 +341,29 @@
|
|
|
399
341
|
const fSys = el("input", { type: "text", value: inst.systemPrompt || "", placeholder: "e.g. file:prompts/dev.md" });
|
|
400
342
|
const tags = [...(inst.tags || [])];
|
|
401
343
|
const fGeneral = el("input", { type: "checkbox" }); fGeneral.checked = !!inst.general_topic;
|
|
402
|
-
const auto = overrideControl(inst, "auto_pause_after", el("input", { type: "number", min: "0", step: "1", value: inst.auto_pause_after ?? defaults.auto_pause_after ?? 0, placeholder: "0 = disabled" }), defaults.auto_pause_after ?? 0);
|
|
403
|
-
const hangRaw = inst.hang_detector || {};
|
|
404
|
-
const hangHolder = hasOwn(hangRaw, "timeout_minutes") ? { value: hangRaw.timeout_minutes } : {};
|
|
405
|
-
const hang = overrideControl(hangHolder, "value", el("input", { type: "number", min: "0.1", step: "0.5", value: hangRaw.timeout_minutes ?? defaults.hang_detector?.timeout_minutes ?? 15 }), defaults.hang_detector?.timeout_minutes ?? 15);
|
|
406
|
-
const agentMode = overrideControl(inst, "agent_mode", select(inst.agent_mode || defaults.agent_mode || "mcp", ["mcp", "cli"]), defaults.agent_mode || "mcp");
|
|
407
|
-
const toolSet = overrideControl(inst, "tool_set", select(inst.tool_set || defaults.tool_set || "full", ["full", "standard", "minimal"]), defaults.tool_set || "full");
|
|
408
|
-
const logLevel = overrideControl(inst, "log_level", select(inst.log_level || defaults.log_level || "info", ["trace", "debug", "info", "warn", "error"]), defaults.log_level || "info");
|
|
409
|
-
const fLightweight = el("input", { type: "checkbox" }); fLightweight.checked = inst.lightweight ?? defaults.lightweight ?? false;
|
|
410
|
-
const lightweight = overrideControl(inst, "lightweight", fLightweight, defaults.lightweight ?? false);
|
|
411
|
-
const fallbackValue = Array.isArray(inst.model_failover) ? (inst.model_failover[0] || "") : (defaults.model_failover?.[0] || "");
|
|
412
|
-
const failover = overrideControl(inst, "model_failover", el("input", { type: "text", value: fallbackValue, placeholder: "e.g. sonnet" }), defaults.model_failover?.[0] || "");
|
|
413
|
-
const displayName = overrideControl(inst, "display_name", el("input", { type: "text", value: inst.display_name ?? defaults.display_name ?? "", placeholder: name }), defaults.display_name || "");
|
|
414
|
-
const autoFeedback = el("div", { class: "feedback" });
|
|
415
|
-
const hangFeedback = el("div", { class: "feedback" });
|
|
416
|
-
const failoverFeedback = el("div", { class: "feedback" });
|
|
417
344
|
const msg = el("span", { class: "msg" });
|
|
418
|
-
const saveBtn = el("button", { class: "primary sm" }, t("save"));
|
|
419
|
-
const validate = () => {
|
|
420
|
-
const autoValue = Number(auto.input.value), hangValue = Number(hang.input.value);
|
|
421
|
-
const validAuto = setValidation(auto.input, autoFeedback, !auto.toggle.checked && (!Number.isFinite(autoValue) || autoValue < 0) ? "Must be 0 or greater" : "");
|
|
422
|
-
const validHang = setValidation(hang.input, hangFeedback, !hang.toggle.checked && (!Number.isFinite(hangValue) || hangValue <= 0) ? "Must be greater than 0" : "");
|
|
423
|
-
setValidation(failover.input, failoverFeedback, "", !failover.toggle.checked && !failover.input.value.trim() ? "Empty list disables failover" : "");
|
|
424
|
-
saveBtn.disabled = !(validAuto && validHang);
|
|
425
|
-
return !saveBtn.disabled;
|
|
426
|
-
};
|
|
427
|
-
for (const ctl of [auto, hang, agentMode, toolSet, logLevel, lightweight, failover, displayName]) {
|
|
428
|
-
ctl.input.addEventListener("input", validate); ctl.input.addEventListener("change", validate); ctl.toggle.addEventListener("change", validate);
|
|
429
|
-
}
|
|
430
|
-
saveBtn.onclick = async () => {
|
|
431
|
-
if (!validate()) return;
|
|
432
|
-
const patch = {
|
|
433
|
-
backend: fBackend.value, model: fModel.value || undefined,
|
|
434
|
-
working_directory: fWd.value, channel_id: fChan.value || undefined,
|
|
435
|
-
description: fDesc.value || undefined, systemPrompt: fSys.value || undefined,
|
|
436
|
-
tags: tags.length ? tags : undefined, general_topic: fGeneral.checked,
|
|
437
|
-
auto_pause_after: auto.toggle.checked ? null : Number(auto.input.value),
|
|
438
|
-
hang_detector: { timeout_minutes: hang.toggle.checked ? null : Number(hang.input.value) },
|
|
439
|
-
agent_mode: agentMode.toggle.checked ? null : agentMode.input.value,
|
|
440
|
-
tool_set: toolSet.toggle.checked ? null : toolSet.input.value,
|
|
441
|
-
log_level: logLevel.toggle.checked ? null : logLevel.input.value,
|
|
442
|
-
lightweight: lightweight.toggle.checked ? null : lightweight.input.checked,
|
|
443
|
-
model_failover: failover.toggle.checked ? null : (failover.input.value.trim() ? [failover.input.value.trim()] : []),
|
|
444
|
-
display_name: displayName.toggle.checked ? null : displayName.input.value.trim(),
|
|
445
|
-
};
|
|
446
|
-
const res = await api(`/api/settings/fleet/instances/${encodeURIComponent(name)}`, { method: "PATCH", body: JSON.stringify(patch) });
|
|
447
|
-
resultMsg(msg, res); if (res.ok) { await reload(); showBanner(`✓ ${t("affected")}: ${name} — 🔄 restart instance`); }
|
|
448
|
-
};
|
|
449
345
|
box.append(
|
|
450
346
|
el("div", { class: "sub", style: "margin:0 0 8px" }, "ID: " + name),
|
|
451
|
-
el("div", { class: "grid2" }, el("div", {}, el("label", {}, t("backend")
|
|
452
|
-
el("label", {}, t("workingDir")
|
|
453
|
-
el("div", { class: "grid2" }, el("div", {}, el("label", {}, t("channelBinding")
|
|
454
|
-
el("label", {}, t("systemPrompt")
|
|
455
|
-
el("label", {}, t("tags")
|
|
456
|
-
el("label", { style: "display:flex;align-items:center;gap:8px;cursor:pointer" }, fGeneral, el("span", {}, t("generalTopicField"))
|
|
457
|
-
el("div", { class: "sub", style: "margin:14px 0 6px;font-weight:600" }, t("runtimeResources")),
|
|
458
|
-
el("div", { class: "grid2" },
|
|
459
|
-
el("div", {}, el("label", {}, `${t("autoPause")} (${t("minutes")})`), auto.row, autoFeedback),
|
|
460
|
-
el("div", {}, el("label", {}, `${t("hangTimeout")} (${t("minutes")})`), hang.row, hangFeedback),
|
|
461
|
-
el("div", {}, el("label", {}, t("agentMode")), agentMode.row),
|
|
462
|
-
el("div", {}, el("label", {}, t("toolSet")), toolSet.row),
|
|
463
|
-
el("div", {}, el("label", {}, t("logLevel")), logLevel.row),
|
|
464
|
-
el("div", {}, el("label", {}, t("lightweight")), lightweight.row),
|
|
465
|
-
el("div", {}, el("label", {}, t("modelFailover")), failover.row, failoverFeedback),
|
|
466
|
-
el("div", {}, el("label", {}, t("displayName")), displayName.row)),
|
|
347
|
+
el("div", { class: "grid2" }, el("div", {}, el("label", {}, t("backend")), fBackend), el("div", {}, el("label", {}, t("model")), fModel)),
|
|
348
|
+
el("label", {}, t("workingDir")), fWd,
|
|
349
|
+
el("div", { class: "grid2" }, el("div", {}, el("label", {}, t("channelBinding")), fChan), el("div", {}, el("label", {}, t("description")), fDesc)),
|
|
350
|
+
el("label", {}, t("systemPrompt")), fSys,
|
|
351
|
+
el("label", {}, t("tags")), chipList(tags, null, "tag"),
|
|
352
|
+
el("label", { style: "display:flex;align-items:center;gap:8px;cursor:pointer" }, fGeneral, el("span", {}, t("generalTopicField"))),
|
|
467
353
|
el("div", { class: "actions" },
|
|
468
|
-
|
|
354
|
+
el("button", { class: "primary sm", onclick: async () => {
|
|
355
|
+
const patch = {
|
|
356
|
+
backend: fBackend.value, model: fModel.value || undefined,
|
|
357
|
+
working_directory: fWd.value, channel_id: fChan.value || undefined,
|
|
358
|
+
description: fDesc.value || undefined, systemPrompt: fSys.value || undefined,
|
|
359
|
+
tags: tags.length ? tags : undefined, general_topic: fGeneral.checked,
|
|
360
|
+
};
|
|
361
|
+
const res = await api(`/api/settings/fleet/instances/${encodeURIComponent(name)}`, { method: "PATCH", body: JSON.stringify(patch) });
|
|
362
|
+
resultMsg(msg, res); if (res.ok) await reload();
|
|
363
|
+
} }, t("save")),
|
|
469
364
|
el("button", { class: "sm ghost", onclick: () => { editing = null; renderAgents(); } }, t("cancel")),
|
|
470
365
|
msg),
|
|
471
366
|
);
|
|
472
|
-
validate();
|
|
473
367
|
return box;
|
|
474
368
|
}
|
|
475
369
|
async function toggleAgent(name, running) {
|
|
@@ -477,11 +371,6 @@
|
|
|
477
371
|
else await api(`/api/instance/${encodeURIComponent(name)}/start`, { method: "POST" });
|
|
478
372
|
setTimeout(reloadLive, 800);
|
|
479
373
|
}
|
|
480
|
-
async function pauseWakeAgent(name, action) {
|
|
481
|
-
const res = await api(`/api/settings/instances/${encodeURIComponent(name)}/${action}`, { method: "POST" });
|
|
482
|
-
if (!res.ok) alert(res.body?.error || `${action} failed`);
|
|
483
|
-
await reloadLive();
|
|
484
|
-
}
|
|
485
374
|
async function delAgent(name) {
|
|
486
375
|
if (!confirm(`Delete agent "${name}"? (config removed; running daemon stops on next Reload)`)) return;
|
|
487
376
|
const res = await api(`/api/settings/fleet/instances/${encodeURIComponent(name)}`, { method: "DELETE" });
|
|
@@ -510,7 +399,6 @@
|
|
|
510
399
|
}
|
|
511
400
|
|
|
512
401
|
// ── Bots ──
|
|
513
|
-
let editingBot = null;
|
|
514
402
|
function renderBots() {
|
|
515
403
|
const host = $("bots"); host.innerHTML = ""; const chs = channels();
|
|
516
404
|
if (!chs.length) { host.className = "card empty"; host.textContent = t("noBots"); return; }
|
|
@@ -524,41 +412,12 @@
|
|
|
524
412
|
el("span", { class: "sub", style: "margin:0" }, ch.bot_token_env || "(no token env)"),
|
|
525
413
|
el("span", { class: "spacer" }),
|
|
526
414
|
el("span", { style: "color:var(--green);font-size:13px" }, state.fleetUp ? t("online") : "—"),
|
|
527
|
-
el("button", { class: "sm ghost", onclick: () => { editingBot = editingBot === i ? null : i; renderBots(); } }, editingBot === i ? t("close") : t("edit")),
|
|
528
415
|
el("button", { class: "sm danger", onclick: () => delBot(i) }, "🗑️"),
|
|
529
416
|
));
|
|
530
|
-
if (editingBot === i) item.append(botEditForm(ch, i));
|
|
531
417
|
host.append(item);
|
|
532
418
|
});
|
|
533
419
|
}
|
|
534
420
|
|
|
535
|
-
function botEditForm(ch, i) {
|
|
536
|
-
ch.access = ch.access || { mode: "locked", allowed_users: [] };
|
|
537
|
-
ch.access.allowed_users = ch.access.allowed_users || [];
|
|
538
|
-
const box = el("div", { class: "edit" });
|
|
539
|
-
const fMode = select(ch.access.mode || "locked", ["open", "locked", "pairing"]);
|
|
540
|
-
const users = [...ch.access.allowed_users];
|
|
541
|
-
const msg = el("span", { class: "msg" });
|
|
542
|
-
box.append(
|
|
543
|
-
el("div", { class: "grid2" },
|
|
544
|
-
el("div", {}, el("label", {}, t("accessMode"), impact("fleet")), fMode),
|
|
545
|
-
el("div", {}, el("label", {}, t("allowedUsers"), impact("fleet")), chipList(users, null, "user id"))),
|
|
546
|
-
el("div", { class: "actions" },
|
|
547
|
-
el("button", { class: "primary sm", onclick: async () => {
|
|
548
|
-
const chs = channels();
|
|
549
|
-
chs[i] = { ...chs[i], access: { ...chs[i].access, mode: fMode.value, allowed_users: users } };
|
|
550
|
-
const res = await saveChannels(msg);
|
|
551
|
-
if (res.ok) {
|
|
552
|
-
const affected = Object.keys(state.fleet.instances || {});
|
|
553
|
-
editingBot = null; await reload();
|
|
554
|
-
showBanner(`✓ ${t("affected")}: ${affected.length ? affected.join(", ") : chLabel(i) + " bot"} — 🔄🔄 restart fleet`);
|
|
555
|
-
}
|
|
556
|
-
} }, t("save")),
|
|
557
|
-
el("button", { class: "sm ghost", onclick: () => { editingBot = null; renderBots(); } }, t("cancel")), msg),
|
|
558
|
-
);
|
|
559
|
-
return box;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
421
|
// ── ClassicBot Channels (read-only; created dynamically via /start /stop) ──
|
|
563
422
|
function renderClassic() {
|
|
564
423
|
const host = $("classicList"); if (!host) return; host.innerHTML = "";
|
|
@@ -627,8 +486,6 @@
|
|
|
627
486
|
state.fleet.defaults = state.fleet.defaults || {};
|
|
628
487
|
state.classic.defaults = state.classic.defaults || {};
|
|
629
488
|
const d = state.fleet.defaults, c = state.classic.defaults;
|
|
630
|
-
const hang = d.hang_detector || {};
|
|
631
|
-
const startup = d.startup || {};
|
|
632
489
|
const primary = channels()[0];
|
|
633
490
|
if (primary) primary.access = primary.access || { mode: "locked", allowed_users: [] };
|
|
634
491
|
const allowedUsers = primary ? (primary.access.allowed_users = primary.access.allowed_users || []) : [];
|
|
@@ -636,93 +493,26 @@
|
|
|
636
493
|
|
|
637
494
|
const fBackend = select(d.backend || "claude-code", BACKENDS);
|
|
638
495
|
const fModel = el("input", { type: "text", value: d.model || "", placeholder: "e.g. claude-opus-4-8" });
|
|
639
|
-
const fAgentMode = select(d.agent_mode || "mcp", ["mcp", "cli"]);
|
|
640
|
-
const fToolSet = select(d.tool_set || "full", ["full", "standard", "minimal"]);
|
|
641
|
-
const fLogLevel = select(d.log_level || "info", ["trace", "debug", "info", "warn", "error"]);
|
|
642
496
|
const fLocale = el("select");
|
|
643
|
-
const fAutoPause = el("input", { type: "number", min: "0", step: "1", value: d.auto_pause_after ?? 0, placeholder: "0 = disabled" });
|
|
644
|
-
const fHangEnabled = el("input", { type: "checkbox" }); fHangEnabled.checked = hang.enabled !== false;
|
|
645
|
-
const fHangTimeout = el("input", { type: "number", min: "0.1", step: "0.5", value: hang.timeout_minutes ?? 15 });
|
|
646
|
-
const fConcurrency = el("input", { type: "number", min: "1", max: "20", step: "1", value: startup.concurrency ?? 10 });
|
|
647
|
-
const fStagger = el("input", { type: "number", min: "0", max: "30000", step: "100", value: startup.stagger_delay_ms ?? 500 });
|
|
648
497
|
[["en", "English"], ["zh-TW", "繁體中文 (zh-TW)"]].forEach(([v, lbl]) => { const o = el("option", {}, lbl); o.value = v; if ((d.locale || "") === v) o.selected = true; fLocale.append(o); });
|
|
649
498
|
const msg = el("span", { class: "msg" });
|
|
650
|
-
const autoFeedback = el("div", { class: "feedback" });
|
|
651
|
-
const hangFeedback = el("div", { class: "feedback" });
|
|
652
|
-
const concurrencyFeedback = el("div", { class: "feedback" });
|
|
653
|
-
const staggerFeedback = el("div", { class: "feedback" });
|
|
654
|
-
const saveBtn = el("button", { class: "primary" }, t("save"));
|
|
655
|
-
const validate = () => {
|
|
656
|
-
const auto = Number(fAutoPause.value), timeout = Number(fHangTimeout.value);
|
|
657
|
-
const concurrency = Number(fConcurrency.value), stagger = Number(fStagger.value);
|
|
658
|
-
const validAuto = setValidation(fAutoPause, autoFeedback, !Number.isFinite(auto) || auto < 0 ? "Must be 0 or greater" : "");
|
|
659
|
-
const validHang = setValidation(fHangTimeout, hangFeedback, !Number.isFinite(timeout) || timeout <= 0 ? "Must be greater than 0" : "");
|
|
660
|
-
const validConcurrency = setValidation(fConcurrency, concurrencyFeedback, !Number.isInteger(concurrency) || concurrency < 1 || concurrency > 20 ? "Must be an integer from 1 to 20" : "", concurrency > 4 ? "May exceed CPU capacity on smaller hosts" : "");
|
|
661
|
-
const validStagger = setValidation(fStagger, staggerFeedback, !Number.isFinite(stagger) || stagger < 0 || stagger > 30000 ? "Must be between 0 and 30000" : "", stagger < 100 ? "Very low values can cause startup spikes" : "");
|
|
662
|
-
saveBtn.disabled = !(validAuto && validHang && validConcurrency && validStagger);
|
|
663
|
-
return !saveBtn.disabled;
|
|
664
|
-
};
|
|
665
|
-
for (const input of [fAutoPause, fHangTimeout, fConcurrency, fStagger]) {
|
|
666
|
-
input.addEventListener("input", validate); input.addEventListener("change", validate);
|
|
667
|
-
}
|
|
668
|
-
saveBtn.onclick = async () => {
|
|
669
|
-
if (!validate()) return;
|
|
670
|
-
const defaultsPatch = {
|
|
671
|
-
backend: fBackend.value,
|
|
672
|
-
model: fModel.value || undefined,
|
|
673
|
-
locale: fLocale.value,
|
|
674
|
-
auto_pause_after: Number(fAutoPause.value),
|
|
675
|
-
agent_mode: fAgentMode.value,
|
|
676
|
-
tool_set: fToolSet.value,
|
|
677
|
-
log_level: fLogLevel.value,
|
|
678
|
-
hang_detector: { enabled: fHangEnabled.checked, timeout_minutes: Number(fHangTimeout.value) },
|
|
679
|
-
startup: { concurrency: Number(fConcurrency.value), stagger_delay_ms: Number(fStagger.value) },
|
|
680
|
-
};
|
|
681
|
-
const r1 = await api("/api/settings/fleet/defaults", { method: "PUT", body: JSON.stringify(defaultsPatch) });
|
|
682
|
-
let r2 = { ok: true, body: {} };
|
|
683
|
-
if (primary) r2 = await saveChannels();
|
|
684
|
-
const r3 = await api("/api/settings/classic/defaults", { method: "PUT", body: JSON.stringify({ backend: c.backend, admin_users: c.admin_users, allowed_guilds: c.allowed_guilds }) });
|
|
685
|
-
const bad = [r1, r2, r3].find(r => !r.ok);
|
|
686
|
-
resultMsg(msg, bad || { ok: true, body: { warnings: [...(r1.body?.warnings || []), ...(r3.body?.warnings || [])] } });
|
|
687
|
-
if (!bad) {
|
|
688
|
-
const affected = Object.keys(state.fleet.instances || {});
|
|
689
|
-
await reload();
|
|
690
|
-
showBanner(`✓ ${t("affected")}: ${affected.length ? affected.join(", ") : "none"} — 🔄 restart instances; startup changes 🔄🔄 restart fleet`);
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
const section = (title, open, ...children) => {
|
|
695
|
-
const details = el("details", { class: "settings-section" }); details.open = open;
|
|
696
|
-
details.append(el("summary", {}, title), el("div", { class: "section-body" }, ...children));
|
|
697
|
-
return details;
|
|
698
|
-
};
|
|
699
499
|
host.append(
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
el("div", { class: "grid2" },
|
|
716
|
-
el("div", { class: "field" }, el("label", {}, t("concurrency"), impact("fleet")), fConcurrency, concurrencyFeedback),
|
|
717
|
-
el("div", { class: "field" }, el("label", {}, `${t("staggerDelay")} (ms)`, impact("fleet")), fStagger, staggerFeedback))),
|
|
718
|
-
section(t("advancedSection"), false,
|
|
719
|
-
el("div", { class: "field" }, el("label", {}, t("language"), impact("now")), fLocale),
|
|
720
|
-
el("div", { class: "field" }, el("label", {}, t("allowedUsers"), impact("fleet")), chipList(allowedUsers, null, "user id")),
|
|
721
|
-
el("div", { class: "field" }, el("label", {}, t("classicAdmins"), impact("fleet")), chipList(c.admin_users, null, "user id")),
|
|
722
|
-
el("div", { class: "field" }, el("label", {}, t("allowedGuilds"), impact("fleet")), chipList(c.allowed_guilds, null, "guild id"))),
|
|
723
|
-
el("div", { class: "field" }, el("div", { class: "actions" }, saveBtn, msg)),
|
|
500
|
+
el("div", { class: "field" }, el("label", {}, t("language")), fLocale),
|
|
501
|
+
el("div", { class: "field" }, el("label", {}, t("defaultBackend")), fBackend),
|
|
502
|
+
el("div", { class: "field" }, el("label", {}, t("defaultModel")), fModel),
|
|
503
|
+
el("div", { class: "field" }, el("label", {}, t("allowedUsers")), chipList(allowedUsers, null, "user id")),
|
|
504
|
+
el("div", { class: "field" }, el("label", {}, t("classicAdmins")), chipList(c.admin_users, null, "user id")),
|
|
505
|
+
el("div", { class: "field" }, el("label", {}, t("allowedGuilds")), chipList(c.allowed_guilds, null, "guild id")),
|
|
506
|
+
el("div", { class: "field" }, el("div", { class: "actions" }, el("button", { class: "primary", onclick: async () => {
|
|
507
|
+
d.backend = fBackend.value; d.model = fModel.value || undefined; d.locale = fLocale.value;
|
|
508
|
+
const r1 = await api("/api/settings/fleet/defaults", { method: "PUT", body: JSON.stringify({ backend: d.backend, model: d.model, locale: d.locale }) });
|
|
509
|
+
let r2 = { ok: true, body: {} };
|
|
510
|
+
if (primary) r2 = await saveChannels();
|
|
511
|
+
const r3 = await api("/api/settings/classic/defaults", { method: "PUT", body: JSON.stringify({ backend: c.backend, admin_users: c.admin_users, allowed_guilds: c.allowed_guilds }) });
|
|
512
|
+
const bad = [r1, r2, r3].find(r => !r.ok);
|
|
513
|
+
resultMsg(msg, bad || { ok: true, body: { warnings: [...(r1.body?.warnings || []), ...(r3.body?.warnings || [])] } });
|
|
514
|
+
} }, t("save")), msg)),
|
|
724
515
|
);
|
|
725
|
-
validate();
|
|
726
516
|
}
|
|
727
517
|
|
|
728
518
|
// ── What's New ──
|
|
@@ -799,8 +589,7 @@
|
|
|
799
589
|
renderAgents(); renderBots(); renderClassic();
|
|
800
590
|
}
|
|
801
591
|
async function reload() {
|
|
802
|
-
|
|
803
|
-
const f = await api("/api/settings/fleet/raw");
|
|
592
|
+
const f = await api("/api/settings/fleet");
|
|
804
593
|
if (!f.ok) { $("banner").style.display = "block"; $("banner").style.background = "#fef2f2"; $("banner").style.color = "var(--red)"; $("banner").textContent = "Failed to load config — check the token in the URL."; return; }
|
|
805
594
|
state.fleet = f.body || {};
|
|
806
595
|
const c = await api("/api/settings/classic"); state.classic = c.body || {};
|
package/dist/web-api.d.ts
CHANGED
|
@@ -61,7 +61,6 @@ export interface WebApiContext {
|
|
|
61
61
|
};
|
|
62
62
|
getInstanceDir(name: string): string;
|
|
63
63
|
getInstanceStatus(name: string): "running" | "paused" | "stopped" | "crashed";
|
|
64
|
-
deliverToInstance(instanceName: string, payload: Record<string, unknown>): Promise<void>;
|
|
65
64
|
getUiStatus(): unknown;
|
|
66
65
|
emitSseEvent(event: string, data: unknown): void;
|
|
67
66
|
startInstance(name: string, config: unknown, topicMode: boolean): Promise<void>;
|
package/dist/web-api.js
CHANGED
|
@@ -41,7 +41,7 @@ const ConfigUpdateSchema = z.object({
|
|
|
41
41
|
access: z.record(z.string(), z.unknown()).optional(),
|
|
42
42
|
}).strict().optional(),
|
|
43
43
|
defaults: z.object({
|
|
44
|
-
backend: z.enum(["claude-code", "gemini-cli", "codex", "opencode", "kiro-cli", "antigravity"
|
|
44
|
+
backend: z.enum(["claude-code", "gemini-cli", "codex", "opencode", "kiro-cli", "antigravity"]).optional(),
|
|
45
45
|
model: z.string().max(128).optional(),
|
|
46
46
|
}).strict().optional(),
|
|
47
47
|
project_roots: z.array(z.string().min(1).max(1024)).max(64).optional(),
|
|
@@ -165,8 +165,6 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
165
165
|
{ name: "gemini-cli", binary: "gemini" },
|
|
166
166
|
{ name: "opencode", binary: "opencode" },
|
|
167
167
|
{ name: "kiro-cli", binary: "kiro-cli" },
|
|
168
|
-
{ name: "antigravity", binary: "agy" },
|
|
169
|
-
{ name: "grok", binary: "grok" },
|
|
170
168
|
];
|
|
171
169
|
const backends = BACKENDS.map(b => {
|
|
172
170
|
let installed = false;
|
|
@@ -594,7 +592,7 @@ function handleSendMessage(req, res, ctx) {
|
|
|
594
592
|
}
|
|
595
593
|
body += chunk.toString();
|
|
596
594
|
});
|
|
597
|
-
req.on("end",
|
|
595
|
+
req.on("end", () => {
|
|
598
596
|
try {
|
|
599
597
|
const raw = JSON.parse(body);
|
|
600
598
|
const parsed = SendMessageSchema.safeParse(raw);
|
|
@@ -616,26 +614,19 @@ function handleSendMessage(req, res, ctx) {
|
|
|
616
614
|
// a separate reply path for that case.
|
|
617
615
|
const groupId = ctx.fleetConfig?.channel?.group_id;
|
|
618
616
|
const topicId = ctx.fleetConfig?.instances[instance]?.topic_id;
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
catch (err) {
|
|
635
|
-
ctx.logger.error({ err, instance }, "Web message delivery failed");
|
|
636
|
-
json(res, 503, { error: "Instance delivery failed" });
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
617
|
+
ipc.send({
|
|
618
|
+
type: "fleet_inbound",
|
|
619
|
+
content: message,
|
|
620
|
+
targetSession: instance,
|
|
621
|
+
meta: {
|
|
622
|
+
chat_id: groupId ? String(groupId) : "",
|
|
623
|
+
message_id: `web-${Date.now()}`,
|
|
624
|
+
user: "web-user", user_id: "web-user",
|
|
625
|
+
ts,
|
|
626
|
+
thread_id: topicId != null ? String(topicId) : "",
|
|
627
|
+
source: "web",
|
|
628
|
+
},
|
|
629
|
+
});
|
|
639
630
|
ctx.lastInboundUser.set(instance, "web-user");
|
|
640
631
|
ctx.eventLog?.logActivity("message", "web-user", message.slice(0, 200), instance);
|
|
641
632
|
ctx.emitSseEvent("message", { instance, sender: "web-user", text: message, ts });
|