@songsid/agend 2.3.1 → 2.3.2-beta.10
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/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/agent-cli.js +21 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +5 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/antigravity-usage-scan.d.ts +58 -0
- package/dist/antigravity-usage-scan.js +257 -0
- package/dist/antigravity-usage-scan.js.map +1 -0
- package/dist/antigravity-usage-worker.d.ts +1 -0
- package/dist/antigravity-usage-worker.js +10 -0
- package/dist/antigravity-usage-worker.js.map +1 -0
- package/dist/auth-api.js +4 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +16 -10
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +7 -1
- package/dist/authority/session-authorizations.js +6 -4
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +19 -6
- package/dist/authority/web-authority.js +22 -8
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +64 -0
- package/dist/backend/kiro-identity.js +101 -0
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro-retired-model.d.ts +62 -0
- package/dist/backend/kiro-retired-model.js +160 -0
- package/dist/backend/kiro-retired-model.js.map +1 -0
- package/dist/backend/kiro.d.ts +71 -2
- package/dist/backend/kiro.js +352 -11
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +59 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-signin-guide.d.ts +1 -0
- package/dist/backend-signin-guide.js +9 -0
- package/dist/backend-signin-guide.js.map +1 -0
- package/dist/backend-signin-pending.d.ts +10 -0
- package/dist/backend-signin-pending.js +44 -0
- package/dist/backend-signin-pending.js.map +1 -0
- package/dist/browser-backend-signins.d.ts +56 -0
- package/dist/browser-backend-signins.js +189 -0
- package/dist/browser-backend-signins.js.map +1 -0
- package/dist/cache-ledger.d.ts +38 -2
- package/dist/cache-ledger.js +133 -8
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-prices.d.ts +2 -1
- package/dist/cache-prices.js +5 -2
- package/dist/cache-prices.js.map +1 -1
- package/dist/cache-service.d.ts +68 -0
- package/dist/cache-service.js +355 -13
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +13 -0
- package/dist/channel/adapters/discord.js +103 -16
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +34 -7
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.js +2 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +11 -0
- package/dist/classic-channel-manager.d.ts +11 -0
- package/dist/classic-channel-manager.js +39 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +21 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +7 -1
- package/dist/config-validator.js +92 -12
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +31 -1
- package/dist/config.js.map +1 -1
- package/dist/cpu-quota.d.ts +23 -0
- package/dist/cpu-quota.js +86 -0
- package/dist/cpu-quota.js.map +1 -0
- package/dist/daemon.d.ts +57 -3
- package/dist/daemon.js +330 -50
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +20 -6
- package/dist/dashboard-permissions.js +58 -9
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/delivery-outbox.d.ts +12 -1
- package/dist/delivery-outbox.js +67 -15
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +11 -1
- package/dist/doctor.js.map +1 -1
- package/dist/event-log.d.ts +5 -0
- package/dist/event-log.js +13 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-manager.d.ts +212 -0
- package/dist/fleet-manager.js +914 -111
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +1 -0
- package/dist/fleet-process-handlers.js +9 -1
- package/dist/fleet-process-handlers.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +9 -0
- package/dist/forged-envelope-scan.js +30 -5
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +28 -5
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +31 -8
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +138 -59
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +145 -61
- package/dist/guest-seen-people.d.ts +38 -0
- package/dist/guest-seen-people.js +78 -0
- package/dist/guest-seen-people.js.map +1 -0
- package/dist/instance-config-impact.js +14 -6
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +20 -0
- package/dist/instance-lifecycle.js +71 -13
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/kiro-db-reader.d.ts +5 -0
- package/dist/kiro-db-reader.js +18 -0
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +2 -0
- package/dist/kiro-engine-status.js +9 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-migrate.d.ts +49 -0
- package/dist/kiro-migrate.js +105 -0
- package/dist/kiro-migrate.js.map +1 -0
- package/dist/kiro-transcript-lane.d.ts +2 -0
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/kiro-transcript-worker.js +1 -0
- package/dist/kiro-transcript-worker.js.map +1 -1
- package/dist/kiro-tui-forensic.d.ts +7 -0
- package/dist/kiro-tui-forensic.js +110 -0
- package/dist/kiro-tui-forensic.js.map +1 -0
- package/dist/kiro-usage-run.d.ts +7 -0
- package/dist/kiro-usage-run.js +39 -0
- package/dist/kiro-usage-run.js.map +1 -0
- package/dist/kiro-usage-scan.d.ts +49 -0
- package/dist/kiro-usage-scan.js +223 -0
- package/dist/kiro-usage-scan.js.map +1 -0
- package/dist/kiro-usage-worker.d.ts +1 -0
- package/dist/kiro-usage-worker.js +10 -0
- package/dist/kiro-usage-worker.js.map +1 -0
- package/dist/kiro-usage.d.ts +58 -0
- package/dist/kiro-usage.js +310 -0
- package/dist/kiro-usage.js.map +1 -0
- package/dist/locale.js +120 -12
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/login-url.d.ts +4 -0
- package/dist/login-url.js +22 -0
- package/dist/login-url.js.map +1 -0
- package/dist/mac-auto-restore.d.ts +117 -0
- package/dist/mac-auto-restore.js +294 -0
- package/dist/mac-auto-restore.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -1
- package/dist/needs-you-hub.js +1 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +8 -2
- package/dist/needs-you.js +6 -0
- package/dist/needs-you.js.map +1 -1
- package/dist/notice-delivery.d.ts +16 -0
- package/dist/notice-delivery.js +35 -0
- package/dist/notice-delivery.js.map +1 -0
- package/dist/office-share-page.d.ts +16 -0
- package/dist/office-share-page.js +85 -0
- package/dist/office-share-page.js.map +1 -0
- package/dist/office-share-service.d.ts +91 -0
- package/dist/office-share-service.js +176 -0
- package/dist/office-share-service.js.map +1 -0
- package/dist/office-share.d.ts +258 -0
- package/dist/office-share.js +549 -0
- package/dist/office-share.js.map +1 -0
- package/dist/opencode-usage-scan.d.ts +28 -0
- package/dist/opencode-usage-scan.js +92 -0
- package/dist/opencode-usage-scan.js.map +1 -0
- package/dist/opencode-usage-worker.d.ts +1 -0
- package/dist/opencode-usage-worker.js +10 -0
- package/dist/opencode-usage-worker.js.map +1 -0
- package/dist/outbound-handlers.js +22 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +28 -2
- package/dist/outbound-schemas.js +29 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +16 -2
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.js +13 -2
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.js +2 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/remote-card-answer.d.ts +83 -0
- package/dist/remote-card-answer.js +208 -0
- package/dist/remote-card-answer.js.map +1 -0
- package/dist/reply-triggers.d.ts +2 -0
- package/dist/reply-triggers.js +3 -0
- package/dist/reply-triggers.js.map +1 -0
- package/dist/settings-api.d.ts +28 -0
- package/dist/settings-api.js +148 -17
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +54 -17
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +12 -3
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +4 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +55 -6
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +9 -0
- package/dist/setup-host.js +127 -6
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-signin-assets.d.ts +2 -0
- package/dist/setup-signin-assets.js +6 -0
- package/dist/setup-signin-assets.js.map +1 -0
- package/dist/setup-wizard.js +2 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/start-attempt.d.ts +9 -5
- package/dist/start-attempt.js +27 -8
- package/dist/start-attempt.js.map +1 -1
- package/dist/start-failure-chat.d.ts +4 -0
- package/dist/start-failure-chat.js +23 -6
- package/dist/start-failure-chat.js.map +1 -1
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +8 -0
- package/dist/start-failure-notice.js.map +1 -1
- package/dist/start-failure.d.ts +25 -0
- package/dist/start-failure.js +75 -2
- package/dist/start-failure.js.map +1 -1
- package/dist/structured-signin-transport.d.ts +8 -0
- package/dist/structured-signin-transport.js +79 -0
- package/dist/structured-signin-transport.js.map +1 -0
- package/dist/structured-signin.d.ts +131 -0
- package/dist/structured-signin.js +388 -0
- package/dist/structured-signin.js.map +1 -0
- package/dist/tool-permissions.js +12 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +6 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +26 -2
- package/dist/transcript-sources.js +103 -40
- package/dist/transcript-sources.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +25 -0
- package/dist/turn-reply-guard.js +111 -12
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +46 -9
- package/dist/ui/backend-signin.js +68 -12
- package/dist/ui/chat-ambient.js +1 -1
- package/dist/ui/chat-effects.js +4 -4
- package/dist/ui/chat-render.js +5 -2
- package/dist/ui/chat-strings.js +4 -4
- package/dist/ui/chat-thread.js +2 -2
- package/dist/ui/first-run.js +2 -2
- package/dist/ui/fleet-canvas-view.js +114 -0
- package/dist/ui/fleet-canvas.js +15 -77
- package/dist/ui/fleet-office-editor.js +94 -14
- package/dist/ui/fleet-office-layout.js +235 -0
- package/dist/ui/fleet-office-model.js +12 -6
- package/dist/ui/fleet-office-overview.js +167 -0
- package/dist/ui/fleet-office-pack.d.ts +44 -0
- package/dist/ui/fleet-office-pack.js +352 -37
- package/dist/ui/fleet-office-skin.js +220 -36
- package/dist/ui/fleet-office-store.js +112 -7
- package/dist/ui/fleet-office-view.js +155 -0
- package/dist/ui/fleet-office-zones.js +264 -42
- package/dist/ui/fleet-office.js +957 -160
- package/dist/ui/fleet-usage.js +26 -21
- package/dist/ui/office-share-dialog.js +145 -0
- package/dist/ui/office-share-page.js +164 -0
- package/dist/ui/panel-chat.js +9 -2
- package/dist/ui/panel-details.js +2 -2
- package/dist/ui/panel-fleet.js +11 -77
- package/dist/ui/panel-log.js +4 -4
- package/dist/ui/panel-needs.js +4 -4
- package/dist/ui/panel-settings.js +608 -167
- package/dist/ui/search-dialog.js +26 -7
- package/dist/ui/settings-appearance.js +82 -29
- package/dist/ui/settings-apply.js +42 -7
- package/dist/ui/settings-dialogs.js +76 -23
- package/dist/ui/settings-draft.js +51 -0
- package/dist/ui/settings-guests.js +255 -79
- package/dist/ui/settings-learn.js +2 -2
- package/dist/ui/settings-model.js +16 -6
- package/dist/ui/settings-registry.js +146 -0
- package/dist/ui/settings-strings.js +116 -44
- package/dist/ui/settings-web-authority.js +34 -23
- package/dist/ui/shared/app-i18n.js +18 -2
- package/dist/ui/shared/app-nav.js +10 -5
- package/dist/ui/shared/app-prefs.js +80 -2
- package/dist/ui/shared/app-route.js +39 -5
- package/dist/ui/shared/app-shell.js +73 -10
- package/dist/ui/shared/app-stream.js +3 -1
- package/dist/ui/shared/app.css +307 -17
- package/dist/ui/shared/app.js +3 -0
- package/dist/ui/shared/effect-stock-trust.js +1 -1
- package/dist/ui/shared/identity-color.js +4 -4
- package/dist/ui/shared/office/cozy.png +0 -0
- package/dist/ui/shared/side-panel.js +95 -0
- package/dist/ui/shared/signin.js +2 -2
- package/dist/ui/shared/ui-dialog.js +6 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/web-authorize.js +13 -12
- package/dist/ui/structured-signin.js +115 -0
- package/dist/usage-report.d.ts +20 -0
- package/dist/usage-report.js +54 -17
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +9 -1
- package/dist/usage-rollup.js +20 -4
- package/dist/usage-rollup.js.map +1 -1
- package/dist/web-api.d.ts +26 -2
- package/dist/web-api.js +361 -5
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +8 -2
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +1 -7
- package/dist/web-backend-login.js +2 -24
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-experimental.d.ts +1 -1
- package/dist/web-experimental.js +1 -1
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-mod-agent.js +2 -2
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-office-acts.d.ts +173 -0
- package/dist/web-office-acts.js +285 -0
- package/dist/web-office-acts.js.map +1 -0
- package/dist/web-office-skins.d.ts +109 -0
- package/dist/web-office-skins.js +299 -0
- package/dist/web-office-skins.js.map +1 -0
- package/dist/web-office-store.d.ts +8 -2
- package/dist/web-office-store.js +77 -14
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +8 -1
- package/dist/web-settings-patch.js +65 -5
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -2
- package/dist/web-shell-routes.js +17 -7
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/working-recovery.d.ts +104 -0
- package/dist/working-recovery.js +298 -0
- package/dist/working-recovery.js.map +1 -0
- package/dist/working-state-journal.d.ts +5 -1
- package/dist/working-state-journal.js +31 -3
- package/dist/working-state-journal.js.map +1 -1
- package/package.json +3 -2
- package/templates/windows-shortcuts.ps1 +155 -140
package/dist/ui/search-dialog.js
CHANGED
|
@@ -11,9 +11,12 @@ import { navigate } from "/assets/app-nav.js";
|
|
|
11
11
|
import { chatPath, fleetPath } from "/assets/app-route.js";
|
|
12
12
|
import { namesOf, namesStore } from "/assets/instance-nav.js";
|
|
13
13
|
import { Icon } from "/assets/ui-icons.js";
|
|
14
|
+
import { goToSetting, searchSettings, settingLabel } from "./settings-registry.js";
|
|
15
|
+
import "./settings-strings.js";
|
|
14
16
|
|
|
15
17
|
register("search", {
|
|
16
18
|
en: {
|
|
19
|
+
settingsGroup: "Settings", settingsWhere: "Settings › {0}",
|
|
17
20
|
label: "Search", placeholder: "Search chats, messages and tasks…", close: "Close", filters: "Filters", filtersOn: "Filters ({0})",
|
|
18
21
|
hint: "Find who you asked about something: a word or two from the chat, a message between agents or a task. Short words (1–2 characters) work too.",
|
|
19
22
|
recent: "Recent searches", clearRecent: "Clear",
|
|
@@ -32,6 +35,7 @@ register("search", {
|
|
|
32
35
|
notFound: "No longer found — it may have been removed.", from: "{0} → {1}", groupCount: "{0} results",
|
|
33
36
|
},
|
|
34
37
|
"zh-TW": {
|
|
38
|
+
settingsGroup: "設定", settingsWhere: "設定 › {0}",
|
|
35
39
|
label: "搜尋", placeholder: "搜尋聊天、訊息與任務…", close: "關閉", filters: "篩選", filtersOn: "篩選({0})",
|
|
36
40
|
hint: "找回某件事當初交給誰:輸入聊天、agent 之間訊息或任務裡的一兩個詞。1–2 個字的短詞也可以。",
|
|
37
41
|
recent: "最近的搜尋", clearRecent: "清除",
|
|
@@ -142,6 +146,9 @@ export function jumpToMessage(instance, key, w = window) {
|
|
|
142
146
|
|
|
143
147
|
const errorText = (status) => (status === 404 ? t("search.unavailable") : status === 503 ? t("search.busy") : status === 401 ? t("search.signedOut") : t("search.failed"));
|
|
144
148
|
|
|
149
|
+
/** #2347 §6: how many settings the dialog lists above the messages (the Settings page's own search lists them all). */
|
|
150
|
+
const SETTINGS_SHOWN = 5;
|
|
151
|
+
|
|
145
152
|
export function SearchDialog({ preset = {}, onClose }) {
|
|
146
153
|
const ref = useRef(null), input = useRef(null), list = useRef(null);
|
|
147
154
|
const app = useStore(appStore);
|
|
@@ -211,7 +218,9 @@ export function SearchDialog({ preset = {}, onClose }) {
|
|
|
211
218
|
const label = (name) => (byName.has(name) ? namesOf(byName.get(name), names.primary).primary : name);
|
|
212
219
|
// While a new query runs, the last answer stays (dimmed) rather than flashing empty.
|
|
213
220
|
const groups = useMemo(() => groupHits(res.hits || []), [res]);
|
|
214
|
-
|
|
221
|
+
// #2347 §6: the settings matching the query, from the page's own registry (no request), above the messages.
|
|
222
|
+
const settings = useMemo(() => (q.trim() ? searchSettings(q).slice(0, SETTINGS_SHOWN) : []), [q]);
|
|
223
|
+
const flat = useMemo(() => [...settings.map((entry) => ({ setting: entry })), ...flatHits(groups)], [settings, groups]);
|
|
215
224
|
const activeFilters = (f.instance ? 1 : 0) + (f.team ? 1 : 0) + (f.since !== "any" ? 1 : 0) + (f.sources.length < SOURCES.length ? 1 : 0) + (f.mine ? 1 : 0);
|
|
216
225
|
|
|
217
226
|
// The active row stays in view.
|
|
@@ -222,6 +231,7 @@ export function SearchDialog({ preset = {}, onClose }) {
|
|
|
222
231
|
|
|
223
232
|
const open = (hit) => {
|
|
224
233
|
if (!hit) return;
|
|
234
|
+
if (hit.setting) { rememberSearch(q); onClose(); goToSetting(hit.setting); return; }
|
|
225
235
|
rememberSearch(q); setRecent(readRecent());
|
|
226
236
|
const key = hit.source === "chat" ? messageKeyOf(hit) : null;
|
|
227
237
|
if (key && hit.live) { onClose(); jumpToMessage(hit.instance, key); return; }
|
|
@@ -286,31 +296,40 @@ export function SearchDialog({ preset = {}, onClose }) {
|
|
|
286
296
|
</div>` : null}
|
|
287
297
|
<div class="search-body" ref=${list}>
|
|
288
298
|
${detail ? html`<${Detail} detail=${detail} q=${q} label=${label} onBack=${() => { setDetail(null); input.current && input.current.focus(); }} onClose=${onClose} />`
|
|
289
|
-
: html`<${Results} q=${q} res=${res} groups=${groups} active=${active} setActive=${setActive} open=${open} label=${label} filtered=${activeFilters > 0}
|
|
299
|
+
: html`<${Results} q=${q} res=${res} groups=${groups} settings=${settings} active=${active} setActive=${setActive} open=${open} label=${label} filtered=${activeFilters > 0}
|
|
290
300
|
recent=${recent} pick=${(s) => { recordEdit(input.current); setQ(s); input.current && input.current.focus(); }} clearRecent=${() => { forgetRecent(); setRecent([]); }} />`}
|
|
291
301
|
</div>
|
|
292
302
|
<div class="search-foot" aria-hidden="true">${t("search.keys")}</div>
|
|
293
303
|
</div></dialog>`;
|
|
294
304
|
}
|
|
295
305
|
|
|
296
|
-
function Results({ q, res, groups, active, setActive, open, label, filtered, recent, pick, clearRecent }) {
|
|
306
|
+
function Results({ q, res, groups, settings = [], active, setActive, open, label, filtered, recent, pick, clearRecent }) {
|
|
297
307
|
if (!q.trim()) {
|
|
298
308
|
return html`<div class="search-empty"><p class="search-hint">${t("search.hint")}</p>
|
|
299
309
|
${recent.length ? html`<div class="search-recent"><div class="search-recent-head"><span>${t("search.recent")}</span>
|
|
300
310
|
<button type="button" class="chip-btn" onClick=${clearRecent}>${t("search.clearRecent")}</button></div>
|
|
301
311
|
<ul>${recent.map(s => html`<li><button type="button" class="search-recent-item" onClick=${() => pick(s)}><${Icon} name="clock" size=${14} /><span>${s}</span></button></li>`)}</ul></div>` : null}</div>`;
|
|
302
312
|
}
|
|
303
|
-
|
|
304
|
-
const
|
|
313
|
+
// #2383 review: the settings are this page's own — shown (and reachable) whatever the message search answered.
|
|
314
|
+
const failed = res.status === "error";
|
|
315
|
+
const hits = failed ? [] : res.hits || [];
|
|
305
316
|
return html`
|
|
306
317
|
${res.building ? html`<p class="search-note" role="status">${t("search.building")}</p>` : null}
|
|
307
318
|
${res.limited ? html`<p class="search-note" role="status">${t("search.limited")}</p>` : null}
|
|
308
319
|
${res.status === "loading" && !hits.length ? html`<p class="search-status" role="status">${t("search.searching")}</p>` : null}
|
|
309
|
-
${
|
|
320
|
+
${failed ? html`<p class="search-status bad" role="alert">${res.error}</p>` : null}
|
|
321
|
+
${res.status === "ok" && !hits.length && !settings.length ? html`<p class="search-status" role="status">${filtered ? t("search.noneFiltered") : t("search.none")}</p>` : null}
|
|
310
322
|
<div id="search-results" role="listbox" aria-label=${t("search.results")} class=${`search-results${res.status === "loading" ? " stale" : ""}`}>
|
|
323
|
+
${settings.length ? html`<div role="group" class="search-group search-settings" aria-label=${t("search.settingsGroup")}>
|
|
324
|
+
<div class="search-group-head" aria-hidden="true"><span>${t("search.settingsGroup")}</span><span class="search-count">${t("search.groupCount", settings.length)}</span></div>
|
|
325
|
+
${settings.map((entry, i) => html`<div id=${`search-opt-${i}`} role="option" aria-selected=${i === active ? "true" : "false"} class=${`search-row${i === active ? " on" : ""}`}
|
|
326
|
+
onMouseMove=${i === active ? undefined : () => setActive(i)} onClick=${() => open({ setting: entry })}>
|
|
327
|
+
<div class="search-row-top"><span class="search-badge setting">${t("search.settingsGroup")}</span><span class="search-who">${t("search.settingsWhere", t(`settings.sec_${entry.section}`))}</span></div>
|
|
328
|
+
<div class="search-snippet">${settingLabel(entry)}${entry.key ? html` <code class="s-find-key">${entry.key}</code>` : null}</div></div>`)}
|
|
329
|
+
</div>` : null}
|
|
311
330
|
${groups.map(g => html`<div role="group" class="search-group" aria-label=${label(g.instance)}>
|
|
312
331
|
<div class="search-group-head" aria-hidden="true"><span>${label(g.instance)}</span><span class="search-count">${t("search.groupCount", g.hits.length)}</span></div>
|
|
313
|
-
${g.hits.map(({ hit, index }) => html`<${Row} hit=${hit} index=${index} on=${index === active} label=${label} onHover=${() => setActive(index)} onOpen=${() => open(hit)} />`)}
|
|
332
|
+
${g.hits.map(({ hit, index }) => html`<${Row} hit=${hit} index=${index + settings.length} on=${index + settings.length === active} label=${label} onHover=${() => setActive(index + settings.length)} onOpen=${() => open(hit)} />`)}
|
|
314
333
|
</div>`)}
|
|
315
334
|
</div>`;
|
|
316
335
|
}
|
|
@@ -16,7 +16,8 @@ import { followsReducedMotion, onMotionChange, setFollowsReducedMotion } from "/
|
|
|
16
16
|
import { CARD_SIZES, cardSizeDefault, cardSizeStore, setCardSizeDefault } from "/assets/identity-card.js";
|
|
17
17
|
import { AgentWidget, checkWidget, fleetBinds, setSidebarWidget, sidebarWidgetRaw, sidebarWidgetStore, widgetProblem } from "/assets/agent-widget.js";
|
|
18
18
|
import { confirmedWrite } from "./settings-confirm.js";
|
|
19
|
-
import { savePref } from "/assets/app-prefs.js";
|
|
19
|
+
import { savePref, withoutHold } from "/assets/app-prefs.js";
|
|
20
|
+
import { DEFAULT_SCHEMA, impactOf, ownChoiceImpact } from "./settings-model.js";
|
|
20
21
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
21
22
|
import { colorsOff, defaultPlaces, identityClasses, identityOf, PLACEMENTS, paintIdentity, setColorsOff, setDefaultPlaces, useIdentityColors } from "/assets/identity-color.js";
|
|
22
23
|
import { CardTitle } from "./settings-learn.js";
|
|
@@ -52,26 +53,67 @@ function refusal(body) {
|
|
|
52
53
|
return known.includes(problem) ? tn(`cssError_${problem}`, detail || "") : tn("cssError_other", problem || "?");
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
/**
|
|
57
|
+
* #2347: in Settings, a change here is saved by the bar's Save like every Settings change. The synced preferences are
|
|
58
|
+
* held by app-prefs while Settings is open (the panel stages them); `stage`/`unstage`/`staged` (the panel's) carry the
|
|
59
|
+
* rest: this device's own switches and the fleet's Canvas Worker switch. Without them (shown on its own) each control
|
|
60
|
+
* saves at once, as before.
|
|
61
|
+
*/
|
|
62
|
+
export function AppearanceSection(props = {}) {
|
|
63
|
+
const part = props.part || "look";
|
|
56
64
|
const publicLink = typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1";
|
|
57
|
-
|
|
65
|
+
// #2347 regrouping: Look (the person's own), this device's switches (in Preferences) and the host-wide cards (in Web
|
|
66
|
+
// dashboard) are drawn where each belongs. None of it is offered over the public link (Look says so).
|
|
67
|
+
if (publicLink) return part === "look" ? html`<section class="card s-appearance"><h3>${tn("cssTitle")}</h3><p class="sub">${tn("cssPublicLink")}</p></section>` : null;
|
|
68
|
+
if (part === "device") return html`<${MotionCard} ...${props} /><${DeviceCard} ...${props} />`;
|
|
69
|
+
if (part === "dashboard") return html`<${AppIconCard} /><${CardLimitsCard} /><${ExperimentalEffectsCard} ...${props} />`;
|
|
58
70
|
const group = (key) => html`<h2 class="s-ap-group">${tn(key)}</h2>`;
|
|
59
|
-
return html`${group("groupLook")}<${ThemesCard}
|
|
71
|
+
return html`${group("groupLook")}<${ThemesCard} ...${props} /><${IdentityColorCard} /><${CardSizeCard} />
|
|
60
72
|
${group("groupLayout")}<${SidebarWidgetCard} />
|
|
61
|
-
${group("groupCss")}<${OwnerCssCard}
|
|
73
|
+
${group("groupCss")}<${OwnerCssCard} />
|
|
62
74
|
${group("groupMods")}<${ModsCard} /><${EffectsCard} />
|
|
63
|
-
|
|
75
|
+
<${RestoreDefaultsCard} ...${props} />`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** #2347: the staged keys of this device's own switches (Restore defaults sets them, so their staged change goes). */
|
|
79
|
+
const DEVICE_CHOICES = ["device:fx-follow-motion", "device:owner-css-off"];
|
|
80
|
+
/**
|
|
81
|
+
* #2347: a switch kept on this device only — shown at once; in Settings staged under `key` with what it was before, so
|
|
82
|
+
* Discard (or leaving Settings) puts that back. Back to that value: no change.
|
|
83
|
+
*/
|
|
84
|
+
function deviceChoice(props, key, label, read, write) {
|
|
85
|
+
return (value) => {
|
|
86
|
+
const prev = props.staged && props.staged.get(key);
|
|
87
|
+
const from = prev ? prev.from : read();
|
|
88
|
+
write(value);
|
|
89
|
+
if (!props.stage) return;
|
|
90
|
+
if (value === from) props.unstage(key);
|
|
91
|
+
else props.stage(key, { label: tn("youDeviceChoice", label), impact: ownChoiceImpact(props.schema), from, local: { commit: () => {}, revert: () => write(from) } }, true);
|
|
92
|
+
};
|
|
64
93
|
}
|
|
65
94
|
|
|
66
95
|
register("experimentalEffects", {
|
|
67
96
|
en: { title: "Experimental: Canvas Worker effects", help: "Enable uploaded Canvas Worker effects. Ambient effects are always available. Saved effects stay intact when this is off.", failed: "Could not change this setting. Try again." },
|
|
68
97
|
"zh-TW": { title: "實驗功能:Canvas Worker 特效", help: "啟用上傳的 Canvas Worker 特效。氛圍特效不受影響;關閉時保留已儲存的特效。", failed: "無法變更此設定,請重試。" },
|
|
69
98
|
});
|
|
70
|
-
|
|
99
|
+
const CANVAS_WORKER = "fleet:experimental.canvas_worker";
|
|
100
|
+
function ExperimentalEffectsCard(props = {}) {
|
|
71
101
|
const enabled = useCanvasWorker(), [writable, setWritable] = useState(false), [busy, setBusy] = useState(false), [failed, setFailed] = useState(false);
|
|
72
102
|
useEffect(() => { let live = true; Promise.resolve(globalThis.AgendAuth?.trialSession?.()).then(value => { if (live) setWritable(value?.localAdmin === true); }, () => {}); return () => { live = false; }; }, []);
|
|
73
103
|
if (!writable) return null;
|
|
104
|
+
// #2347: in Settings it is a fleet change like any other — staged here, written by the bar's Save (this page's switch
|
|
105
|
+
// follows once it applied).
|
|
106
|
+
const pending = props.staged && props.staged.get(CANVAS_WORKER);
|
|
107
|
+
const shown = pending ? pending.draft : enabled;
|
|
108
|
+
const stageIt = (value) => {
|
|
109
|
+
setFailed(false);
|
|
110
|
+
if (value === enabled) { props.unstage(CANVAS_WORKER); return; }
|
|
111
|
+
props.stage(CANVAS_WORKER, { label: t("experimentalEffects.title"), impact: impactOf(props.schema || DEFAULT_SCHEMA, "web.experimental.canvas_worker"), draft: value,
|
|
112
|
+
request: { method: "PUT", url: "/api/settings/fleet/web", body: { experimental: { canvas_worker: value } } },
|
|
113
|
+
onResult: (outcome) => { if (outcome && outcome.status === "applied") appStore.set({ canvasWorker: value }); else if (outcome && outcome.status === "failed") setFailed(true); } }, true);
|
|
114
|
+
};
|
|
74
115
|
const change = async value => {
|
|
116
|
+
if (props.stage) { stageIt(value); return; }
|
|
75
117
|
setBusy(true); setFailed(false);
|
|
76
118
|
try {
|
|
77
119
|
const result = await confirmedWrite("/api/settings/fleet/web", { method: "PUT", body: { experimental: { canvas_worker: value } }, label: t("experimentalEffects.title") });
|
|
@@ -79,7 +121,7 @@ function ExperimentalEffectsCard() {
|
|
|
79
121
|
} catch { setFailed(true); }
|
|
80
122
|
finally { setBusy(false); }
|
|
81
123
|
};
|
|
82
|
-
return html`<section class="card s-appearance s-experimental-effects"><label class="check"><input type="checkbox" checked=${
|
|
124
|
+
return html`<section class="card s-appearance s-experimental-effects"><label class="check"><input type="checkbox" checked=${shown} disabled=${busy} onChange=${event => change(event.target.checked)} /><span>${t("experimentalEffects.title")}</span></label><p class="sub">${t("experimentalEffects.help")}</p>${failed ? html`<p role="alert">${t("experimentalEffects.failed")}</p>` : null}</section>`;
|
|
83
125
|
}
|
|
84
126
|
|
|
85
127
|
/** #2056 B: a sample sidebar row in the host's default colour places, so the choice is seen rather than described. */
|
|
@@ -118,23 +160,27 @@ function IdentityColorCard() {
|
|
|
118
160
|
* fleet's card limits.
|
|
119
161
|
*/
|
|
120
162
|
export async function restoreAppearanceDefaults() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
163
|
+
// #2347: a confirmed action — it saves at once, Settings open or not (nothing it sets stays held).
|
|
164
|
+
withoutHold(() => {
|
|
165
|
+
setThemesShown(true);
|
|
166
|
+
setFollowsReducedMotion(false);
|
|
167
|
+
setCardSizeDefault("m");
|
|
168
|
+
savePref("card.sizeByInstance", null);
|
|
169
|
+
setSidebarWidget(null);
|
|
170
|
+
setDefaultPlaces(null);
|
|
171
|
+
setColorsOff(false);
|
|
172
|
+
setOwnerCssOffHere(false);
|
|
173
|
+
});
|
|
129
174
|
const r = await postJson("/ui/owner-css/restore", { sha: null });
|
|
130
175
|
return r && r.error ? { ok: false, error: r.error } : { ok: true };
|
|
131
176
|
}
|
|
132
|
-
function RestoreDefaultsCard() {
|
|
177
|
+
function RestoreDefaultsCard(props = {}) {
|
|
133
178
|
const [busy, setBusy] = useState(false);
|
|
134
179
|
async function go() {
|
|
135
180
|
if (!(await confirmDialog({ title: tn("restoreTitle"), message: tn("restoreConfirm"), confirmLabel: tn("restoreGo"), danger: true }))) return;
|
|
136
181
|
setBusy(true);
|
|
137
182
|
const r = await restoreAppearanceDefaults();
|
|
183
|
+
if (props.unstage) for (const key of DEVICE_CHOICES) props.unstage(key); // saved by the restore itself
|
|
138
184
|
setBusy(false);
|
|
139
185
|
if (r.ok) toast(tn("restoreDone")); else toast(tn("restoreCssFailed", r.error), false);
|
|
140
186
|
}
|
|
@@ -148,7 +194,7 @@ function RestoreDefaultsCard() {
|
|
|
148
194
|
function CardSizeCard() {
|
|
149
195
|
useStore(cardSizeStore);
|
|
150
196
|
const size = cardSizeDefault();
|
|
151
|
-
return html`<section class="card s-appearance s-synced"><${CardTitle} title=${tn("cardSizeTitle")} topic="cards" />
|
|
197
|
+
return html`<section class="card s-appearance s-synced s-card-size"><${CardTitle} title=${tn("cardSizeTitle")} topic="cards" />
|
|
152
198
|
<div class="card-size" role="group" aria-label=${tn("cardSizeTitle")}>
|
|
153
199
|
${CARD_SIZES.map((s) => html`<button key=${s} type="button" class=${`seg-item${s === size ? " active" : ""}`} aria-pressed=${s === size ? "true" : "false"}
|
|
154
200
|
onClick=${() => setCardSizeDefault(s)}>${t(`card.size${s.toUpperCase()}Name`)}</button>`)}
|
|
@@ -306,7 +352,7 @@ function CardLimitsCard() {
|
|
|
306
352
|
};
|
|
307
353
|
useEffect(() => { load(); }, []);
|
|
308
354
|
if (!view) return null;
|
|
309
|
-
if (view.error) return html`<section class="card s-appearance"><${CardTitle} title=${tn("cardLimitsTitle")} topic="limits" /><p class="sub">${tn("cardLimitsUnavailable")}</p></section>`;
|
|
355
|
+
if (view.error) return html`<section class="card s-appearance s-card-limits"><${CardTitle} title=${tn("cardLimitsTitle")} topic="limits" /><p class="sub">${tn("cardLimitsUnavailable")}</p></section>`;
|
|
310
356
|
const configured = (g, k) => (view.configured && view.configured[g] && typeof view.configured[g][k] === "number" ? view.configured[g][k] : null);
|
|
311
357
|
const save = async () => {
|
|
312
358
|
const body = {};
|
|
@@ -345,16 +391,10 @@ function CardLimitsCard() {
|
|
|
345
391
|
/** #1629 r2 (d): whether this person's screens show agents' themes (and, as they come, effects) — synced. */
|
|
346
392
|
function ThemesCard() {
|
|
347
393
|
const s = useStore(themesStore);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
useEffect(() => onMotionChange(() => setFollow(followsReducedMotion())), []);
|
|
351
|
-
return html`<section class="card s-appearance s-synced"><${CardTitle} title=${tn("themesTitle")} topic="themes" />
|
|
352
|
-
<label class="check"><input type="checkbox" checked=${s.shown} disabled=${safeMode()} onChange=${(e) => setThemesShown(e.target.checked)} />
|
|
394
|
+
return html`<section class="card s-appearance s-synced s-themes"><${CardTitle} title=${tn("themesTitle")} topic="themes" />
|
|
395
|
+
<label class="check"><input id="fx-show-themes" type="checkbox" checked=${s.shown} disabled=${safeMode()} onChange=${(e) => setThemesShown(e.target.checked)} />
|
|
353
396
|
<span>${tn("themesShow")}</span></label>
|
|
354
397
|
<p class="sub">${safeMode() ? tn("themesSafeMode") : tn("themesShowLead")}</p>
|
|
355
|
-
<label class="check"><input type="checkbox" id="fx-follow-reduced-motion" checked=${follow} onChange=${(e) => setFollowsReducedMotion(e.target.checked)} />
|
|
356
|
-
<span>${tn("themesFollowMotion")}</span></label>
|
|
357
|
-
<p class="sub">${tn("themesFollowMotionLead")}</p>
|
|
358
398
|
</section>`;
|
|
359
399
|
}
|
|
360
400
|
|
|
@@ -499,10 +539,23 @@ function OwnerCssCard() {
|
|
|
499
539
|
</section>`;
|
|
500
540
|
}
|
|
501
541
|
|
|
502
|
-
|
|
542
|
+
/** #2117: this device's own switch (not synced): effects play unless it follows the system's reduced-motion setting. */
|
|
543
|
+
function MotionCard(props = {}) {
|
|
544
|
+
const [follow, setFollow] = useState(followsReducedMotion);
|
|
545
|
+
useEffect(() => onMotionChange(() => setFollow(followsReducedMotion())), []);
|
|
546
|
+
const setFollowHere = deviceChoice(props, DEVICE_CHOICES[0], tn("themesFollowMotion"), followsReducedMotion, setFollowsReducedMotion);
|
|
547
|
+
return html`<section class="card s-appearance s-local s-motion"><h3>${tn("motionTitle")}</h3>
|
|
548
|
+
<label class="check"><input type="checkbox" id="fx-follow-reduced-motion" checked=${follow} onChange=${(e) => setFollowHere(e.target.checked)} />
|
|
549
|
+
<span>${tn("themesFollowMotion")}</span></label>
|
|
550
|
+
<p class="sub">${tn("themesFollowMotionLead")}</p>
|
|
551
|
+
</section>`;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function DeviceCard(props = {}) {
|
|
503
555
|
const [off, setOff] = useState(ownerCssOffHere());
|
|
556
|
+
const setOffHere = deviceChoice(props, DEVICE_CHOICES[1], tn("cssDeviceOff"), ownerCssOffHere, (v) => { setOwnerCssOffHere(v); setOff(ownerCssOffHere()); });
|
|
504
557
|
return html`<section class="card s-appearance s-local"><h3>${tn("cssDeviceTitle")}</h3>
|
|
505
|
-
<label class="check"><input type="checkbox" checked=${off} onChange=${(e) =>
|
|
558
|
+
<label class="check"><input id="css-off-here" type="checkbox" checked=${off} onChange=${(e) => setOffHere(e.target.checked)} />
|
|
506
559
|
<span>${tn("cssDeviceOff")}</span></label>
|
|
507
560
|
<p class="sub">${tn("cssSafe")}</p>
|
|
508
561
|
</section>`;
|
|
@@ -13,6 +13,12 @@ import { toast } from "/assets/ui-toast.js";
|
|
|
13
13
|
import "./settings-strings.js";
|
|
14
14
|
import { api, confirmedWrite, newKey, selfConfirmed } from "./settings-confirm.js";
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* #2347 (leader's default, for the user to confirm): a Save that needs AgEnD restarted offers Restart now (its card, and
|
|
18
|
+
* the app-wide banner) and never restarts on its own. true restarts once such a Save settles cleanly.
|
|
19
|
+
*/
|
|
20
|
+
export const AUTO_RESTART_AFTER_SAVE = false;
|
|
21
|
+
|
|
16
22
|
const WATCH_LIMIT_MS = 10 * 60_000;
|
|
17
23
|
const POST_RETRIES = [1000, 2000, 4000];
|
|
18
24
|
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
@@ -26,7 +32,8 @@ function view() {
|
|
|
26
32
|
if (!op) return null;
|
|
27
33
|
return {
|
|
28
34
|
id: op.id, phase: op.phase, error: op.error, job: op.job, lostJob: op.lostJob, restart: op.restart,
|
|
29
|
-
|
|
35
|
+
// stageKey: which staged change a step is (#2367 review: the panel tells that change's section how it went).
|
|
36
|
+
steps: op.steps.map(({ label, impact, status, error, pendingId, note, stageKey }) => ({ label, impact, status, error: error || null, pendingId: pendingId || null, ...(note ? { note } : {}), ...(stageKey ? { stageKey } : {}) })),
|
|
30
37
|
leftover: op.leftover,
|
|
31
38
|
};
|
|
32
39
|
}
|
|
@@ -199,24 +206,29 @@ async function watch(o, id) {
|
|
|
199
206
|
const rows = (current && current.targets) || [];
|
|
200
207
|
const failed = rows.some((r) => r.status === "failed"), restart = rows.some((r) => r.status === "restart-required");
|
|
201
208
|
if (!o.lostJob) toast(t(failed ? "settings.applyPartial" : restart ? "settings.applyRestartNeeded" : "settings.changesApplied"), !(failed || restart));
|
|
209
|
+
if (AUTO_RESTART_AFTER_SAVE && restart && !failed && !o.lostJob && o.restart === "idle") restartFleet();
|
|
202
210
|
}
|
|
203
211
|
|
|
204
212
|
/**
|
|
205
213
|
* A full AgEnD restart for a job that needs one: its own confirmation (the caller's), its own key, one at a time. The
|
|
206
214
|
* job's fleet row moves to "running" on the server; that job is watched again.
|
|
207
215
|
*/
|
|
216
|
+
/** POST /api/settings/restart-fleet for `jobId`, with its own key: { ok, status, body } (a lost answer: status 0). */
|
|
217
|
+
async function postRestart(jobId) {
|
|
218
|
+
const key = newKey("restart");
|
|
219
|
+
try {
|
|
220
|
+
return await api("/api/settings/restart-fleet", { method: "POST", headers: { "Idempotency-Key": key },
|
|
221
|
+
body: JSON.stringify({ job_id: jobId, confirm: "restart-agend", idempotency_key: key }) });
|
|
222
|
+
} catch { return { ok: false, status: 0, body: null }; }
|
|
223
|
+
}
|
|
224
|
+
|
|
208
225
|
export async function restartFleet(forJob) {
|
|
209
226
|
const o = op;
|
|
210
227
|
if (!o || !o.job || o.restart === "busy" || ACTIVE.has(o.phase)) return { ok: false };
|
|
211
228
|
// A confirmation given for one job never restarts for another (the operation was replaced meanwhile).
|
|
212
229
|
if (forJob && (forJob.opId !== o.id || forJob.jobId !== o.job.id)) return { ok: false, stale: true };
|
|
213
230
|
o.restart = "busy"; publish();
|
|
214
|
-
const
|
|
215
|
-
let res;
|
|
216
|
-
try {
|
|
217
|
-
res = await api("/api/settings/restart-fleet", { method: "POST", headers: { "Idempotency-Key": key },
|
|
218
|
-
body: JSON.stringify({ job_id: o.job.id, confirm: "restart-agend", idempotency_key: key }) });
|
|
219
|
-
} catch { res = { ok: false, status: 0, body: null }; }
|
|
231
|
+
const res = await postRestart(o.job.id);
|
|
220
232
|
if (!mine(o)) return res;
|
|
221
233
|
if (!res.ok) { o.restart = "idle"; publish(); return res; }
|
|
222
234
|
toast(t("settings.restartFleetStarted")); // when it is accepted; how it ends is said when it settles
|
|
@@ -229,6 +241,29 @@ export async function restartFleet(forJob) {
|
|
|
229
241
|
return res;
|
|
230
242
|
}
|
|
231
243
|
|
|
244
|
+
/**
|
|
245
|
+
* #2347: Restart now from the app-wide banner, for the newest Save that needs it (`jobId`, the server's pick). The Save
|
|
246
|
+
* in hand when it is that job. Otherwise the restart is asked for first, and only once it is accepted does that job
|
|
247
|
+
* become the operation, so its card and line follow the restart as they follow any other (a refusal leaves the banner
|
|
248
|
+
* as it was). The caller asked first.
|
|
249
|
+
*/
|
|
250
|
+
export async function restartPendingChanges(jobId) {
|
|
251
|
+
if (operationActive()) return { ok: false, busy: true };
|
|
252
|
+
if (op && op.job && op.job.id === jobId) return restartFleet({ opId: op.id, jobId });
|
|
253
|
+
const res = await postRestart(jobId);
|
|
254
|
+
if (!res.ok || operationActive()) return res;
|
|
255
|
+
toast(t("settings.restartFleetStarted"));
|
|
256
|
+
let fresh = null;
|
|
257
|
+
try { fresh = await api(`/api/settings/apply/${encodeURIComponent(jobId)}`); } catch { fresh = null; }
|
|
258
|
+
if (operationActive()) return res;
|
|
259
|
+
const job = fresh && fresh.ok && fresh.body && fresh.body.id ? fresh.body
|
|
260
|
+
: { id: jobId, status: "running", targets: [{ target: "fleet", kind: "restart", status: "running" }] };
|
|
261
|
+
const o = op = { id: ++seq, phase: "watching", error: null, job, lostJob: false, restart: "busy", leftover: [], steps: [] };
|
|
262
|
+
publish();
|
|
263
|
+
try { await watch(o, jobId); } finally { if (mine(o)) { o.restart = "idle"; publish(); } }
|
|
264
|
+
return res;
|
|
265
|
+
}
|
|
266
|
+
|
|
232
267
|
// Leaving while writes or the POST are still to come would lose them: the browser asks first. Once the job exists,
|
|
233
268
|
// a reload re-attaches nothing but loses nothing either (the job runs on the server).
|
|
234
269
|
if (typeof window !== "undefined") {
|
|
@@ -14,6 +14,9 @@ import { api, confirmedWrite, newKey } from "./settings-confirm.js";
|
|
|
14
14
|
import { adminUserIdError, adminUserIdPattern, botHandle, TokenEnvNote, TokenField, verifyBotToken } from "./settings-token.js";
|
|
15
15
|
import { DiscordServerPicker } from "./settings-discord.js";
|
|
16
16
|
import { startOperation } from "./settings-apply.js";
|
|
17
|
+
import { goToTarget } from "./settings-registry.js";
|
|
18
|
+
import { sectionPath } from "/assets/app-route.js";
|
|
19
|
+
import { backendLabel } from "/assets/instance-nav.js";
|
|
17
20
|
import "./settings-strings.js"; // its words, wherever a picker of this file is used (#2072: Fleet's create dialog too)
|
|
18
21
|
import { backendChoices, modelChoices, OTHER_MODEL, useBackendRows, useModelCatalog } from "./settings-catalog.js";
|
|
19
22
|
import {
|
|
@@ -69,18 +72,45 @@ export function ModelSelect({ value, onChange, disabled, id, backend, instance,
|
|
|
69
72
|
value=${value} onInput=${(e) => onChange(e.target.value)} />` : null}</div>`;
|
|
70
73
|
}
|
|
71
74
|
export function Impact({ schema, field }) { return html`<span class="impact">${impactText(impactOf(schema, field))}</span>`; }
|
|
72
|
-
export function Label({ text, schema, field, htmlFor }) {
|
|
73
|
-
return html`<label for=${htmlFor}>${text}${field ? html` <${Impact} schema=${schema} field=${field} />` : null}</label>`;
|
|
75
|
+
export function Label({ text, schema, field, htmlFor, mark }) {
|
|
76
|
+
return html`<label for=${htmlFor}>${text}${mark ? html` ${mark}` : null}${field ? html` <${Impact} schema=${schema} field=${field} />` : null}</label>`;
|
|
74
77
|
}
|
|
78
|
+
/** #2347 §10: the mark of a value nobody set — what is in effect is the built-in default. */
|
|
79
|
+
export function DefaultMark() {
|
|
80
|
+
return html`<span class="tag s-default">${tn("defaultMark")}</span>`;
|
|
81
|
+
}
|
|
82
|
+
/** #2347 §10: what an empty field means — the value in effect, in plain text, and where it comes from (the mark, or why). */
|
|
83
|
+
export function InEffect({ text, why }) {
|
|
84
|
+
return html`<p class="s-effect">${tn("inEffect", text)} ${why ? html`<span class="tag">${why}</span>` : html`<${DefaultMark} />`}</p>`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* #2347 §10: what an inherited field inherits — its value, marked "default" when nobody set it there either — and a
|
|
88
|
+
* link to where it is set (Agent defaults; ClassicBot defaults for a room). `from`: { section, target, label }.
|
|
89
|
+
*/
|
|
90
|
+
export function Inherited({ text, builtin, from }) {
|
|
91
|
+
const go = (e) => { e.preventDefault(); goToTarget(from.section, from.target); };
|
|
92
|
+
return html`<p class="s-inherited">${tn("inheritedValue", text)}${builtin ? html` <${DefaultMark} />` : null}${from
|
|
93
|
+
? html` · <a href=${`${sectionPath(from.section)}${from.target || ""}`} onClick=${go}>${tn(from.label)}</a>` : null}</p>`;
|
|
94
|
+
}
|
|
95
|
+
/** A value as the inherited line says it: on/off, minutes (0 = off), a backend's name; anything else as it is. */
|
|
96
|
+
export function valueText(v, kind) {
|
|
97
|
+
if (typeof v === "boolean") return tn(v ? "valueOn" : "valueOff");
|
|
98
|
+
if (kind === "minutes") return Number(v) === 0 ? tn("valueOff") : tn("minutesValue", v);
|
|
99
|
+
if (kind === "backend") return backendLabel(v);
|
|
100
|
+
return String(v);
|
|
101
|
+
}
|
|
102
|
+
/** Where an agent's inherited setting is set: Agent defaults, at its field. */
|
|
103
|
+
export const inAgentDefaults = (target) => ({ section: "agent-defaults", target, label: "changeInDefaults" });
|
|
75
104
|
export function Feedback({ error, warning }) {
|
|
76
105
|
if (!error && !warning) return null;
|
|
77
106
|
return html`<p class=${`feedback${error ? " error" : " warning"}`} role=${error ? "alert" : undefined}>${error ? tn(error) : tn(warning)}</p>`;
|
|
78
107
|
}
|
|
79
108
|
/** An override of a default: the control, and "Inherit from defaults" beside it (on: the control shows the default). */
|
|
80
|
-
export function Override({ inherit, onInherit, schema, field, children }) {
|
|
109
|
+
export function Override({ inherit, onInherit, schema, field, inherited, children }) {
|
|
81
110
|
return html`<div class="override">${children}
|
|
82
111
|
<label class="check inherit-row"><input type="checkbox" checked=${inherit} onChange=${(e) => onInherit(e.target.checked)} /><span>${tn("inheritDefault")}</span>
|
|
83
|
-
${field ? html`<${Impact} schema=${schema} field=${field} />` : null}</label
|
|
112
|
+
${field ? html`<${Impact} schema=${schema} field=${field} />` : null}</label>
|
|
113
|
+
${inherit && inherited ? html`<${Inherited} ...${inherited} />` : null}</div>`;
|
|
84
114
|
}
|
|
85
115
|
export function Drawer({ title, children, open = false }) {
|
|
86
116
|
return html`<details class="drawer" open=${open}><summary>${title}</summary><div class="drawer-body">${children}</div></details>`;
|
|
@@ -253,20 +283,25 @@ export function AgentDialog({ name, inst, ctx, onClose }) {
|
|
|
253
283
|
};
|
|
254
284
|
// What an override shows while it inherits: the default.
|
|
255
285
|
const shown = (k, own, dflt) => (f.inherit[k] ? dflt : own);
|
|
286
|
+
// #2347 §10: …and says so — the value, "default" when Agent defaults do not set it either, and where it is set.
|
|
287
|
+
const dh = defaults.hang_detector || {};
|
|
288
|
+
const inh = (k, value, target, kind, set = hasOwn(defaults, k)) => ({ text: valueText(value, kind), builtin: !set, from: target ? inAgentDefaults(target) : null });
|
|
289
|
+
const inheritedBackend = !inst.backend && f.backend === (defaults.backend || "claude-code");
|
|
256
290
|
const L = (text, field, id) => html`<${Label} text=${text} schema=${schema} field=${field} htmlFor=${id} />`;
|
|
257
291
|
return html`<${EditDialog} title=${ctx.shortName(name, inst)} subtitle=${tn("idLine", name)} onClose=${onClose} onStage=${stage} ready=${ready} impacts=${Object.keys(pending()).map((k) => `instance.${k}`)} schema=${schema}>
|
|
258
292
|
<div class="grid2">
|
|
259
293
|
<div class="field">${L(tn("displayName"), "instance.display_name", "ag-dn")}
|
|
260
|
-
<${Override} inherit=${f.inherit.display_name} onInherit=${setInherit("display_name")}>
|
|
294
|
+
<${Override} inherit=${f.inherit.display_name} onInherit=${setInherit("display_name")} inherited=${inh("display_name", defaults.display_name || name, null, "", !!defaults.display_name)}>
|
|
261
295
|
<input id="ag-dn" type="text" placeholder=${name} disabled=${f.inherit.display_name} value=${shown("display_name", f.display_name, defaults.display_name || "")} onInput=${(e) => set("display_name")(e.target.value)} /></${Override}></div>
|
|
262
296
|
<div class="field">${L(tn("description"), "instance.description", "ag-desc")}<input id="ag-desc" type="text" value=${f.description} onInput=${(e) => set("description")(e.target.value)} /></div>
|
|
263
|
-
<div class="field">${L(tn("backend"), "instance.backend", "ag-be")}<${BackendSelect} id="ag-be" value=${f.backend} onChange=${set("backend")}
|
|
297
|
+
<div class="field">${L(tn("backend"), "instance.backend", "ag-be")}<${BackendSelect} id="ag-be" value=${f.backend} onChange=${set("backend")} />
|
|
298
|
+
${inheritedBackend ? html`<${Inherited} ...${inh("backend", f.backend, "#g-be", "backend")} />` : null}</div>
|
|
264
299
|
<div class="field">${L(tn("model"), "instance.model", "ag-model")}<${ModelSelect} id="ag-model" value=${f.model} onChange=${set("model")}
|
|
265
|
-
backend=${f.backend || defaults.backend || "claude-code"} instance=${name} inherit=${tn("
|
|
300
|
+
backend=${f.backend || defaults.backend || "claude-code"} instance=${name} inherit=${tn("inheritValue", defaults.model || tn("modelCliDefault"))} /></div>
|
|
266
301
|
</div>
|
|
267
302
|
<div class="field">${L(tn("workingDir"), "instance.working_directory", "ag-wd")}<input id="ag-wd" type="text" value=${f.working_directory} onInput=${(e) => set("working_directory")(e.target.value)} /></div>
|
|
268
303
|
<div class="field">${L(`${tn("autoPause")} (${tn("minutes")})`, "instance.auto_pause_after", "ag-auto")}
|
|
269
|
-
<${Override} inherit=${f.inherit.auto_pause_after} onInherit=${setInherit("auto_pause_after")}>
|
|
304
|
+
<${Override} inherit=${f.inherit.auto_pause_after} onInherit=${setInherit("auto_pause_after")} inherited=${inh("auto_pause_after", defaults.auto_pause_after ?? 0, "#g-auto", "minutes")}>
|
|
270
305
|
<input id="ag-auto" type="number" min="0" step="1" placeholder=${tn("zeroDisabled")} class=${errors.auto ? "invalid" : ""} disabled=${f.inherit.auto_pause_after}
|
|
271
306
|
value=${shown("auto_pause_after", f.auto_pause_after, String(defaults.auto_pause_after ?? 0))} onInput=${(e) => set("auto_pause_after")(e.target.value)} /></${Override}>
|
|
272
307
|
<${Feedback} error=${errors.auto} /></div>
|
|
@@ -274,16 +309,18 @@ export function AgentDialog({ name, inst, ctx, onClose }) {
|
|
|
274
309
|
<div class="grid2">
|
|
275
310
|
<div class="field">${L(tn("channelBinding"), "instance.topic_id", "ag-ch")}<${Select} id="ag-ch" value=${f.channel_id} onChange=${set("channel_id")} options=${["", ...ids]} /></div>
|
|
276
311
|
<div class="field">${L(`${tn("hangTimeout")} (${tn("minutes")})`, "instance.hang_detector", "ag-hang")}
|
|
277
|
-
<${Override} inherit=${f.inherit.hang} onInherit=${setInherit("hang")}
|
|
312
|
+
<${Override} inherit=${f.inherit.hang} onInherit=${setInherit("hang")}
|
|
313
|
+
inherited=${inh("hang", dh.timeout_minutes ?? HANG_TIMEOUT_DEFAULT_MINUTES, "#g-hang", "minutes", hasOwn(dh, "timeout_minutes"))}>
|
|
278
314
|
<input id="ag-hang" type="number" min="0.1" step="0.5" class=${errors.hang ? "invalid" : ""} disabled=${f.inherit.hang}
|
|
279
315
|
value=${shown("hang", f.hang, String((defaults.hang_detector && defaults.hang_detector.timeout_minutes) ?? HANG_TIMEOUT_DEFAULT_MINUTES))} onInput=${(e) => set("hang")(e.target.value)} /></${Override}>
|
|
280
316
|
<${Feedback} error=${errors.hang} /></div>
|
|
281
|
-
${[["agent_mode", "agentMode", AGENT_MODES, defaults.agent_mode || "mcp"], ["tool_set", "toolSet", TOOL_SETS, toolSetDefault(defaults, inst, name)],
|
|
282
|
-
["tool_progress", "toolProgress", TOOL_PROGRESS, defaults.tool_progress ?? "off"],
|
|
283
|
-
["cross_instance_visibility", "crossInstanceVisibility", VISIBILITY_MODES, visibilityDefault(defaults)],
|
|
284
|
-
["log_level", "logLevel", LOG_LEVELS, defaults.log_level || "info"]].map(([k, label, opts, dflt]) => html`<div key=${k} class="field">
|
|
317
|
+
${[["agent_mode", "agentMode", AGENT_MODES, defaults.agent_mode || "mcp", "#g-am"], ["tool_set", "toolSet", TOOL_SETS, toolSetDefault(defaults, inst, name), "#g-ts"],
|
|
318
|
+
["tool_progress", "toolProgress", TOOL_PROGRESS, defaults.tool_progress ?? "off", "#g-tp"],
|
|
319
|
+
["cross_instance_visibility", "crossInstanceVisibility", VISIBILITY_MODES, visibilityDefault(defaults), "#g-vis"],
|
|
320
|
+
["log_level", "logLevel", LOG_LEVELS, defaults.log_level || "info", "#g-ll"]].map(([k, label, opts, dflt, target]) => html`<div key=${k} class="field">
|
|
285
321
|
${L(tn(label), `instance.${k}`, `ag-${k}`)}
|
|
286
|
-
<${Override} inherit=${f.inherit[k]} onInherit=${setInherit(k)}
|
|
322
|
+
<${Override} inherit=${f.inherit[k]} onInherit=${setInherit(k)}
|
|
323
|
+
inherited=${inh(k, dflt, target, "", k === "cross_instance_visibility" ? VISIBILITY_MODES.includes(defaults[k]) : hasOwn(defaults, k))}>
|
|
287
324
|
<${Select} id=${`ag-${k}`} value=${shown(k, f[k], dflt)} disabled=${f.inherit[k]} onChange=${set(k)}
|
|
288
325
|
options=${opts.includes(shown(k, f[k], dflt)) || k === "cross_instance_visibility" ? opts : [shown(k, f[k], dflt), ...opts]} /></${Override}>
|
|
289
326
|
${k === "cross_instance_visibility" ? html`<p class="note">${tn("crossInstanceVisibilityHint")}</p>` : null}</div>`)}
|
|
@@ -297,16 +334,17 @@ export function AgentDialog({ name, inst, ctx, onClose }) {
|
|
|
297
334
|
</select></div>`)}
|
|
298
335
|
</fieldset>
|
|
299
336
|
<div class="field">${L(tn("replyCompletionGuard"), "instance.reply_completion_guard")}
|
|
300
|
-
<${Override} inherit=${f.inherit.reply_completion_guard} onInherit=${setInherit("reply_completion_guard")}>
|
|
337
|
+
<${Override} inherit=${f.inherit.reply_completion_guard} onInherit=${setInherit("reply_completion_guard")} inherited=${inh("reply_completion_guard", defaults.reply_completion_guard ?? true, "#g-reply")}>
|
|
301
338
|
<label class="check"><input type="checkbox" disabled=${f.inherit.reply_completion_guard} checked=${shown("reply_completion_guard", f.reply_completion_guard, defaults.reply_completion_guard ?? true)}
|
|
302
339
|
onChange=${(e) => set("reply_completion_guard")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span></label></${Override}>
|
|
303
340
|
<p class="note">${replyHint(f.backend, f.inherit.agent_mode ? defaults.agent_mode || "mcp" : f.agent_mode, kiroUi)}</p></div>
|
|
304
341
|
<div class="field">${L(tn("lightweight"), "instance.lightweight")}
|
|
305
|
-
<${Override} inherit=${f.inherit.lightweight} onInherit=${setInherit("lightweight")}>
|
|
342
|
+
<${Override} inherit=${f.inherit.lightweight} onInherit=${setInherit("lightweight")} inherited=${inh("lightweight", defaults.lightweight ?? false, null)}>
|
|
306
343
|
<label class="check"><input type="checkbox" disabled=${f.inherit.lightweight} checked=${shown("lightweight", f.lightweight, defaults.lightweight ?? false)}
|
|
307
344
|
onChange=${(e) => set("lightweight")(e.target.checked)} /><span>${tn("lightweight")}</span></label></${Override}></div>
|
|
308
345
|
<div class="field">${L(tn("modelFailover"), "instance.model_failover", "ag-fo")}
|
|
309
|
-
<${Override} inherit=${f.inherit.model_failover} onInherit=${setInherit("model_failover")}
|
|
346
|
+
<${Override} inherit=${f.inherit.model_failover} onInherit=${setInherit("model_failover")}
|
|
347
|
+
inherited=${inh("model_failover", (defaults.model_failover && defaults.model_failover[0]) || tn("modelNone"), null, "", !!(defaults.model_failover && defaults.model_failover.length))}>
|
|
310
348
|
<${ModelSelect} id="ag-fo" disabled=${f.inherit.model_failover} backend=${f.backend || defaults.backend || "claude-code"} instance=${name} inherit=${tn("modelNone")}
|
|
311
349
|
value=${shown("model_failover", f.model_failover, (defaults.model_failover && defaults.model_failover[0]) || "")} onChange=${set("model_failover")} /></${Override}>
|
|
312
350
|
<${Feedback} warning=${failoverWarn} /></div>
|
|
@@ -604,6 +642,7 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
604
642
|
const inherited = {
|
|
605
643
|
backend: cd.backend || fd.backend || "claude-code", model: cd.model || fd.model || "",
|
|
606
644
|
auto_pause_after: cd.auto_pause_after ?? fd.auto_pause_after ?? 0, tool_progress: cd.tool_progress ?? fd.tool_progress ?? "off",
|
|
645
|
+
reply_triggers: Boolean(cd.reply_triggers ?? fd.reply_triggers ?? schema.reply_triggers_default),
|
|
607
646
|
reply_completion_guard: cd.reply_completion_guard ?? fd.reply_completion_guard ?? true,
|
|
608
647
|
};
|
|
609
648
|
const c = room;
|
|
@@ -611,8 +650,9 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
611
650
|
backend: c.backend || inherited.backend, model: c.model || "",
|
|
612
651
|
auto_pause_after: String(c.auto_pause_after ?? inherited.auto_pause_after), tool_progress: c.tool_progress ?? inherited.tool_progress,
|
|
613
652
|
reply_completion_guard: c.reply_completion_guard ?? inherited.reply_completion_guard,
|
|
653
|
+
reply_triggers: c.reply_triggers ?? inherited.reply_triggers,
|
|
614
654
|
collab: !!c.collab, web_echo: classicWebEchoEffective(c, fleet), context_lines: String(c.context_lines ?? cd.context_lines ?? 5),
|
|
615
|
-
inherit: { auto_pause_after: !hasOwn(c, "auto_pause_after"), tool_progress: !hasOwn(c, "tool_progress"), reply_completion_guard: !hasOwn(c, "reply_completion_guard") },
|
|
655
|
+
inherit: { reply_triggers: !hasOwn(c, "reply_triggers"), auto_pause_after: !hasOwn(c, "auto_pause_after"), tool_progress: !hasOwn(c, "tool_progress"), reply_completion_guard: !hasOwn(c, "reply_completion_guard") },
|
|
616
656
|
}));
|
|
617
657
|
const set = (k) => (v) => setF((x) => ({ ...x, [k]: v }));
|
|
618
658
|
const setInherit = (k) => (on) => setF((x) => ({ ...x, inherit: { ...x.inherit, [k]: on } }));
|
|
@@ -626,12 +666,14 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
626
666
|
auto_pause_after: f.inherit.auto_pause_after ? null : Number(f.auto_pause_after),
|
|
627
667
|
tool_progress: f.inherit.tool_progress ? null : f.tool_progress,
|
|
628
668
|
reply_completion_guard: f.inherit.reply_completion_guard ? null : f.reply_completion_guard,
|
|
669
|
+
reply_triggers: f.inherit.reply_triggers ? null : f.reply_triggers,
|
|
629
670
|
collab: f.collab, context_lines: Number(f.context_lines), web_echo: f.web_echo,
|
|
630
671
|
}, {
|
|
631
672
|
backend: c.backend || inherited.backend, model: (c.model && c.model.trim()) || null,
|
|
632
673
|
auto_pause_after: hasOwn(c, "auto_pause_after") ? c.auto_pause_after : null,
|
|
633
674
|
tool_progress: hasOwn(c, "tool_progress") ? c.tool_progress : null,
|
|
634
675
|
reply_completion_guard: hasOwn(c, "reply_completion_guard") ? c.reply_completion_guard : null,
|
|
676
|
+
reply_triggers: hasOwn(c, "reply_triggers") ? c.reply_triggers : null,
|
|
635
677
|
collab: !!c.collab, context_lines: c.context_lines ?? cd.context_lines ?? 5, web_echo: classicWebEchoEffective(c, fleet),
|
|
636
678
|
});
|
|
637
679
|
const stage = async () => {
|
|
@@ -642,25 +684,36 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
642
684
|
ctx.stageClassic(c, patch);
|
|
643
685
|
onClose();
|
|
644
686
|
};
|
|
687
|
+
// #2347 §10: what a room inherits, from where — ClassicBot defaults when they set it, else Agent defaults ("default"
|
|
688
|
+
// when neither does) — with a link there.
|
|
689
|
+
const roomInh = (k, kind, classicTarget, agentTarget) => {
|
|
690
|
+
const own = hasOwn(cd, k);
|
|
691
|
+
return { text: valueText(inherited[k], kind), builtin: !own && !hasOwn(fd, k),
|
|
692
|
+
from: own ? { section: "chat", target: classicTarget, label: "changeInClassic" } : inAgentDefaults(agentTarget) };
|
|
693
|
+
};
|
|
645
694
|
const L = (text, field, id) => html`<${Label} text=${text} schema=${schema} field=${field} htmlFor=${id} />`;
|
|
646
695
|
return html`<${EditDialog} title=${c.name || c.instanceName} subtitle=${`${tn("idLine", c.instanceName)} · ${tn(`exec_${runtime.execution}`)}`} onClose=${onClose} onStage=${stage} ready=${ready} impacts=${Object.keys(pending()).map((k) => `classic.${k}`)} schema=${schema}>
|
|
647
696
|
<div class="grid2">
|
|
648
|
-
<div class="field">${L(tn("backend"), "classic.backend", "cl-be")}<${BackendSelect} id="cl-be" value=${f.backend} onChange=${set("backend")}
|
|
697
|
+
<div class="field">${L(tn("backend"), "classic.backend", "cl-be")}<${BackendSelect} id="cl-be" value=${f.backend} onChange=${set("backend")} />
|
|
698
|
+
${!c.backend && f.backend === inherited.backend ? html`<${Inherited} ...${roomInh("backend", "backend", "#g-cbe", "#g-be")} />` : null}</div>
|
|
649
699
|
<div class="field">${L(tn("model"), "classic.model", "cl-model")}<${ModelSelect} id="cl-model" value=${f.model} onChange=${set("model")}
|
|
650
|
-
backend=${f.backend} instance=${c.instanceName} inherit=${
|
|
700
|
+
backend=${f.backend} instance=${c.instanceName} inherit=${tn("inheritValue", inherited.model || tn("modelCliDefault"))} /></div>
|
|
651
701
|
<div class="field">${L(`${tn("autoPause")} (${tn("minutes")})`, "classic.auto_pause_after", "cl-auto")}
|
|
652
|
-
<${Override} inherit=${f.inherit.auto_pause_after} onInherit=${setInherit("auto_pause_after")}>
|
|
702
|
+
<${Override} inherit=${f.inherit.auto_pause_after} onInherit=${setInherit("auto_pause_after")} inherited=${roomInh("auto_pause_after", "minutes", "#classicbot", "#g-auto")}>
|
|
653
703
|
<input id="cl-auto" type="number" min="0" step="1" class=${errors.auto ? "invalid" : ""} disabled=${f.inherit.auto_pause_after}
|
|
654
704
|
value=${f.inherit.auto_pause_after ? String(inherited.auto_pause_after) : f.auto_pause_after} onInput=${(e) => set("auto_pause_after")(e.target.value)} /></${Override}>
|
|
655
705
|
<${Feedback} error=${errors.auto} /></div>
|
|
656
706
|
<div class="field">${L(tn("toolProgress"), "classic.tool_progress", "cl-tp")}
|
|
657
|
-
<${Override} inherit=${f.inherit.tool_progress} onInherit=${setInherit("tool_progress")}>
|
|
707
|
+
<${Override} inherit=${f.inherit.tool_progress} onInherit=${setInherit("tool_progress")} inherited=${roomInh("tool_progress", "", "#g-ctp", "#g-tp")}>
|
|
658
708
|
<${Select} id="cl-tp" disabled=${f.inherit.tool_progress} value=${f.inherit.tool_progress ? inherited.tool_progress : f.tool_progress} onChange=${set("tool_progress")} options=${TOOL_PROGRESS} /></${Override}></div>
|
|
659
709
|
<div class="field">${L(tn("replyCompletionGuard"), "classic.reply_completion_guard")}
|
|
660
|
-
<${Override} inherit=${f.inherit.reply_completion_guard} onInherit=${setInherit("reply_completion_guard")}>
|
|
710
|
+
<${Override} inherit=${f.inherit.reply_completion_guard} onInherit=${setInherit("reply_completion_guard")} inherited=${roomInh("reply_completion_guard", "", "#g-creply", "#g-reply")}>
|
|
661
711
|
<label class="check"><input type="checkbox" disabled=${f.inherit.reply_completion_guard} checked=${f.inherit.reply_completion_guard ? inherited.reply_completion_guard : f.reply_completion_guard}
|
|
662
712
|
onChange=${(e) => set("reply_completion_guard")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span></label></${Override}>
|
|
663
713
|
<p class="note">${replyHint(f.backend, classicMode, fd.kiro_ui)}</p></div>
|
|
714
|
+
<div class="field">${L(tn("replyTriggers"), "classic.reply_triggers")}
|
|
715
|
+
<${Override} inherit=${f.inherit.reply_triggers} onInherit=${setInherit("reply_triggers")} inherited=${roomInh("reply_triggers", "", "#g-creply-triggers", "#g-reply-triggers")}>
|
|
716
|
+
<label class="check"><input type="checkbox" disabled=${f.inherit.reply_triggers} checked=${f.inherit.reply_triggers ? inherited.reply_triggers : f.reply_triggers} onChange=${(e) => set("reply_triggers")(e.target.checked)} /><span>${tn("replyTriggers")}</span></label></${Override}><p class="note">${tn("replyTriggersHint")}</p></div>
|
|
664
717
|
<label class="check"><input type="checkbox" checked=${f.collab} onChange=${(e) => set("collab")(e.target.checked)} /><span>${tn("collabMode")}</span><${Impact} schema=${schema} field="classic.collab" /></label>
|
|
665
718
|
<label class="check"><input type="checkbox" checked=${f.web_echo} onChange=${(e) => set("web_echo")(e.target.checked)} /><span>${tn("webEcho")}</span><${Impact} schema=${schema} field="classic.web_echo" /></label>
|
|
666
719
|
</div>
|