@songsid/agend 2.3.0-beta.2 → 2.3.0-beta.3
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/agent-whats-new.js +2 -0
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.js +10 -5
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/claude-code.d.ts +2 -2
- package/dist/backend/claude-code.js +5 -4
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/types.d.ts +5 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/mcp-tools.js +4 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +8 -3
- package/dist/classic-channel-manager.js +10 -3
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/delivery-outbox.js +5 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-manager.d.ts +68 -3
- package/dist/fleet-manager.js +247 -41
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-traffic.d.ts +38 -0
- package/dist/fleet-traffic.js +96 -0
- package/dist/fleet-traffic.js.map +1 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +13 -5
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +39 -4
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +398 -0
- package/dist/locale.js +6 -4
- package/dist/locale.js.map +1 -1
- package/dist/memory-hogs.d.ts +27 -0
- package/dist/memory-hogs.js +124 -0
- package/dist/memory-hogs.js.map +1 -0
- package/dist/outbound-handlers.d.ts +2 -0
- package/dist/outbound-handlers.js +40 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +88 -0
- package/dist/outbound-schemas.js +50 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +1 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.js +16 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.js +4 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/ui/app-effects.js +33 -9
- package/dist/ui/chat-effects.js +62 -4
- package/dist/ui/chat-strings.js +40 -4
- package/dist/ui/chat-thread.js +13 -5
- package/dist/ui/effect-trial-panel.js +19 -16
- package/dist/ui/fleet-canvas-layout.js +111 -0
- package/dist/ui/fleet-canvas.js +489 -0
- package/dist/ui/fleet-org.js +27 -12
- package/dist/ui/fleet-traffic.js +224 -0
- package/dist/ui/panel-chat.js +8 -2
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +17 -5
- package/dist/ui/panel-settings.js +3 -2
- package/dist/ui/preview.js +3 -2
- package/dist/ui/settings-appearance.js +34 -18
- package/dist/ui/settings-dialogs.js +3 -6
- package/dist/ui/settings-effects.js +4 -3
- package/dist/ui/settings-learn.js +25 -0
- package/dist/ui/settings-model.js +6 -2
- package/dist/ui/settings-mods.js +4 -3
- package/dist/ui/settings-owner-effects.js +8 -8
- package/dist/ui/settings-strings.js +34 -38
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-prefs.js +1 -1
- package/dist/ui/shared/app-shell.js +23 -1
- package/dist/ui/shared/app-store.js +12 -1
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +152 -10
- package/dist/ui/shared/effect-app-runtime.js +1 -1
- package/dist/ui/shared/effect-frame.js +10 -5
- package/dist/ui/shared/effect-geometry.js +24 -9
- package/dist/ui/shared/effect-policy.js +2 -1
- package/dist/ui/shared/effect-registry.js +71 -17
- package/dist/ui/shared/effect-trial-shadow.js +62 -0
- package/dist/ui/shared/effect-trial-stage.js +15 -9
- package/dist/ui/shared/effect-trial.css +40 -0
- package/dist/ui/shared/identity-card.js +5 -2
- package/dist/ui/shared/identity-color.js +3 -3
- package/dist/ui/shared/instance-nav.js +20 -4
- package/dist/ui/shared/panel-view.js +2 -2
- package/dist/ui/shared/view-strings.js +16 -0
- package/dist/view-api.d.ts +21 -0
- package/dist/view-api.js +28 -0
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +5 -6
- package/dist/web-api.js +57 -10
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-view.d.ts +10 -0
- package/dist/web-appearance-view.js +77 -8
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-effect-trials.d.ts +2 -2
- package/dist/web-effect-trials.js +3 -3
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-guest-access.d.ts +67 -0
- package/dist/web-guest-access.js +126 -0
- package/dist/web-guest-access.js.map +1 -0
- package/dist/web-identity-palette.d.ts +1 -1
- package/dist/web-identity-palette.js +2 -2
- package/dist/web-identity-palette.js.map +1 -1
- package/dist/web-mod-store.d.ts +5 -0
- package/dist/web-mod-store.js +6 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-prefs.d.ts +8 -0
- package/dist/web-prefs.js +9 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -2
- package/dist/web-preview.js +4 -2
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +15 -7
- package/dist/web-session.js +25 -8
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-tools.d.ts +69 -0
- package/dist/web-settings-tools.js +247 -0
- package/dist/web-settings-tools.js.map +1 -0
- package/package.json +1 -1
|
@@ -222,8 +222,12 @@ export function accessConfirmations(previousAccess, nextMode, nextUsers) {
|
|
|
222
222
|
return out;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
/**
|
|
226
|
-
|
|
225
|
+
/**
|
|
226
|
+
* #2054: whether a ClassicBot room copies web chat, as the fleet decides it (ClassicChannelManager's load +
|
|
227
|
+
* classicWebEchoOn): an absent `web_echo` follows the fleet-wide `web.echo_to_channel` (default on); any other value
|
|
228
|
+
* echoes only when it is `true` (a `null`, `0` or string reads as off, as the manager reads it).
|
|
229
|
+
*/
|
|
230
|
+
export const classicWebEchoEffective = (room, fleet) => (room?.web_echo === undefined ? fleet?.web?.echo_to_channel !== false : room.web_echo === true);
|
|
227
231
|
|
|
228
232
|
// ── Developer YAML: the config subset's writer and reader, exactly as settings.html had them (round-trip verified) ──
|
|
229
233
|
export function toYaml(value, indent = 0) {
|
package/dist/ui/settings-mods.js
CHANGED
|
@@ -12,6 +12,7 @@ import { toast } from "/assets/ui-toast.js";
|
|
|
12
12
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
13
13
|
import { startOwnerCssTrial } from "/assets/owner-css.js";
|
|
14
14
|
import { AgentWidget, checkWidget, fleetBinds, instanceBinds } from "/assets/agent-widget.js";
|
|
15
|
+
import { CardTitle } from "./settings-learn.js";
|
|
15
16
|
import "./settings-strings.js";
|
|
16
17
|
|
|
17
18
|
const tn = (k, ...v) => t(`settings.${k}`, ...v);
|
|
@@ -204,8 +205,8 @@ export function ModsCard() {
|
|
|
204
205
|
setState(b && Array.isArray(b.mods) ? { mods: b.mods.filter((m) => m && typeof m.id === "string"), staged, proposals } : { failed: true });
|
|
205
206
|
};
|
|
206
207
|
useEffect(() => { load(); }, []);
|
|
207
|
-
if (!state) return html`<section class="card s-appearance s-mods"
|
|
208
|
-
if (state.failed) return html`<section class="card s-appearance s-mods"
|
|
208
|
+
if (!state) return html`<section class="card s-appearance s-mods"><${CardTitle} title=${tn("modsTitle")} topic="mods" /><p class="sub">…</p></section>`;
|
|
209
|
+
if (state.failed) return html`<section class="card s-appearance s-mods"><${CardTitle} title=${tn("modsTitle")} topic="mods" /><p class="err">${tn("modsLoadFailed")}</p></section>`;
|
|
209
210
|
const stage = async () => {
|
|
210
211
|
const f = file.current && file.current.files && file.current.files[0];
|
|
211
212
|
if (!f) return;
|
|
@@ -238,7 +239,7 @@ export function ModsCard() {
|
|
|
238
239
|
if (!r || !r.ok) { toast(tn("modFailed", r ? r.status : "network"), false); return; }
|
|
239
240
|
download(await r.text(), `${m.name}-${m.version}.agendmod.json`);
|
|
240
241
|
};
|
|
241
|
-
return html`<section class="card s-appearance s-mods"
|
|
242
|
+
return html`<section class="card s-appearance s-mods"><${CardTitle} title=${tn("modsTitle")} topic="mods" />
|
|
242
243
|
<p class="sub">${tn("modsLead")}</p>
|
|
243
244
|
${state.staged ? html`<${Plan} key=${state.staged.stage} staged=${state.staged} onDone=${load} />` : html`<div class="s-mod-import">
|
|
244
245
|
<label class="btn"><${Icon} name="attach" size=${16} /><span>${tn("modChoose")}</span>
|
|
@@ -7,24 +7,24 @@ import { getAppEffects } from "./app-effects.js";
|
|
|
7
7
|
import { ownerEffectsStore, watchOwnerEffects, refreshOwnerEffects, saveOwnerEffects } from "/assets/owner-effect-prefs.js";
|
|
8
8
|
register("ownerEffects", {
|
|
9
9
|
en: {
|
|
10
|
-
title: "Your effect choices", operatorTitle: "Host-wide effect choices", person: "
|
|
11
|
-
operator: "
|
|
10
|
+
title: "Your effect choices", operatorTitle: "Host-wide effect choices", person: "Follows your sign-in; Discord and Telegram are separate.",
|
|
11
|
+
operator: "Shared by everyone signed in as the host.",
|
|
12
12
|
sidebar: "Sidebar", header: "Header", page: "Page", box: "Box", cursor: "Cursor", none: "None", savedChoice: "Saved choice",
|
|
13
13
|
unknown: "Choices are unavailable. Reload to try again.", changed: "This page can no longer access these choices. Reload and sign in again.",
|
|
14
14
|
unavailable: "No longer available", clear: "Clear", reload: "Reload choices", saved: "Saved.", failed: "Couldn't save. Reload choices and try again.",
|
|
15
15
|
savedRefresh: "Saved, but the choices couldn't be refreshed. Reload to check.", readOnly: "Sign in as an admin to change these choices.",
|
|
16
|
-
playback: "
|
|
17
|
-
pause: "Pause", resume: "Resume", running: "Running", cursorFailed: "The cursor could not be applied here. Clear or reload the choice to try again.", starting: "Starting", queued: "Waiting for a slot", paused: "Paused", off: "Playback is off or unavailable here.", budget: "Paused to
|
|
16
|
+
playback: "Plays once Effects and previews are allowed.",
|
|
17
|
+
pause: "Pause", resume: "Resume", running: "Running", cursorFailed: "The cursor could not be applied here. Clear or reload the choice to try again.", starting: "Starting", queued: "Waiting for a slot", paused: "Paused", off: "Playback is off or unavailable here.", budget: "Paused to keep the page responsive.", resumeFailed: "This effect cannot resume: the page or its safety history is not ready. Reload the page or choose another effect.",
|
|
18
18
|
},
|
|
19
19
|
"zh-TW": {
|
|
20
|
-
title: "你的效果選擇", operatorTitle: "主機共用效果選擇", person: "
|
|
21
|
-
operator: "
|
|
20
|
+
title: "你的效果選擇", operatorTitle: "主機共用效果選擇", person: "跟隨你的登入身分;Discord 與 Telegram 各自獨立。",
|
|
21
|
+
operator: "所有以主機身分登入的人共用。",
|
|
22
22
|
sidebar: "側邊欄", header: "頁首", page: "頁面", box: "區塊", cursor: "游標", none: "無", savedChoice: "已儲存的選擇",
|
|
23
23
|
unknown: "目前無法取得選擇,請重新載入再試。", changed: "這個頁面已無法存取選擇,請重新載入並登入。",
|
|
24
24
|
unavailable: "已無法使用", clear: "清除", reload: "重新載入選擇", saved: "已儲存。", failed: "無法儲存,請重新載入選擇再試。",
|
|
25
25
|
savedRefresh: "已儲存,但無法更新畫面;請重新載入確認。", readOnly: "請以管理員身分登入才能修改選擇。",
|
|
26
|
-
playback: "
|
|
27
|
-
pause: "暫停", resume: "恢復", running: "播放中", cursorFailed: "這裡無法套用游標。可清除或重新載入選擇後再試。", starting: "啟動中", queued: "等待空位", paused: "已暫停", off: "這裡已關閉播放,或無法播放效果。", budget: "
|
|
26
|
+
playback: "開啟效果並允許預覽後才會播放。",
|
|
27
|
+
pause: "暫停", resume: "恢復", running: "播放中", cursorFailed: "這裡無法套用游標。可清除或重新載入選擇後再試。", starting: "啟動中", queued: "等待空位", paused: "已暫停", off: "這裡已關閉播放,或無法播放效果。", budget: "為維持頁面順暢,已暫停。", resumeFailed: "頁面或安全紀錄尚未就緒,無法恢復此效果。請重新載入頁面,或選擇其他效果。",
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
const text = key => t(`ownerEffects.${key}`);
|
|
@@ -14,7 +14,7 @@ register("settings", {
|
|
|
14
14
|
publicTtl: "Public link minutes (1–480)",
|
|
15
15
|
publicProtocol: "Tunnel protocol",
|
|
16
16
|
webEcho: "Web echo",
|
|
17
|
-
webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms
|
|
17
|
+
webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms follow it unless a room sets its own.",
|
|
18
18
|
webLogTab: "Log tab: each agent's steps", webLogTabHint: "Shows each instance's prompts, replies, tool calls and results, and fleet events in its Log tab, read from its own transcript only while the tab is open. Secret values are masked. Also over the public link. Turning it on waits for a fleet admin's confirmation.",
|
|
19
19
|
general: "General Settings",
|
|
20
20
|
advanced: "Advanced",
|
|
@@ -88,7 +88,6 @@ register("settings", {
|
|
|
88
88
|
wake: "Wake",
|
|
89
89
|
accessMode: "Access mode",
|
|
90
90
|
affected: "Affected instances",
|
|
91
|
-
webEchoGroupConfirm: "This looks like a group channel: enabling posts every web message to this instance where all channel members can read it. Enable web echo?",
|
|
92
91
|
language: "Language (bot replies)",
|
|
93
92
|
defaultBackend: "Default backend",
|
|
94
93
|
defaultModel: "Default model",
|
|
@@ -290,17 +289,18 @@ register("settings", {
|
|
|
290
289
|
sec_web: "Web",
|
|
291
290
|
// #1629 r4 §3: Settings → Appearance (owner CSS).
|
|
292
291
|
sec_appearance: "Web appearance",
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
groupLook: "Look", groupLayout: "Your layout", groupCss: "Styles you write", groupMods: "Add-ons", groupAdvanced: "Advanced", learnMore: "Learn more: {0}",
|
|
293
|
+
colorTitle: "Identity colours", colorLead: "One agent's colour: its ⋯ menu → Colour…",
|
|
294
|
+
colorPlaces: "Where colours show", colorSample: "Sample agent", colorOff: "Turn off colours",
|
|
295
|
+
colorOffLead: "Colours people picked are kept.",
|
|
296
|
+
restoreTitle: "Restore defaults", restoreLead: "Puts this host's look back to the defaults. Asks first.",
|
|
297
|
+
restoreConfirm: "Resets, for this host: showing agents' themes and effects, the card size and each card's own size, your sidebar widget, where colours show, and colours off. Also turns your custom CSS off (its versions are kept) and its switch on this device. Kept: the colours people picked for agents, installed mods, uploaded effects and the card limits.",
|
|
298
298
|
restoreGo: "Restore defaults", restoreDone: "Appearance settings are back to their defaults.", restoreCssFailed: "The settings are back to their defaults, but your custom CSS could not be turned off: {0}",
|
|
299
299
|
cardSizeTitle: "Identity cards",
|
|
300
|
-
cardSizeLead: "
|
|
300
|
+
cardSizeLead: "A card's own S / M / L overrides this.",
|
|
301
301
|
cardLimitsTitle: "Identity card upload limits",
|
|
302
|
-
cardLimitsLead: "
|
|
303
|
-
cardLimitsUnavailable: "Only a signed-in admin can
|
|
302
|
+
cardLimitsLead: "Empty = the default. Raising a limit needs an admin's OK.",
|
|
303
|
+
cardLimitsUnavailable: "Only a signed-in admin can change these.",
|
|
304
304
|
cardLimit_portrait_max_width: "Portrait width (px)", cardLimit_portrait_max_height: "Portrait height (px)", cardLimit_portrait_max_kib: "Portrait size (KiB)",
|
|
305
305
|
cardLimit_banner_max_width: "Banner width (px)", cardLimit_banner_max_height: "Banner height (px)", cardLimit_banner_max_kib: "Banner size (KiB)",
|
|
306
306
|
cardLimit_instance_quota_files: "Pictures per agent", cardLimit_instance_quota_mib: "Picture space per agent (MiB)",
|
|
@@ -312,10 +312,10 @@ register("settings", {
|
|
|
312
312
|
cardLimitsFailed: "Not saved: {0}",
|
|
313
313
|
themesTitle: "Agents' themes",
|
|
314
314
|
themesShow: "Show agents' themes, effects and widgets",
|
|
315
|
-
themesShowLead: "
|
|
315
|
+
themesShowLead: "When off, every chat looks the same.",
|
|
316
316
|
themesSafeMode: "This page was opened with ?safe=1: agents' themes are not shown on it.",
|
|
317
317
|
widgetTitle: "Your sidebar widget",
|
|
318
|
-
widgetLead: "A small panel under
|
|
318
|
+
widgetLead: "A small panel under your agent list, written as JSON.",
|
|
319
319
|
widgetNotJson: "Not JSON.",
|
|
320
320
|
widgetSave: "Save widget",
|
|
321
321
|
widgetSaved: "Sidebar widget saved.",
|
|
@@ -323,7 +323,7 @@ register("settings", {
|
|
|
323
323
|
widgetRemove: "Remove widget",
|
|
324
324
|
widgetRemoved: "Sidebar widget removed.",
|
|
325
325
|
modsTitle: "Mods",
|
|
326
|
-
modsLead: "
|
|
326
|
+
modsLead: "Only the parts you tick are applied.",
|
|
327
327
|
modsLoadFailed: "Couldn't load the installed mods. Reload the page to try again.",
|
|
328
328
|
modsNone: "No mods installed.",
|
|
329
329
|
modChoose: "Import a mod file…",
|
|
@@ -360,7 +360,7 @@ register("settings", {
|
|
|
360
360
|
modUninstallConfirm: "Uninstall {0}? Its effects leave your library unless something still uses them. What it applied stays.",
|
|
361
361
|
modUninstalled: "Uninstalled {0}.",
|
|
362
362
|
modExport: "Export a mod",
|
|
363
|
-
modExportLead: "
|
|
363
|
+
modExportLead: "Save what's in force now as a mod file.",
|
|
364
364
|
modExportInstance: "Agent",
|
|
365
365
|
modExportName: "Name (a-z, 0-9, -)",
|
|
366
366
|
modExportVersion: "Version",
|
|
@@ -372,7 +372,7 @@ register("settings", {
|
|
|
372
372
|
modReview: "Review",
|
|
373
373
|
modDismiss: "Dismiss",
|
|
374
374
|
cssTitle: "Custom CSS (yours only)",
|
|
375
|
-
cssLead: "
|
|
375
|
+
cssLead: "Applies to your screens only.",
|
|
376
376
|
cssLoadFailed: "Couldn't load your custom CSS. Reload the page to try again.",
|
|
377
377
|
cssPublicLink: "Custom CSS isn't available on a temporary public link.",
|
|
378
378
|
cssInForce: "In force: {0}",
|
|
@@ -385,15 +385,14 @@ register("settings", {
|
|
|
385
385
|
cssCurrent: "in force",
|
|
386
386
|
cssRestore: "Use this",
|
|
387
387
|
cssAssets: "Assets",
|
|
388
|
-
cssAssetsLead: "
|
|
388
|
+
cssAssetsLead: "{0} of {1} files, {2} in total (at most 1 MiB in all).",
|
|
389
389
|
cssAssetAdd: "Add a picture or font",
|
|
390
390
|
cssAssetCopy: "Copy reference",
|
|
391
391
|
cssCopied: "Copied {0}",
|
|
392
392
|
cssAssetRemove: "Remove",
|
|
393
393
|
cssDeviceTitle: "On this device",
|
|
394
394
|
cssDeviceOff: "Turn off custom CSS on this device",
|
|
395
|
-
|
|
396
|
-
cssSafe: "Is something hidden or broken? Add ?safe=1 to the end of any page's address and it loads without custom CSS.",
|
|
395
|
+
cssSafe: "Something hidden? Add ?safe=1 to the address.",
|
|
397
396
|
cssError_at_rule: "Not saved: {0} isn't allowed.",
|
|
398
397
|
cssError_url: "Not saved: the only url() allowed is url(\"asset:<id>\") for a file in Assets.",
|
|
399
398
|
cssError_unknown_asset: "Not saved: there's no asset {0}. Add it under Assets first.",
|
|
@@ -491,7 +490,6 @@ register("settings", {
|
|
|
491
490
|
discordUserPlaceholder: "your Discord user id",
|
|
492
491
|
telegramUserPlaceholder: "your Telegram user id",
|
|
493
492
|
bindingApplyButton: "Rebind",
|
|
494
|
-
webEchoEnable: "Turn on web echo",
|
|
495
493
|
help1: "Agents: each agent's settings, Start/Stop, Pause/Wake, and New agent.",
|
|
496
494
|
help2: "Connections: who may use each bot, its binding, its status emojis, a new token; and provider API keys.",
|
|
497
495
|
help3: "ClassicBot: each room's backend, model and options.",
|
|
@@ -535,7 +533,7 @@ register("settings", {
|
|
|
535
533
|
publicTtl: "公開連結分鐘數(1–480)",
|
|
536
534
|
publicProtocol: "Tunnel 協定",
|
|
537
535
|
webEcho: "Web 同步",
|
|
538
|
-
webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord
|
|
536
|
+
webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題。ClassicBot 聊天室也照這個設定,除非該聊天室另外設定。",
|
|
539
537
|
webLogTab: "紀錄分頁:每個 agent 的步驟", webLogTabHint: "在每個 instance 的「紀錄」分頁顯示提示、回覆、工具呼叫與結果,以及 fleet 事件;只在分頁開著時從它自己的對話紀錄讀取。機密值會遮蔽。公開連結也看得到。開啟需 fleet admin 確認。",
|
|
540
538
|
general: "一般設定",
|
|
541
539
|
advanced: "進階",
|
|
@@ -584,7 +582,6 @@ register("settings", {
|
|
|
584
582
|
wake: "喚醒",
|
|
585
583
|
accessMode: "存取模式",
|
|
586
584
|
affected: "受影響 instances",
|
|
587
|
-
webEchoGroupConfirm: "這看起來是群組頻道:開啟後,這個 instance 的每則 web 訊息都會貼到所有頻道成員看得到的地方。確定要開啟 web echo?",
|
|
588
585
|
language: "語言(bot 回覆)",
|
|
589
586
|
defaultBackend: "預設後端",
|
|
590
587
|
defaultModel: "預設模型",
|
|
@@ -785,17 +782,18 @@ register("settings", {
|
|
|
785
782
|
webChat: "網頁聊天",
|
|
786
783
|
sec_web: "網頁",
|
|
787
784
|
sec_appearance: "網頁外觀",
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
785
|
+
groupLook: "外觀", groupLayout: "你的版面", groupCss: "自己寫的樣式", groupMods: "擴充", groupAdvanced: "進階", learnMore: "了解更多:{0}",
|
|
786
|
+
colorTitle: "識別色", colorLead: "單一 agent 的顏色:⋯ 選單 → 顏色…",
|
|
787
|
+
colorPlaces: "顏色顯示的位置", colorSample: "範例 agent", colorOff: "關閉顏色",
|
|
788
|
+
colorOffLead: "已挑選的顏色會保留。",
|
|
789
|
+
restoreTitle: "還原預設值", restoreLead: "把這台主機的外觀改回預設值,會先詢問。",
|
|
790
|
+
restoreConfirm: "會重設這台主機的:是否顯示 agent 的主題與效果、卡片大小與各張卡片自己的大小、你的側欄小工具、顏色顯示的位置、是否關閉顏色;也會關閉你的自訂 CSS(版本會保留)與這台裝置上的 CSS 開關。不變:有人替 agent 挑的顏色、已安裝的 mod、上傳的效果與卡片上限。",
|
|
793
791
|
restoreGo: "還原預設值", restoreDone: "外觀設定已改回預設值。", restoreCssFailed: "設定已改回預設值,但無法關閉你的自訂 CSS:{0}",
|
|
794
792
|
cardSizeTitle: "身分卡",
|
|
795
|
-
cardSizeLead: "
|
|
793
|
+
cardSizeLead: "卡片上的 小/中/大 可單獨設定。",
|
|
796
794
|
cardLimitsTitle: "身分卡上傳限制",
|
|
797
|
-
cardLimitsLead: "
|
|
798
|
-
cardLimitsUnavailable: "
|
|
795
|
+
cardLimitsLead: "留空=預設值。調高上限需管理員確認。",
|
|
796
|
+
cardLimitsUnavailable: "只有已登入的管理者能修改。",
|
|
799
797
|
cardLimit_portrait_max_width: "肖像寬度(px)", cardLimit_portrait_max_height: "肖像高度(px)", cardLimit_portrait_max_kib: "肖像大小(KiB)",
|
|
800
798
|
cardLimit_banner_max_width: "橫幅寬度(px)", cardLimit_banner_max_height: "橫幅高度(px)", cardLimit_banner_max_kib: "橫幅大小(KiB)",
|
|
801
799
|
cardLimit_instance_quota_files: "每個 agent 的圖片數", cardLimit_instance_quota_mib: "每個 agent 的圖片空間(MiB)",
|
|
@@ -807,10 +805,10 @@ register("settings", {
|
|
|
807
805
|
cardLimitsFailed: "未儲存:{0}",
|
|
808
806
|
themesTitle: "Agent 的主題",
|
|
809
807
|
themesShow: "顯示 agent 的主題、效果與小工具",
|
|
810
|
-
themesShowLead: "
|
|
808
|
+
themesShowLead: "關閉時每個聊天看起來都一樣。",
|
|
811
809
|
themesSafeMode: "這個頁面是用 ?safe=1 開啟的:不顯示 agent 的主題。",
|
|
812
810
|
widgetTitle: "你的側邊欄小工具",
|
|
813
|
-
widgetLead: "
|
|
811
|
+
widgetLead: "agent 清單下方的小面板,用 JSON 撰寫。",
|
|
814
812
|
widgetNotJson: "不是 JSON。",
|
|
815
813
|
widgetSave: "儲存小工具",
|
|
816
814
|
widgetSaved: "已儲存側邊欄小工具。",
|
|
@@ -818,7 +816,7 @@ register("settings", {
|
|
|
818
816
|
widgetRemove: "移除小工具",
|
|
819
817
|
widgetRemoved: "已移除側邊欄小工具。",
|
|
820
818
|
modsTitle: "Mod",
|
|
821
|
-
modsLead: "
|
|
819
|
+
modsLead: "只套用你勾選的部分。",
|
|
822
820
|
modsLoadFailed: "無法載入已安裝的 mod。請重新載入頁面再試一次。",
|
|
823
821
|
modsNone: "尚未安裝任何 mod。",
|
|
824
822
|
modChoose: "匯入 mod 檔案…",
|
|
@@ -855,7 +853,7 @@ register("settings", {
|
|
|
855
853
|
modUninstallConfirm: "要解除安裝 {0} 嗎?它的效果會離開你的效果庫,除非還有東西在使用。它已套用的外觀會保留。",
|
|
856
854
|
modUninstalled: "已解除安裝 {0}。",
|
|
857
855
|
modExport: "匯出 mod",
|
|
858
|
-
modExportLead: "
|
|
856
|
+
modExportLead: "把目前生效的外觀存成 mod 檔。",
|
|
859
857
|
modExportInstance: "Agent",
|
|
860
858
|
modExportName: "名稱(a-z、0-9、-)",
|
|
861
859
|
modExportVersion: "版本",
|
|
@@ -867,7 +865,7 @@ register("settings", {
|
|
|
867
865
|
modReview: "檢視",
|
|
868
866
|
modDismiss: "略過",
|
|
869
867
|
cssTitle: "自訂 CSS(只套用在你自己)",
|
|
870
|
-
cssLead: "
|
|
868
|
+
cssLead: "只套用在你的畫面。",
|
|
871
869
|
cssLoadFailed: "無法載入你的自訂 CSS。請重新整理頁面再試一次。",
|
|
872
870
|
cssPublicLink: "臨時公開連結無法使用自訂 CSS。",
|
|
873
871
|
cssInForce: "使用中:{0}",
|
|
@@ -880,15 +878,14 @@ register("settings", {
|
|
|
880
878
|
cssCurrent: "使用中",
|
|
881
879
|
cssRestore: "改用這版",
|
|
882
880
|
cssAssets: "資源",
|
|
883
|
-
cssAssetsLead: "
|
|
881
|
+
cssAssetsLead: "{0} / {1} 個檔案,合計 {2}(全部合計最多 1 MiB)。",
|
|
884
882
|
cssAssetAdd: "加入圖片或字型",
|
|
885
883
|
cssAssetCopy: "複製引用",
|
|
886
884
|
cssCopied: "已複製 {0}",
|
|
887
885
|
cssAssetRemove: "移除",
|
|
888
886
|
cssDeviceTitle: "這台裝置",
|
|
889
887
|
cssDeviceOff: "在這台裝置關閉自訂 CSS",
|
|
890
|
-
|
|
891
|
-
cssSafe: "畫面被藏起來或壞掉了嗎?在任何頁面網址的最後加上 ?safe=1,就會不套用自訂 CSS 地載入。",
|
|
888
|
+
cssSafe: "畫面被藏起來?在網址後加上 ?safe=1。",
|
|
892
889
|
cssError_at_rule: "未儲存:不允許使用 {0}。",
|
|
893
890
|
cssError_url: "未儲存:url() 只能用 url(\"asset:<id>\") 引用「資源」裡的檔案。",
|
|
894
891
|
cssError_unknown_asset: "未儲存:找不到資源 {0}。請先在「資源」加入它。",
|
|
@@ -986,7 +983,6 @@ register("settings", {
|
|
|
986
983
|
discordUserPlaceholder: "你的 Discord 使用者 id",
|
|
987
984
|
telegramUserPlaceholder: "你的 Telegram 使用者 id",
|
|
988
985
|
bindingApplyButton: "改綁",
|
|
989
|
-
webEchoEnable: "開啟網頁轉發",
|
|
990
986
|
help1: "Agent:每個 agent 的設定、啟動/停止、暫停/喚醒,以及新增 agent。",
|
|
991
987
|
help2: "連線:誰可以使用各個 bot、它的綁定、狀態表情、新的 token;以及供應商 API key。",
|
|
992
988
|
help3: "ClassicBot:每個房間的 backend、model 與選項。",
|
|
@@ -60,7 +60,7 @@ export function t(key, ...values) {
|
|
|
60
60
|
|
|
61
61
|
register("app", {
|
|
62
62
|
en: {
|
|
63
|
-
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet overview", view: "View", settings: "Settings", instances: "Instances", newInstance: "New instance",
|
|
63
|
+
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet overview", view: "View", settings: "Settings", instances: "Instances", newInstance: "New instance", newAgent: "New agent",
|
|
64
64
|
collapse: "Hide the sidebar", expand: "Show the sidebar", openMenu: "Open the sidebar", closeMenu: "Close the sidebar",
|
|
65
65
|
resizeSidebar: "Sidebar width", resizeSidebarHint: "Drag to resize · double-click to reset",
|
|
66
66
|
names: "Names", namesNickname: "Nickname first", namesInstance: "Real name first",
|
|
@@ -92,7 +92,7 @@ register("app", {
|
|
|
92
92
|
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed",
|
|
93
93
|
},
|
|
94
94
|
"zh-TW": {
|
|
95
|
-
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance",
|
|
95
|
+
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
96
96
|
collapse: "隱藏側邊欄", expand: "顯示側邊欄", openMenu: "打開側邊欄", closeMenu: "關閉側邊欄",
|
|
97
97
|
resizeSidebar: "側邊欄寬度", resizeSidebarHint: "拖曳調整寬度 · 按兩下恢復預設",
|
|
98
98
|
names: "名稱", namesNickname: "暱稱優先", namesInstance: "實際名稱優先",
|
|
@@ -40,7 +40,7 @@ export const SYNCED = {
|
|
|
40
40
|
"card.sizeByInstance": { ls: "agend_card_sizes", ...json },
|
|
41
41
|
// #1629 r4-4: the person's own sidebar widget ({ spec, data }), drawn by the page's own components.
|
|
42
42
|
"widget.sidebar": { ls: "agend_widget_sidebar", ...json },
|
|
43
|
-
// #1958: where identity colours show by default (
|
|
43
|
+
// #1958: where identity colours show by default (#2056: name, bar and ring unless chosen), and the host's switch to turn them off.
|
|
44
44
|
"color.show": { ls: "agend_color_show", ...json },
|
|
45
45
|
"color.off": { ls: "agend_color_off", toLocal: (v) => (v === true ? "on" : null), fromLocal: (s) => (s === "on" ? true : undefined) },
|
|
46
46
|
};
|
|
@@ -39,6 +39,25 @@ let newInstanceOpener = null;
|
|
|
39
39
|
export function setNewInstanceOpener(fn) { newInstanceOpener = fn; }
|
|
40
40
|
export function requestNewInstance() { if (newInstanceOpener) newInstanceOpener(); }
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* #2074: whether this page's session may make an agent — an admin's (/auth/session's tier); a guest's create is refused.
|
|
44
|
+
* Asked once per page; a session that ends takes the buttons away. A display hint only: the create route decides.
|
|
45
|
+
*/
|
|
46
|
+
export const canCreateStore = createStore({ value: false });
|
|
47
|
+
let canCreateOf = null; // the AgendAuth asked (one per page)
|
|
48
|
+
export function useCanCreate() {
|
|
49
|
+
const s = useStore(canCreateStore);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const auth = typeof window !== "undefined" ? window.AgendAuth : undefined;
|
|
52
|
+
if (!auth || typeof auth.canWrite !== "function" || canCreateOf === auth) return;
|
|
53
|
+
canCreateOf = auth;
|
|
54
|
+
canCreateStore.set({ value: false });
|
|
55
|
+
Promise.resolve(auth.canWrite()).then((v) => { if (canCreateOf === auth && !auth.sessionEnded?.()) canCreateStore.set({ value: v === true }); }, () => {});
|
|
56
|
+
auth.onSessionEnd?.(() => { if (canCreateOf === auth) canCreateStore.set({ value: false }); });
|
|
57
|
+
}, []);
|
|
58
|
+
return s.value;
|
|
59
|
+
}
|
|
60
|
+
|
|
42
61
|
/** An app-level dialog (New instance): rendered by the shell until closed, whatever panel is showing. */
|
|
43
62
|
export function showDialog(Component, props = {}) { shellStore.set({ dialog: { Component, props } }); }
|
|
44
63
|
export function closeDialog() { shellStore.set({ dialog: null }); }
|
|
@@ -247,6 +266,7 @@ export function signInHref() {
|
|
|
247
266
|
function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
248
267
|
const app = useStore(appStore);
|
|
249
268
|
const shell = useStore(shellStore);
|
|
269
|
+
const canCreate = useCanCreate();
|
|
250
270
|
// #1675: the Fleet panel is "Fleet overview"'s (one current row); the "Fleet" row is current on an instance's Details.
|
|
251
271
|
const on = (panel) => !!route && (panel === "fleet" ? route.panel === "details" : route.panel === panel);
|
|
252
272
|
const openInstance = openInstanceOf(route);
|
|
@@ -280,13 +300,13 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
280
300
|
<div class="side-head" data-trust="navigation">
|
|
281
301
|
<a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
|
|
282
302
|
<button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
|
|
283
|
-
<button type="button" class="icon-btn" onClick=${onNewInstance} aria-label=${t("app.newInstance")} title=${t("app.newInstance")}><${Icon} name="plus" /></button>
|
|
284
303
|
</div>
|
|
285
304
|
<nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>
|
|
286
305
|
${overview}
|
|
287
306
|
${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
|
|
288
307
|
${navLink("fleet", openInstance ? detailsPath(openInstance) : "/ui/fleet", "fleet", t("app.fleet"))}
|
|
289
308
|
${navLink("view", "/view", "view", t("app.view"))}
|
|
309
|
+
${canCreate && onNewInstance ? html`<button type="button" class="side-row side-new" onClick=${onNewInstance}><${Icon} name="plus" /><span class="grow">${t("app.newAgent")}</span></button>` : null}
|
|
290
310
|
</nav>
|
|
291
311
|
${shell.side ? html`<${shell.side.Component} />` : html`<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false}
|
|
292
312
|
exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />`}
|
|
@@ -349,9 +369,11 @@ function PrefsPopover() {
|
|
|
349
369
|
*/
|
|
350
370
|
export function PanelHeader({ title, sub, children, headingRef, nav }) {
|
|
351
371
|
const shell = useStore(shellStore);
|
|
372
|
+
const canCreate = useCanCreate() && !!newInstanceOpener;
|
|
352
373
|
return html`<header data-trust="header" class=${`panel-head${shell.collapsed ? " collapsed" : ""}`}>
|
|
353
374
|
<button type="button" id="sbOpen" class="icon-btn sb-open" onClick=${() => (narrow() ? openDrawer() : toggleSidebar())}
|
|
354
375
|
aria-label=${narrow() ? t("app.openMenu") : t("app.expand")} title=${narrow() ? t("app.openMenu") : t("app.expand")} aria-controls="sidebar" aria-expanded=${shell.drawer ? "true" : "false"}><${Icon} name="menu" /></button>
|
|
376
|
+
${canCreate && shell.collapsed ? html`<button type="button" class="icon-btn sb-new" onClick=${requestNewInstance} aria-label=${t("app.newAgent")} title=${t("app.newAgent")}><${Icon} name="plus" /></button>` : null}
|
|
355
377
|
<div class="panel-title"><h1 ref=${headingRef} tabindex="-1">${title}</h1>${sub ? html`<div class="panel-sub">${sub}</div>` : null}</div>
|
|
356
378
|
${nav || null}
|
|
357
379
|
<div class="panel-actions">${children}</div>
|
|
@@ -42,7 +42,18 @@ export function applyStatus(d) {
|
|
|
42
42
|
// #1629: the agents' themes' revision (app-themes.js re-reads them when it moves).
|
|
43
43
|
themesRev: typeof d.themes_rev === "number" ? d.themes_rev : null,
|
|
44
44
|
// #1685: host memory pressure slowing or holding new agents ("elevated" | "critical"), else null.
|
|
45
|
-
hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null
|
|
45
|
+
hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null,
|
|
46
|
+
// #2015: while it lasts, the largest processes in the fleet and whose they are (at most 3; anything else dropped).
|
|
47
|
+
hostMemoryTop: hostMemoryTop(d.host_memory_top) });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** #2015: the status frame's host_memory_top, as the dashboard keeps it: well-formed entries only, at most 3. */
|
|
51
|
+
export function hostMemoryTop(raw) {
|
|
52
|
+
if (!Array.isArray(raw)) return [];
|
|
53
|
+
return raw.slice(0, 3).flatMap(p => p && typeof p.name === "string" && Number.isSafeInteger(p.pid) && Number.isSafeInteger(p.rssBytes) && p.rssBytes >= 0
|
|
54
|
+
&& ["fleet", "tmux", "instance", "other"].includes(p.owner)
|
|
55
|
+
? [{ name: p.name.slice(0, 64), pid: p.pid, rssBytes: p.rssBytes, owner: p.owner, ...(p.owner === "instance" && typeof p.instance === "string" ? { instance: p.instance.slice(0, 128) } : {}) }]
|
|
56
|
+
: []);
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
/** One "activity" event: an instance started or stopped working. */
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
// - suspend()/resume(): the page is leaving (pagehide) / came back from the back-forward cache.
|
|
31
31
|
|
|
32
32
|
// #1218: steps_tick — an instance's transcript moved while a Log watches it (SSE only: a poll page asks the Log itself).
|
|
33
|
-
|
|
33
|
+
// #1918: traffic — a message between instances moved (SSE only: the org canvas reads /ui/traffic when it has no stream).
|
|
34
|
+
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock", "traffic"];
|
|
34
35
|
const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
|
|
35
36
|
const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
|
|
36
37
|
const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
|