@songsid/agend 2.3.0-beta.21 → 2.3.0-beta.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.zh-TW.md +2 -2
- package/dist/agent-cli.js +4 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +9 -0
- package/dist/agent-endpoint.js +15 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +5 -0
- package/dist/agent-whats-new.js +16 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +7 -0
- package/dist/auth-api.js +10 -3
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/codex-package.d.ts +30 -0
- package/dist/backend/codex-package.js +133 -0
- package/dist/backend/codex-package.js.map +1 -0
- package/dist/backend/codex.d.ts +2 -0
- package/dist/backend/codex.js +9 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +56 -3
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +9 -1
- package/dist/backend/kiro.js +102 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/opencode-permission.js +1 -1
- package/dist/backend/opencode-permission.js.map +1 -1
- package/dist/backend/opencode.js +2 -1
- package/dist/backend/opencode.js.map +1 -1
- package/dist/binary-probe.js +1 -1
- package/dist/bug-report-cli.js +1 -1
- package/dist/bundled-skills.d.ts +7 -3
- package/dist/bundled-skills.js +16 -7
- package/dist/bundled-skills.js.map +1 -1
- package/dist/channel/adapters/discord.js +3 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-server.js +12 -4
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +3 -1
- package/dist/channel/mcp-tools.js +38 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/child-process.d.ts +21 -0
- package/dist/child-process.js +54 -0
- package/dist/child-process.js.map +1 -0
- package/dist/cli.js +167 -182
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +28 -2
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +16 -2
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +14 -0
- package/dist/daemon.js +45 -8
- package/dist/daemon.js.map +1 -1
- package/dist/darwin-memory.js +1 -1
- package/dist/doctor.d.ts +5 -0
- package/dist/doctor.js +42 -0
- package/dist/doctor.js.map +1 -1
- package/dist/export-import.js +1 -1
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +73 -2
- package/dist/fleet-manager.js +400 -33
- package/dist/fleet-manager.js.map +1 -1
- package/dist/full-restart.d.ts +5 -5
- package/dist/full-restart.js +5 -5
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +319 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +529 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +19 -4
- package/dist/general-knowledge/steering/core-rules.md +1 -1
- package/dist/instance-config-impact.js +13 -3
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.js +6 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.js +2 -1
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +137 -10
- package/dist/locale.js.map +1 -1
- package/dist/login-flows.js +1 -1
- package/dist/login-shell.js +3 -1
- package/dist/login-shell.js.map +1 -1
- package/dist/ls-rows.js +1 -1
- package/dist/needs-you-hub.d.ts +98 -1
- package/dist/needs-you-hub.js +313 -44
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +5 -2
- package/dist/needs-you-live.js +6 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +58 -3
- package/dist/needs-you.js +36 -3
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.js +25 -10
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +3 -3
- package/dist/provider-secret-registry.d.ts +5 -3
- package/dist/provider-secret-registry.js +8 -2
- package/dist/provider-secret-registry.js.map +1 -1
- package/dist/public-link-progress.d.ts +12 -1
- package/dist/public-link-progress.js +5 -10
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-tunnel-config.d.ts +11 -0
- package/dist/public-tunnel-config.js +68 -0
- package/dist/public-tunnel-config.js.map +1 -0
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +3 -2
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +13 -2
- package/dist/public-web-link.js +37 -10
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart.js +14 -8
- package/dist/quickstart.js.map +1 -1
- package/dist/resource-report.js +1 -1
- package/dist/scheduler/task-board.d.ts +41 -1
- package/dist/scheduler/task-board.js +150 -4
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/sd-notify.js +2 -1
- package/dist/sd-notify.js.map +1 -1
- package/dist/secret-store.d.ts +2 -0
- package/dist/secret-store.js +21 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-installer.d.ts +69 -0
- package/dist/service-installer.js +181 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +44 -0
- package/dist/service-owner.js +48 -0
- package/dist/service-owner.js.map +1 -0
- package/dist/settings-api.d.ts +5 -0
- package/dist/settings-api.js +32 -10
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +86 -3
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +6 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +2 -0
- package/dist/settings-http-confirmation.js +4 -3
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-request-capability.d.ts +4 -1
- package/dist/settings-request-capability.js +11 -3
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/setup-host.js +1 -1
- package/dist/setup-wizard.js +1 -1
- package/dist/setup-wizard.js.map +1 -1
- package/dist/task-board-summary.d.ts +101 -0
- package/dist/task-board-summary.js +177 -0
- package/dist/task-board-summary.js.map +1 -0
- package/dist/task-board-waker.d.ts +8 -1
- package/dist/task-board-waker.js +15 -6
- package/dist/task-board-waker.js.map +1 -1
- package/dist/tmux-control.js +1 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +5 -1
- package/dist/tmux-exec-helper.js +13 -21
- package/dist/tmux-exec-helper.js.map +1 -1
- package/dist/tmux-manager.js +1 -1
- package/dist/tmux-read.js +1 -1
- package/dist/tmux-read.js.map +1 -1
- package/dist/topic-commands.d.ts +3 -0
- package/dist/topic-commands.js +29 -18
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.js +5 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +2 -0
- package/dist/transcript-sources.js +4 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared-install.js +3 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -16
- package/dist/tunnel/cloudflared.js +65 -13
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +13 -0
- package/dist/tunnel/named-diagnostics.js +52 -0
- package/dist/tunnel/named-diagnostics.js.map +1 -0
- package/dist/tunnel/types.d.ts +2 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/ui/app-effects.js +10 -4
- package/dist/ui/app.html +2 -0
- package/dist/ui/chat-render.js +39 -0
- package/dist/ui/chat-store.js +8 -0
- package/dist/ui/chat-strings.js +5 -2
- package/dist/ui/chat-thread.js +15 -8
- package/dist/ui/effect-trial-offer.js +2 -31
- package/dist/ui/effects-waker.js +2 -70
- package/dist/ui/fleet-canvas.js +14 -6
- package/dist/ui/fleet-route-scene.js +86 -21
- package/dist/ui/fleet-task-card.js +5 -5
- package/dist/ui/fleet-task-common.js +41 -7
- package/dist/ui/fleet-task-work.js +107 -0
- package/dist/ui/fleet-tasks.js +46 -12
- package/dist/ui/fleet-traffic.js +57 -10
- package/dist/ui/icons/icon-192.png +0 -0
- package/dist/ui/icons/icon-512.png +0 -0
- package/dist/ui/image-lightbox.js +39 -1
- package/dist/ui/image-zoom.js +242 -0
- package/dist/ui/panel-chat.js +24 -13
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +6 -2
- package/dist/ui/panel-needs.js +21 -6
- package/dist/ui/panel-settings.js +90 -15
- package/dist/ui/preview-panel.js +2 -1
- package/dist/ui/search-dialog.js +2 -1
- package/dist/ui/settings-appearance.js +159 -9
- package/dist/ui/settings-dialogs.js +33 -17
- package/dist/ui/settings-discord.js +6 -2
- package/dist/ui/settings-guests.js +2 -1
- package/dist/ui/settings-learn.js +1 -0
- package/dist/ui/settings-model.js +2 -11
- package/dist/ui/settings-mods.js +6 -3
- package/dist/ui/settings-strings.js +80 -0
- package/dist/ui/settings-token.js +3 -1
- package/dist/ui/settings-web-authority.js +6 -3
- package/dist/ui/settings-wizard.js +13 -7
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-needs.js +2 -2
- package/dist/ui/shared/app-store.js +2 -2
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +125 -28
- package/dist/ui/shared/app.js +5 -1
- package/dist/ui/shared/effect-app-runtime.js +7 -5
- package/dist/ui/shared/effect-chat-runtime.js +2 -7
- package/dist/ui/shared/effect-cursor.js +3 -2
- package/dist/ui/shared/effect-display-metadata.js +39 -0
- package/dist/ui/shared/effect-registry.js +4 -2
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-trust.js +1 -1
- package/dist/ui/shared/feature-flags.js +127 -0
- package/dist/ui/shared/identity-color.js +6 -3
- package/dist/ui/shared/instance-nav.js +3 -2
- package/dist/ui/shared/text-undo.js +210 -0
- package/dist/ui/shared/ui-dialog.js +4 -3
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/signin.html +2 -0
- package/dist/update-dispatch.js +1 -1
- package/dist/update-launch.d.ts +1 -1
- package/dist/update-launch.js +1 -2
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/providers.js +1 -1
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.js +1 -1
- package/dist/web-api.d.ts +12 -2
- package/dist/web-api.js +266 -18
- package/dist/web-api.js.map +1 -1
- package/dist/web-app-icon-worker.d.ts +1 -0
- package/dist/web-app-icon-worker.js +15 -0
- package/dist/web-app-icon-worker.js.map +1 -0
- package/dist/web-app-icon.d.ts +107 -0
- package/dist/web-app-icon.js +256 -0
- package/dist/web-app-icon.js.map +1 -0
- package/dist/web-appearance-tools.d.ts +1 -0
- package/dist/web-appearance-tools.js +7 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance.d.ts +4 -10
- package/dist/web-appearance.js +4 -3
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-chat-history.d.ts +37 -0
- package/dist/web-chat-history.js +57 -2
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-experimental-http.d.ts +2 -0
- package/dist/web-experimental-http.js +12 -0
- package/dist/web-experimental-http.js.map +1 -0
- package/dist/web-experimental.d.ts +11 -0
- package/dist/web-experimental.js +49 -0
- package/dist/web-experimental.js.map +1 -0
- package/dist/web-guest-access.d.ts +1 -0
- package/dist/web-guest-access.js +11 -3
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-icons.d.ts +33 -1
- package/dist/web-icons.js +83 -11
- package/dist/web-icons.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -0
- package/dist/web-mod-store.js +10 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-png.d.ts +29 -0
- package/dist/web-png.js +321 -0
- package/dist/web-png.js.map +1 -0
- package/dist/web-preview.d.ts +2 -0
- package/dist/web-preview.js +2 -0
- package/dist/web-preview.js.map +1 -1
- package/dist/web-reactions.d.ts +34 -0
- package/dist/web-reactions.js +47 -0
- package/dist/web-reactions.js.map +1 -0
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +5 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +1 -0
- package/dist/web-settings-tools.js +14 -10
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-terminal.js +1 -1
- package/dist/web-theme-store.d.ts +2 -2
- package/dist/web-theme-store.js +6 -3
- package/dist/web-theme-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -13,6 +13,19 @@ register("settings", {
|
|
|
13
13
|
publicLinkHint: "Explicit admin consent on every request. Cloudflare handles TLS; link users have full web-admin access. HTML previews get a second temporary tunnel unless web.preview_on_public_link is false.",
|
|
14
14
|
publicTtl: "Public link minutes (1–480)",
|
|
15
15
|
publicProtocol: "Tunnel protocol",
|
|
16
|
+
namedHostname: "Fixed public hostname (optional)",
|
|
17
|
+
namedOriginPort: "Named tunnel origin port",
|
|
18
|
+
namedHostnameInvalid: "Enter a DNS hostname or HTTPS root URL.",
|
|
19
|
+
namedPortInvalid: "Use an integer port from 1024 to 65535.",
|
|
20
|
+
namedTunnelHint: "Blank hostname uses a quick tunnel. Named routes point to this loopback port. Opening, expiry and sign-in still apply.",
|
|
21
|
+
namedTunnelSetup: "How to set this up",
|
|
22
|
+
namedToken: "Cloudflare connector token",
|
|
23
|
+
namedTokenHint: "Stored privately, never shown again. Format checked locally; Cloudflare credentials and routing are checked when opening. Saving or clearing closes the current public link.",
|
|
24
|
+
namedTokenInvalid: "Paste only the long string that starts with eyJ.",
|
|
25
|
+
namedTokenSet: "Set token",
|
|
26
|
+
namedTokenClear: "Clear token",
|
|
27
|
+
awaitingConfirmation: "Waiting for confirmation.",
|
|
28
|
+
namedTokenSaved: "Token change saved. Reopen the public link.",
|
|
16
29
|
webEcho: "Web echo",
|
|
17
30
|
webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms follow it unless a room sets its own.",
|
|
18
31
|
webUsagePublic: "Usage report over the public link", webUsagePublicHint: "Fleet → Usage (up to 400 days of each agent's tokens, requests, messages and API-equivalent amounts) is offered over the temporary public link too. Off by default; guests never see it. Applies at once.",
|
|
@@ -379,6 +392,33 @@ register("settings", {
|
|
|
379
392
|
modProposedBy: "{0} proposes",
|
|
380
393
|
modReview: "Review",
|
|
381
394
|
modDismiss: "Dismiss",
|
|
395
|
+
appIconTitle: "App icon",
|
|
396
|
+
appIconLead: "Shown on browser tabs and phone home screens. Square, 512\u00a0px or more.",
|
|
397
|
+
appIconCurrent: "The app icon now",
|
|
398
|
+
appIconDefault: "The AgEnD icon (default)",
|
|
399
|
+
appIconCustom: "Your icon",
|
|
400
|
+
appIconPreview: "The new icon",
|
|
401
|
+
appIconChoose: "Choose image…",
|
|
402
|
+
appIconUse: "Use this icon",
|
|
403
|
+
appIconCancel: "Cancel",
|
|
404
|
+
appIconReset: "Restore default",
|
|
405
|
+
appIconSaved: "App icon changed",
|
|
406
|
+
appIconResetDone: "App icon back to the default",
|
|
407
|
+
appIconLow: "Smaller than 512\u00a0px: it is enlarged and may look soft.",
|
|
408
|
+
appIconNotAnImage: "That file could not be read as an image.",
|
|
409
|
+
appIconLoadFailed: "The app icon could not be read.",
|
|
410
|
+
appIconReadOnly: "Only an admin's session can change it.",
|
|
411
|
+
appIconWho: "Anyone who can open this address sees it: no private pictures.",
|
|
412
|
+
appIconIos: "On an iPhone, add the home-screen shortcut again to see a change.",
|
|
413
|
+
appIconError_app_icon_too_large: "The image is too large ({0}).",
|
|
414
|
+
appIconError_app_icon_not_png: "The host takes a PNG ({0}).",
|
|
415
|
+
appIconError_app_icon_unreadable: "The image could not be used: {0}.",
|
|
416
|
+
appIconError_app_icon_admin_only: "Only an admin's session can change the app icon.",
|
|
417
|
+
appIconError_app_icon_needs_a_signed_in_person: "Sign in to change the app icon.",
|
|
418
|
+
appIconError_app_icon_busy: "Another icon is being made; try again in a moment.",
|
|
419
|
+
appIconError_app_icon_superseded: "The icon was reset meanwhile; choose the picture again.",
|
|
420
|
+
appIconError_app_icon_not_reset: "The default could not be restored ({0}).",
|
|
421
|
+
appIconError_other: "The app icon was not changed ({0}).",
|
|
382
422
|
cssTitle: "Custom CSS (yours only)",
|
|
383
423
|
cssLead: "Applies to your screens only.",
|
|
384
424
|
cssLoadFailed: "Couldn't load your custom CSS. Reload the page to try again.",
|
|
@@ -574,6 +614,19 @@ register("settings", {
|
|
|
574
614
|
publicLinkHint: "每次都需管理員明確啟用。Cloudflare 終止 TLS;登入者具有完整網頁管理權限。HTML 預覽會另開一條臨時通道,除非設定 web.preview_on_public_link: false。",
|
|
575
615
|
publicTtl: "公開連結分鐘數(1–480)",
|
|
576
616
|
publicProtocol: "Tunnel 協定",
|
|
617
|
+
namedHostname: "固定公開網域(選用)",
|
|
618
|
+
namedOriginPort: "Named tunnel 本機連接埠",
|
|
619
|
+
namedHostnameInvalid: "請輸入 DNS 網域名稱或 HTTPS 根網址。",
|
|
620
|
+
namedPortInvalid: "請使用 1024 到 65535 的整數連接埠。",
|
|
621
|
+
namedTunnelHint: "網域留空時使用 quick tunnel。Named 路由需指向此本機連接埠;仍須開啟連結,並遵守到期及登入規則。",
|
|
622
|
+
namedTunnelSetup: "設定教學",
|
|
623
|
+
namedToken: "Cloudflare 連接器 token",
|
|
624
|
+
namedTokenHint: "私密儲存,不會讀回。儲存時只檢查格式,開啟時才確認憑證與路由。設定或清除會關閉目前的公開連結。",
|
|
625
|
+
namedTokenInvalid: "請只貼上以 eyJ 開頭的長字串。",
|
|
626
|
+
namedTokenSet: "設定 token",
|
|
627
|
+
namedTokenClear: "清除 token",
|
|
628
|
+
awaitingConfirmation: "等待確認中。",
|
|
629
|
+
namedTokenSaved: "Token 變更已儲存,請重新開啟公開連結。",
|
|
577
630
|
webEcho: "Web 同步",
|
|
578
631
|
webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題。ClassicBot 聊天室也照這個設定,除非該聊天室另外設定。",
|
|
579
632
|
webUsagePublic: "透過公開連結提供用量報告", webUsagePublicHint: "Fleet → 用量(最多 400 天、每個 agent 的 token、請求、訊息與依牌價換算的 API 等值)也會透過臨時公開連結提供。預設關閉;訪客一律看不到。變更立即生效。",
|
|
@@ -914,6 +967,33 @@ register("settings", {
|
|
|
914
967
|
modProposedBy: "{0} 提議",
|
|
915
968
|
modReview: "檢視",
|
|
916
969
|
modDismiss: "略過",
|
|
970
|
+
appIconTitle: "App 圖示",
|
|
971
|
+
appIconLead: "顯示在瀏覽器分頁和手機主畫面。正方形,512\u00a0px 以上。",
|
|
972
|
+
appIconCurrent: "目前的 App 圖示",
|
|
973
|
+
appIconDefault: "AgEnD 圖示(預設)",
|
|
974
|
+
appIconCustom: "你的圖示",
|
|
975
|
+
appIconPreview: "新的圖示",
|
|
976
|
+
appIconChoose: "選擇圖片…",
|
|
977
|
+
appIconUse: "使用這個圖示",
|
|
978
|
+
appIconCancel: "取消",
|
|
979
|
+
appIconReset: "恢復預設",
|
|
980
|
+
appIconSaved: "App 圖示已更換",
|
|
981
|
+
appIconResetDone: "App 圖示已恢復預設",
|
|
982
|
+
appIconLow: "小於 512\u00a0px:會被放大,可能不夠清晰。",
|
|
983
|
+
appIconNotAnImage: "無法把這個檔案讀成圖片。",
|
|
984
|
+
appIconLoadFailed: "讀不到 App 圖示的設定。",
|
|
985
|
+
appIconReadOnly: "只有管理者的 session 能更換。",
|
|
986
|
+
appIconWho: "能打開這個網址的人都看得到:請別用私人照片。",
|
|
987
|
+
appIconIos: "iPhone 主畫面要刪掉捷徑重新加入才會換。",
|
|
988
|
+
appIconError_app_icon_too_large: "圖片太大({0})。",
|
|
989
|
+
appIconError_app_icon_not_png: "主機只接受 PNG({0})。",
|
|
990
|
+
appIconError_app_icon_unreadable: "這張圖無法使用:{0}。",
|
|
991
|
+
appIconError_app_icon_admin_only: "只有管理者的 session 能更換 App 圖示。",
|
|
992
|
+
appIconError_app_icon_needs_a_signed_in_person: "請先登入再更換 App 圖示。",
|
|
993
|
+
appIconError_app_icon_busy: "另一張圖示正在處理中,請稍後再試。",
|
|
994
|
+
appIconError_app_icon_superseded: "圖示剛被恢復成預設,請重新選擇圖片。",
|
|
995
|
+
appIconError_app_icon_not_reset: "無法恢復預設({0})。",
|
|
996
|
+
appIconError_other: "App 圖示沒有更換({0})。",
|
|
917
997
|
cssTitle: "自訂 CSS(只套用在你自己)",
|
|
918
998
|
cssLead: "只套用在你的畫面。",
|
|
919
999
|
cssLoadFailed: "無法載入你的自訂 CSS。請重新整理頁面再試一次。",
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// hands it back — afterwards a connection shows "Token set · @bot".
|
|
6
6
|
import { html, useState } from "/assets/app-html.js";
|
|
7
7
|
import { t } from "/assets/app-i18n.js";
|
|
8
|
+
import { useTypedText } from "/assets/text-undo.js";
|
|
8
9
|
import { Icon } from "/assets/ui-icons.js";
|
|
9
10
|
import { api } from "./settings-confirm.js";
|
|
10
11
|
|
|
@@ -36,10 +37,11 @@ export const botHandle = (username) => (username ? `@${String(username).replace(
|
|
|
36
37
|
*/
|
|
37
38
|
export function TokenField({ id, platform, value, onInput, identity, busy, onVerify, hint }) {
|
|
38
39
|
const [shown, setShown] = useState(false);
|
|
40
|
+
const [text, onText] = useTypedText(value); // #2342: the box keeps what was typed; the parent gets it trimmed
|
|
39
41
|
return html`<div class="field token-field"><label for=${id}>${tn("wizardToken")}</label>
|
|
40
42
|
<div class="token-row">
|
|
41
43
|
<input id=${id} type=${shown ? "text" : "password"} autocomplete="off" autocapitalize="off" spellcheck=${false} disabled=${!!busy}
|
|
42
|
-
placeholder=${platform === "discord" ? "MTA…" : "123456:ABC-DEF…"} value=${
|
|
44
|
+
placeholder=${platform === "discord" ? "MTA…" : "123456:ABC-DEF…"} value=${text} onInput=${(e) => onInput(onText(e.target.value))} />
|
|
43
45
|
<button type="button" class="icon-btn" aria-pressed=${shown ? "true" : "false"} title=${shown ? tn("tokenHide") : tn("tokenShow")}
|
|
44
46
|
aria-label=${shown ? tn("tokenHide") : tn("tokenShow")} onClick=${() => setShown(!shown)}><${Icon} name="eye" size=${16} /></button>
|
|
45
47
|
</div>
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
// them grants anything by itself — a session still needs its account's Confirm in Discord or Telegram).
|
|
6
6
|
import { html, useEffect, useState } from "/assets/app-html.js";
|
|
7
7
|
import { t } from "/assets/app-i18n.js";
|
|
8
|
+
import { useTypedText } from "/assets/text-undo.js";
|
|
8
9
|
import { toast } from "/assets/ui-toast.js";
|
|
9
10
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
10
11
|
import { api } from "./settings-confirm.js";
|
|
11
12
|
import { Feedback } from "./settings-dialogs.js";
|
|
13
|
+
import { DEFAULT_SCHEMA, impactOf } from "./settings-model.js";
|
|
12
14
|
import { resetWebAuthorization } from "/assets/web-authorize.js";
|
|
13
15
|
import "./settings-strings.js";
|
|
14
16
|
|
|
@@ -26,6 +28,8 @@ export function verifiedAuthorityBody(original, f) {
|
|
|
26
28
|
export function WebAuthorityCard({ ctx, staged, disabled = false }) {
|
|
27
29
|
const [overview, setOverview] = useState(null), [failed, setFailed] = useState(false);
|
|
28
30
|
const [original, setOriginal] = useState(null), [f, setF] = useState(null), [msg, setMsg] = useState(null);
|
|
31
|
+
// #2342: the hours box keeps what was typed ("01", "1.50"; its undo history); the form gets the number.
|
|
32
|
+
const [hoursText, onHoursText] = useTypedText(f ? f.hours : null, (v) => (v.trim() === "" ? null : Number(v)));
|
|
29
33
|
const load = async () => {
|
|
30
34
|
// What changes here (a revoke, the switch) changes this browser's own line: the chat reads it again when it shows.
|
|
31
35
|
resetWebAuthorization();
|
|
@@ -46,7 +50,6 @@ export function WebAuthorityCard({ ctx, staged, disabled = false }) {
|
|
|
46
50
|
if (!overview || !f) return card(html`<p class="note">${t("app.loading")}</p>`);
|
|
47
51
|
|
|
48
52
|
const set = (patch) => setF((x) => ({ ...x, ...patch }));
|
|
49
|
-
const hoursText = f.hours === null ? "" : String(f.hours);
|
|
50
53
|
const hoursError = f.hours !== null && (!Number.isFinite(f.hours) || f.hours < overview.hours.min || f.hours > overview.hours.max) ? "vaHoursRange" : "";
|
|
51
54
|
const stuckOff = f.enabled && original.enabled && !overview.state.enabled;
|
|
52
55
|
const warnHosts = !f.loopbackOnly && overview.lanHosts.length > 0;
|
|
@@ -55,7 +58,7 @@ export function WebAuthorityCard({ ctx, staged, disabled = false }) {
|
|
|
55
58
|
const review = () => {
|
|
56
59
|
if (hoursError) return;
|
|
57
60
|
const body = verifiedAuthorityBody(original, f);
|
|
58
|
-
if (body) ctx.stage("verified_authority", { label: tn("vaTitle"), impact: "
|
|
61
|
+
if (body) ctx.stage("verified_authority", { label: tn("vaTitle"), impact: impactOf(ctx.schema || DEFAULT_SCHEMA, "web.verified_authority"), request: { method: "PUT", url: "/api/settings/fleet/web", body: { verified_authority: body } } });
|
|
59
62
|
else if (staged.has("verified_authority")) ctx.unstage("verified_authority");
|
|
60
63
|
setMsg(tn("readyApply"));
|
|
61
64
|
};
|
|
@@ -77,7 +80,7 @@ export function WebAuthorityCard({ ctx, staged, disabled = false }) {
|
|
|
77
80
|
${warnHosts ? html`<p class="note s-va-warn" role="status" id="vaLanWarning">${tn("vaLanWarning", overview.lanHosts.join(", "))}</p>` : null}
|
|
78
81
|
<div class="field"><label for="vaHours">${tn("vaHours", overview.hours.min, overview.hours.max)}</label>
|
|
79
82
|
<input id="vaHours" type="number" min=${overview.hours.min} max=${overview.hours.max} step="any" placeholder=${tn("defaultHours", overview.hours.default)}
|
|
80
|
-
class=${hoursError ? "invalid" : ""} value=${hoursText} onInput=${(e) => set({ hours:
|
|
83
|
+
class=${hoursError ? "invalid" : ""} value=${hoursText} onInput=${(e) => set({ hours: onHoursText(e.target.value) })} />
|
|
81
84
|
<${Feedback} error=${hoursError} /></div>
|
|
82
85
|
<h4>${tn("vaSessionsTitle")}</h4>
|
|
83
86
|
${overview.authorized.length
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
// progress, deadline and restart recovery as every other change.
|
|
5
5
|
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
6
6
|
import { t } from "/assets/app-i18n.js";
|
|
7
|
+
import { useTypedText } from "/assets/text-undo.js";
|
|
7
8
|
import { useLease } from "/assets/app-ctx.js";
|
|
8
9
|
import { Dialog } from "/assets/ui-dialog.js";
|
|
9
10
|
import { api } from "./settings-confirm.js";
|
|
10
11
|
import { startOperation } from "./settings-apply.js";
|
|
11
|
-
import { BACKENDS,
|
|
12
|
+
import { BACKENDS, newConnectionImpact, toYaml } from "./settings-model.js";
|
|
12
13
|
import { Drawer, Select } from "./settings-dialogs.js";
|
|
13
14
|
import { adminUserIdError, adminUserIdPattern, botHandle, TokenEnvNote, TokenField, verifyBotToken } from "./settings-token.js";
|
|
14
15
|
import { DiscordServerPicker } from "./settings-discord.js";
|
|
@@ -26,6 +27,11 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
26
27
|
const bump = () => { rev.current++; };
|
|
27
28
|
const [busy, setBusy] = useState("");
|
|
28
29
|
const [err, setErr] = useState("");
|
|
30
|
+
// #2342: the typed fields keep what was typed (a space in a path, the undo history); the form gets them trimmed.
|
|
31
|
+
const [dirText, onDirText] = useTypedText(w ? w.working_directory : "");
|
|
32
|
+
const [nameText, onNameText] = useTypedText(w ? w.instance_name : "");
|
|
33
|
+
const [userText, onUserText] = useTypedText(w ? w.admin_user_id : "");
|
|
34
|
+
const [groupText, onGroupText] = useTypedText(w ? w.group_id : "");
|
|
29
35
|
useEffect(() => {
|
|
30
36
|
(async () => {
|
|
31
37
|
const env = await api("/api/settings/quickstart/environment").catch(() => null);
|
|
@@ -115,7 +121,7 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
115
121
|
// either if it was taken since, instead of quietly picking another.
|
|
116
122
|
const body = { ...input(), channel_id: w.plan.channel_id, token_env: w.plan.token_env, token_env_generated: true, token: w.token };
|
|
117
123
|
// It writes the connection and the first agent: it costs what a connection change does (the server's schema).
|
|
118
|
-
const handed = startOperation([{ label: tn("wizardTitle"), impact:
|
|
124
|
+
const handed = startOperation([{ label: tn("wizardTitle"), impact: newConnectionImpact(ctx && ctx.schema),
|
|
119
125
|
request: { method: "POST", url: "/api/settings/quickstart/commit", body, sensitive: true } }]);
|
|
120
126
|
if (!handed) { setErr(tn("applyBusyLocal")); return; }
|
|
121
127
|
setW((x) => ({ ...x, token: "" }));
|
|
@@ -134,8 +140,8 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
134
140
|
<p class="note">${tn("wizardAgentExistingNote")}</p></div>` : html`${which}<div class="field"><label for="wz-be">${tn("wizardBackend")}</label>
|
|
135
141
|
<${Select} id="wz-be" value=${w.backend} onChange=${set("backend")} options=${w.env.backends && w.env.backends.length ? w.env.backends : BACKENDS} />
|
|
136
142
|
<p class="note">${w.env.backends && w.env.backends.length ? tn("wizardBackendFound", w.env.backends.join(", ")) : tn("wizardBackendNone")}</p></div>
|
|
137
|
-
<div class="field"><label for="wz-wd">${tn("workingDir")}</label><input id="wz-wd" type="text" placeholder="/home/you/projects/app" value=${
|
|
138
|
-
<div class="field"><label for="wz-name">${agents.length ? tn("wizardAgentNewName") : tn("wizardAgentName")}</label><input id="wz-name" type="text" value=${
|
|
143
|
+
<div class="field"><label for="wz-wd">${tn("workingDir")}</label><input id="wz-wd" type="text" placeholder="/home/you/projects/app" value=${dirText} onInput=${(e) => set("working_directory")(onDirText(e.target.value))} /></div>
|
|
144
|
+
<div class="field"><label for="wz-name">${agents.length ? tn("wizardAgentNewName") : tn("wizardAgentName")}</label><input id="wz-name" type="text" value=${nameText} onInput=${(e) => set("instance_name")(onNameText(e.target.value))} /></div>`;
|
|
139
145
|
} else if (w.step === 2) {
|
|
140
146
|
body = html`<div class="seg-inline" role="group" aria-label=${tn("wizardPlatform")}>
|
|
141
147
|
${["telegram", "discord"].map((p) => html`<button key=${p} type="button" class=${`btn${w.platform === p ? " btn-primary" : ""}`} aria-pressed=${w.platform === p ? "true" : "false"}
|
|
@@ -148,12 +154,12 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
148
154
|
<${DiscordServerPicker} idPrefix="wz" token=${w.identity && w.identity.valid ? w.token : ""} bot=${w.identity && botHandle(w.identity.username)}
|
|
149
155
|
invite=${w.identity && w.identity.invite} portal=${w.identity && w.identity.portal} guilds=${w.guilds} onGuilds=${(g) => setW((x) => ({ ...x, guilds: g }))}
|
|
150
156
|
guild=${w.guild_id} onGuild=${set("guild_id")} channel=${w.general_channel_id} onChannel=${set("general_channel_id")} />
|
|
151
|
-
<div class="field"><label for="wz-user">${tn("wizardAdminUser")}</label><input id="wz-user" type="text" required=${true} inputmode="numeric" pattern=${adminUserIdPattern(w.platform)} placeholder=${tn("discordUserPlaceholder")} value=${
|
|
157
|
+
<div class="field"><label for="wz-user">${tn("wizardAdminUser")}</label><input id="wz-user" type="text" required=${true} inputmode="numeric" pattern=${adminUserIdPattern(w.platform)} placeholder=${tn("discordUserPlaceholder")} value=${userText} onInput=${(e) => set("admin_user_id")(onUserText(e.target.value))} /></div>`
|
|
152
158
|
: html`
|
|
153
|
-
<div class="field"><label for="wz-group">${tn("groupIdField")}</label><input id="wz-group" type="text" placeholder="-1001234567890" value=${
|
|
159
|
+
<div class="field"><label for="wz-group">${tn("groupIdField")}</label><input id="wz-group" type="text" placeholder="-1001234567890" value=${groupText} onInput=${(e) => set("group_id")(onGroupText(e.target.value))} />
|
|
154
160
|
<p class="note">${tn("wizardDetectHint")}</p></div>
|
|
155
161
|
<div class="dlg-inline-actions"><button type="button" class="btn btn-sm" disabled=${!!busy} onClick=${detect}>${tn("wizardDetect")}</button></div>
|
|
156
|
-
<div class="field"><label for="wz-user">${tn("wizardAdminUser")}</label><input id="wz-user" type="text" required=${true} inputmode="numeric" pattern=${adminUserIdPattern(w.platform)} placeholder=${tn("telegramUserPlaceholder")} value=${
|
|
162
|
+
<div class="field"><label for="wz-user">${tn("wizardAdminUser")}</label><input id="wz-user" type="text" required=${true} inputmode="numeric" pattern=${adminUserIdPattern(w.platform)} placeholder=${tn("telegramUserPlaceholder")} value=${userText} onInput=${(e) => set("admin_user_id")(onUserText(e.target.value))} /></div>`}`;
|
|
157
163
|
} else {
|
|
158
164
|
body = !w.plan ? html`<p class="note">${tn("wizardPlanLoading")}</p>` : html`
|
|
159
165
|
<p><strong>${tn("wizardWillWrite")}</strong></p>
|
|
@@ -94,7 +94,7 @@ register("app", {
|
|
|
94
94
|
search: "Search", searchTitle: "Search chats, messages between agents and tasks ({0})",
|
|
95
95
|
confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
|
|
96
96
|
// The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
|
|
97
|
-
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",
|
|
97
|
+
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", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
98
98
|
},
|
|
99
99
|
"zh-TW": {
|
|
100
100
|
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
@@ -129,6 +129,6 @@ register("app", {
|
|
|
129
129
|
needsNav: "等你處理", needsTab: "待處理", needsCount: "{0} 件待處理",
|
|
130
130
|
search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
|
|
131
131
|
confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
|
|
132
|
-
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗",
|
|
132
|
+
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
133
133
|
},
|
|
134
134
|
});
|
|
@@ -77,8 +77,8 @@ export function startNeedsNotifier({ open, env = globalThis } = {}) {
|
|
|
77
77
|
seen.add(item.id);
|
|
78
78
|
if (!notifyOn(env)) return;
|
|
79
79
|
try {
|
|
80
|
-
const n = new env.Notification(item.instance, { body: item.detail ? `${reasonText(item)}: ${item.detail}` : reasonText(item), tag: item.id });
|
|
81
|
-
n.onclick = () => { try { env.focus && env.focus(); } catch { /* ignore */ } if (open) open(item.instance); n.close(); };
|
|
80
|
+
const n = new env.Notification(item.instance || reasonText(item), { body: item.detail ? `${reasonText(item)}: ${item.detail}` : reasonText(item), tag: item.id });
|
|
81
|
+
n.onclick = () => { try { env.focus && env.focus(); } catch { /* ignore */ } if (open && item.instance) open(item.instance); n.close(); };
|
|
82
82
|
} catch { /* a browser that refuses at the last moment: the list still shows it */ }
|
|
83
83
|
};
|
|
84
84
|
const consider = (items) => {
|
|
@@ -24,7 +24,7 @@ export function createStore(initial) {
|
|
|
24
24
|
* (app-stream.js catchUp) — "catching" / "retrying" / "failed" / "ok"; `retryHydration` asks for it again.
|
|
25
25
|
* `connections`: how many chat connections the fleet has (#1519 P7: 0 is web-only — the first-run card); null until known. */
|
|
26
26
|
export const appStore = createStore({ ready: false, instances: [], uptime: 0, exec: {}, awaiting: {}, connection: "connecting", needs: [], connections: null,
|
|
27
|
-
hydration: "none", retryHydration: null });
|
|
27
|
+
hydration: "none", retryHydration: null, canvasWorker: typeof document !== "undefined" && document.body?.dataset.canvasWorker === "1" });
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* #1920 phase 3: this page is a guest's — the server says so on <body> (data-tier="guest"). A guest sees only its own
|
|
@@ -49,7 +49,7 @@ export function applyStatus(d) {
|
|
|
49
49
|
exec[i.name] = (i.execution_state !== undefined ? i.execution_state : i.state) ?? null;
|
|
50
50
|
if (i.state === "awaiting_input") awaiting[i.name] = typeof i.interaction_summary === "string" ? i.interaction_summary : "";
|
|
51
51
|
}
|
|
52
|
-
appStore.set({ ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
|
|
52
|
+
appStore.set({ canvasWorker: d.canvas_worker === true, ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
|
|
53
53
|
connections: typeof d.connections === "number" ? d.connections : null,
|
|
54
54
|
// #1665: the host preferences' revision (app-prefs.js re-reads them when it moves).
|
|
55
55
|
prefsRev: typeof d.prefs_rev === "number" ? d.prefs_rev : null,
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
// org canvas reads /ui/traffic when it has no stream).
|
|
35
35
|
// #2233: backend_login — a dashboard sign-in started, moved or ended (no details: the page reads its own view).
|
|
36
36
|
// tasks — the task board changed: the card numbers a write touched (SSE only: the board reads again when it is shown).
|
|
37
|
-
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks"];
|
|
37
|
+
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "reactions", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks"];
|
|
38
38
|
const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
|
|
39
39
|
const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
|
|
40
40
|
const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
|
|
@@ -128,6 +128,7 @@ export function createStream(opts) {
|
|
|
128
128
|
if (Array.isArray(d.deliveries)) emit("deliveries", d.deliveries);
|
|
129
129
|
if (Array.isArray(d.prompts)) emit("prompts", d.prompts);
|
|
130
130
|
if (Array.isArray(d.reply_buttons)) for (const u of d.reply_buttons) emit("reply_buttons", u); // #1266
|
|
131
|
+
if (Array.isArray(d.reactions)) for (const u of d.reactions) emit("reactions", u); // #2305
|
|
131
132
|
if (Array.isArray(d.needs)) emit("needs", { items: d.needs });
|
|
132
133
|
return true;
|
|
133
134
|
} catch { return false; /* the next tick, or the catch-up's retry, tries again */ }
|
package/dist/ui/shared/app.css
CHANGED
|
@@ -124,6 +124,17 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
124
124
|
.idc.id-bar { position: relative; }
|
|
125
125
|
.idc.id-bar::before { content: ""; position: absolute; left: 0; top: var(--s-2); bottom: var(--s-2); width: 3px; background: var(--id); pointer-events: none; }
|
|
126
126
|
.idc.id-name .inst-name { color: var(--id-name); }
|
|
127
|
+
/* #2330: the same straight bar for every other coloured left edge (a 3px border-left curved into a rounded box's
|
|
128
|
+
corners). `.lbar` is the utility; the places below join its selector list instead of carrying a class. A place sets
|
|
129
|
+
--lbar-color (status variants too) and adds the 3px the border took to its own padding-left, so its text stays put.
|
|
130
|
+
A short box that clips to its corners (.msg-quote) moves the bar in (--lbar-left) and shortens it (--lbar-inset) so
|
|
131
|
+
the corner never cuts its ends round.
|
|
132
|
+
tests/web-left-bar-2330.test.ts keeps a coloured border-left off rounded boxes. */
|
|
133
|
+
.lbar, .reply-bar, .msg-quote, .p-log .log-item.k-error, .p-log .log-item.s-failed, .org-node, .us-basis, .us-partial, .cmd-card.bad, .tb-tile { position: relative; }
|
|
134
|
+
.lbar::before, .reply-bar::before, .msg-quote::before, .p-log .log-item.k-error::before, .p-log .log-item.s-failed::before, .org-node::before,
|
|
135
|
+
.us-basis::before, .us-partial::before, .cmd-card.bad::before, .tb-tile::before {
|
|
136
|
+
content: ""; position: absolute; left: var(--lbar-left, 0); top: var(--lbar-inset, var(--s-2)); bottom: var(--lbar-inset, var(--s-2)); width: 3px;
|
|
137
|
+
background: var(--lbar-color, var(--accent)); pointer-events: none; }
|
|
127
138
|
.idc-swatches, .idc-places { border: 0; padding: 0; margin: 0 0 var(--s-3); display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
128
139
|
.idc-swatches legend, .idc-places legend { font-weight: var(--fw-semibold); margin-bottom: 6px; width: 100%; }
|
|
129
140
|
.idc-swatch { --sw: var(--sw-dark); width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; background: var(--sw); cursor: pointer; padding: 0; }
|
|
@@ -139,6 +150,14 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
139
150
|
.s-ap-group { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); margin: var(--s-4) 0 var(--s-2); }
|
|
140
151
|
.s-ap-group:first-child { margin-top: 0; }
|
|
141
152
|
.s-ap-title { display: flex; align-items: center; gap: var(--s-2); }
|
|
153
|
+
/* #2308: the app icon card — the icon now (home-screen size, and tab size) beside the one chosen, before it is used. */
|
|
154
|
+
.s-app-icon-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s-4); margin: var(--s-2) 0; }
|
|
155
|
+
.s-app-icon-row figure { margin: 0; display: grid; justify-items: center; gap: var(--s-1); }
|
|
156
|
+
.s-app-icon-row figure.s-app-icon-now { grid-template-columns: auto auto; align-items: end; column-gap: var(--s-3); }
|
|
157
|
+
.s-app-icon-row figure.s-app-icon-now figcaption { grid-column: 1 / -1; }
|
|
158
|
+
.s-app-icon-row figcaption { font-size: var(--fs-sm); color: var(--text-2); }
|
|
159
|
+
.s-app-icon-big { width: 96px; height: 96px; border-radius: 22%; border: 1px solid var(--border); background: var(--surface-2); object-fit: cover; }
|
|
160
|
+
.s-app-icon-small { width: 32px; height: 32px; border-radius: 6px; object-fit: cover; }
|
|
142
161
|
/* The fields' placeholders show the defaults: readable, not the browser's faint grey (dark mode). */
|
|
143
162
|
.s-appearance input::placeholder { color: var(--text-3); opacity: 1; }
|
|
144
163
|
/* A card title in Chinese is never upper-cased ("AGENT 的主題"): the small caps are a Latin convention. */
|
|
@@ -284,7 +303,7 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
284
303
|
.p-log .log-item.turn-start { margin-top: var(--s-4); }
|
|
285
304
|
.p-log .log-item.k-user { background: var(--user-bubble); }
|
|
286
305
|
.p-log .log-item.k-turn_end, .p-log .log-item.k-state, .p-log .log-item.k-event { background: transparent; color: var(--text-3); padding-block: 2px; font-size: var(--fs-sm); }
|
|
287
|
-
.p-log .log-item.k-error, .p-log .log-item.s-failed {
|
|
306
|
+
.p-log .log-item.k-error, .p-log .log-item.s-failed { --lbar-color: var(--danger); padding-left: calc(var(--s-3) + 3px); }
|
|
288
307
|
.p-log .log-head { display: flex; align-items: baseline; gap: var(--s-2); min-width: 0; }
|
|
289
308
|
.p-log .log-icon { flex: none; }
|
|
290
309
|
.p-log .log-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -364,6 +383,17 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
364
383
|
.dlg-title { flex: 1; font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
|
|
365
384
|
.dlg-body { padding: var(--s-2) var(--s-5) var(--s-4); overflow-y: auto; display: flex; flex-direction: column; gap: var(--s-3); }
|
|
366
385
|
.dlg-actions { display: flex; justify-content: flex-end; gap: var(--s-2); padding: var(--s-3) var(--s-5) var(--s-5); }
|
|
386
|
+
/* A drawer (ui-dialog.js `drawer`): on a desk, the right edge at full height, the page in view beside it. A phone keeps
|
|
387
|
+
the bottom sheet (the rules below are for 900 px and up only). */
|
|
388
|
+
@media (min-width: 900px) {
|
|
389
|
+
.dlg.dlg-drawer { width: min(620px, 100vw); max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0 0 0 auto; border-radius: 0;
|
|
390
|
+
background: var(--bg); box-shadow: var(--shadow-2); animation: dlg-drawer-in 0.18s var(--ease); }
|
|
391
|
+
.dlg-drawer .dlg-box { height: 100%; max-height: 100dvh; }
|
|
392
|
+
.dlg-drawer .dlg-head { padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5); border-bottom: 1px solid var(--border); }
|
|
393
|
+
.dlg-drawer .dlg-body { flex: 1; padding-top: var(--s-4); padding-bottom: var(--s-8); }
|
|
394
|
+
}
|
|
395
|
+
@keyframes dlg-drawer-in { from { transform: translateX(28px); opacity: 0.6; } }
|
|
396
|
+
@media (prefers-reduced-motion: reduce) { .dlg.dlg-drawer { animation: none; } }
|
|
367
397
|
|
|
368
398
|
/* ── Forms ── */
|
|
369
399
|
.form { display: flex; flex-direction: column; gap: var(--s-3); }
|
|
@@ -495,8 +525,19 @@ html.lb-open .scroller { overflow: hidden; }
|
|
|
495
525
|
.lb { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
|
|
496
526
|
background: rgba(0, 0, 0, 0.95); color: #fff; overflow: hidden; overscroll-behavior: contain; }
|
|
497
527
|
.lb::backdrop { background: rgba(0, 0, 0, 0.6); }
|
|
498
|
-
.lb-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 56px 16px 16px; box-sizing: border-box;
|
|
499
|
-
|
|
528
|
+
.lb-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 56px 16px 16px; box-sizing: border-box;
|
|
529
|
+
overflow: hidden; touch-action: none; }
|
|
530
|
+
/* #2333: the picture at its own size, placed and scaled by a CSSOM transform from its top-left corner (image-zoom.js);
|
|
531
|
+
hidden until it has loaded and been fitted. One that fails to load is shown where the browser puts a broken one. */
|
|
532
|
+
.lb-img { position: absolute; left: 0; top: 0; max-width: none; max-height: none; display: block; transform-origin: 0 0; will-change: transform;
|
|
533
|
+
visibility: hidden; cursor: zoom-in; user-select: none; -webkit-user-select: none; -webkit-user-drag: none; -webkit-touch-callout: none; }
|
|
534
|
+
.lb-img.lb-ready { visibility: visible; }
|
|
535
|
+
.lb-img.lb-err { position: static; max-width: 100%; max-height: 100%; visibility: visible; transform: none; cursor: default; }
|
|
536
|
+
.lb-stage.lb-zoomed .lb-img { cursor: grab; }
|
|
537
|
+
.lb-stage.lb-zoomed .lb-img:active { cursor: grabbing; }
|
|
538
|
+
.lb-zoom { display: inline-flex; align-items: center; gap: 2px; }
|
|
539
|
+
.lb .lb-level { min-width: 4.5em; justify-content: center; color: #fff; background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.3); font-variant-numeric: tabular-nums; }
|
|
540
|
+
.lb .lb-fit-width.on { background: rgba(255, 255, 255, 0.22); }
|
|
500
541
|
.lb-bar { position: absolute; top: 0; left: 0; right: 0; z-index: 1; display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3);
|
|
501
542
|
background: rgba(0, 0, 0, 0.75); }
|
|
502
543
|
.lb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); }
|
|
@@ -633,8 +674,8 @@ img.amb-p { object-fit: contain; }
|
|
|
633
674
|
background: var(--surface); box-shadow: var(--shadow-1); opacity: 0; pointer-events: none; transition: opacity var(--t-fast); }
|
|
634
675
|
.msg:hover > .msg-actions, .msg:focus-within > .msg-actions { opacity: 1; pointer-events: auto; }
|
|
635
676
|
@media (hover: none) { .msg-actions { display: none; } }
|
|
636
|
-
.msg-quote { display: flex; align-items: center; gap: 4px; max-width: 100%; margin: 0 0 4px; padding: 2px var(--s-2); border: 0;
|
|
637
|
-
|
|
677
|
+
.msg-quote { display: flex; align-items: center; gap: 4px; max-width: 100%; margin: 0 0 4px; padding: 2px var(--s-2) 2px calc(var(--s-2) + 3px); border: 0;
|
|
678
|
+
--lbar-color: var(--border-strong, var(--border)); --lbar-inset: 4px; --lbar-left: 2px; border-radius: var(--r-sm); background: transparent; color: var(--text-3);
|
|
638
679
|
font: inherit; font-size: var(--fs-sm); text-align: left; cursor: pointer; overflow: hidden; }
|
|
639
680
|
.msg.user .msg-quote { margin-left: auto; }
|
|
640
681
|
.msg-quote:hover, .msg-quote:focus-visible { color: var(--text-2); background: var(--surface-2); outline: none; }
|
|
@@ -760,8 +801,8 @@ img.amb-p { object-fit: contain; }
|
|
|
760
801
|
.guest-note { margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
|
|
761
802
|
.pending-files { display: flex; flex-wrap: wrap; gap: var(--s-2); padding: var(--s-2) var(--s-2) 0; }
|
|
762
803
|
/* #2272: replying — the bar above the composer (who and what is answered; ✕ / Esc cancels). */
|
|
763
|
-
.reply-bar { display: flex; align-items: center; gap: var(--s-2); min-width: 0; margin: var(--s-2) var(--s-2) 0; padding: 4px var(--s-2) 4px var(--s-3);
|
|
764
|
-
|
|
804
|
+
.reply-bar { display: flex; align-items: center; gap: var(--s-2); min-width: 0; margin: var(--s-2) var(--s-2) 0; padding: 4px var(--s-2) 4px calc(var(--s-3) + 3px);
|
|
805
|
+
--lbar-color: var(--accent); border-radius: var(--r-sm); background: var(--surface-2); font-size: var(--fs-sm); }
|
|
765
806
|
.reply-bar .reply-mark { color: var(--accent); }
|
|
766
807
|
.reply-bar .reply-label { font-weight: var(--fw-semibold); white-space: nowrap; }
|
|
767
808
|
.reply-bar .reply-text { flex: 1; min-width: 0; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -1281,10 +1322,10 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
|
|
|
1281
1322
|
.org-team-head h3 { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-md); font-weight: var(--fw-semibold); overflow-wrap: anywhere; }
|
|
1282
1323
|
.org-team-desc { color: var(--text-2); font-size: var(--fs-sm); overflow-wrap: anywhere; }
|
|
1283
1324
|
.org-team-sub { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-3); font-size: var(--fs-xs); }
|
|
1284
|
-
.org-node { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; padding: var(--s-3); border-radius: var(--r-md); background: var(--surface);
|
|
1285
|
-
.org-node.st-needs, .org-node.st-stuck {
|
|
1286
|
-
.org-node.st-crashed {
|
|
1287
|
-
.org-node.st-working {
|
|
1325
|
+
.org-node { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; padding: var(--s-3) var(--s-3) var(--s-3) calc(var(--s-3) + 3px); border-radius: var(--r-md); background: var(--surface); --lbar-color: transparent; }
|
|
1326
|
+
.org-node.st-needs, .org-node.st-stuck { --lbar-color: var(--warn); }
|
|
1327
|
+
.org-node.st-crashed { --lbar-color: var(--danger); }
|
|
1328
|
+
.org-node.st-working { --lbar-color: var(--ok); }
|
|
1288
1329
|
.org-node.st-missing { opacity: 0.7; }
|
|
1289
1330
|
.org-node-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
|
|
1290
1331
|
.org-names { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
@@ -1377,16 +1418,17 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1377
1418
|
.oc { --fx-task: #b794f6; --fx-send: #2dd4bf; --fx-report: #f472b6; --fx-broadcast: #fb923c; --fx-team: #cbd5e1; }
|
|
1378
1419
|
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .oc { --fx-task: #7c3aed; --fx-send: #0f766e; --fx-report: #be185d; --fx-broadcast: #c2410c; --fx-team: #475569; } }
|
|
1379
1420
|
:root[data-theme="light"] .oc { --fx-task: #7c3aed; --fx-send: #0f766e; --fx-report: #be185d; --fx-broadcast: #c2410c; --fx-team: #475569; }
|
|
1380
|
-
|
|
1421
|
+
/* #2329: a line's stroke width is its own attribute (fleet-traffic.js strokeOf): its head and its trimmed ends are sized from it. */
|
|
1422
|
+
.oc-flow { fill: none; stroke-linecap: round; }
|
|
1381
1423
|
.oc-flow-halo { fill: none; stroke: var(--bg); stroke-width: 6; stroke-linecap: round; opacity: 0.85; }
|
|
1382
1424
|
.oc-flow.h-task { stroke: var(--fx-task); } .oc-flow.h-send { stroke: var(--fx-send); } .oc-flow.h-report { stroke: var(--fx-report); }
|
|
1383
|
-
.oc-flow.h-broadcast { stroke: var(--fx-broadcast); } .oc-flow.h-team { stroke: var(--fx-team);
|
|
1425
|
+
.oc-flow.h-broadcast { stroke: var(--fx-broadcast); } .oc-flow.h-team { stroke: var(--fx-team); }
|
|
1384
1426
|
.oc-flow.ph-live { stroke-dasharray: 7 6; animation: oc-dash 0.9s linear infinite; }
|
|
1385
1427
|
.oc-flow.ph-queued { stroke-dasharray: 2 5; opacity: 0.8; }
|
|
1386
1428
|
.oc-flow.ph-fading { stroke: var(--text-3); animation: oc-fade 12s ease-out forwards; }
|
|
1387
1429
|
/* #1918 review: the work — a delegation in progress (a slow dash, kept until its report), its report coming back, none. */
|
|
1388
|
-
.oc-flow.ph-work { stroke-dasharray: 10 7;
|
|
1389
|
-
.oc-flow.ph-return {
|
|
1430
|
+
.oc-flow.ph-work { stroke-dasharray: 10 7; animation: oc-dash 2.4s linear infinite; }
|
|
1431
|
+
.oc-flow.ph-return { animation: oc-fade 2.4s ease-out forwards; }
|
|
1390
1432
|
.oc-flow.ph-stale { stroke: var(--text-3); stroke-dasharray: 3 6; animation: oc-fade 12s ease-out forwards; }
|
|
1391
1433
|
.oc-ah.h-task { fill: var(--fx-task); } .oc-ah.h-send { fill: var(--fx-send); } .oc-ah.h-report { fill: var(--fx-report); }
|
|
1392
1434
|
.oc-ah.h-broadcast { fill: var(--fx-broadcast); } .oc-ah.h-team { fill: var(--fx-team); } .oc-ah.h-fading { fill: var(--text-3); }
|
|
@@ -1483,9 +1525,9 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1483
1525
|
.us-csv { margin-left: auto; }
|
|
1484
1526
|
.us-custom { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s-2) var(--s-3); font-size: var(--fs-sm); }
|
|
1485
1527
|
.us-custom label { display: inline-flex; flex-direction: column; gap: 2px; color: var(--text-2); }
|
|
1486
|
-
.us-basis { font-size: var(--fs-sm); color: var(--text); padding: var(--s-2) var(--s-3)
|
|
1528
|
+
.us-basis { font-size: var(--fs-sm); color: var(--text); padding: var(--s-2) var(--s-3) var(--s-2) calc(var(--s-3) + 3px); --lbar-color: var(--accent); background: var(--surface-2); border-radius: var(--r-sm); }
|
|
1487
1529
|
.us-fresh { font-size: var(--fs-xs); }
|
|
1488
|
-
.us-partial { font-size: var(--fs-sm); padding: var(--s-2) var(--s-3)
|
|
1530
|
+
.us-partial { font-size: var(--fs-sm); padding: var(--s-2) var(--s-3) var(--s-2) calc(var(--s-3) + 3px); --lbar-color: var(--warn); background: var(--warn-bg); border-radius: var(--r-sm); }
|
|
1489
1531
|
.us-unpriced { font-size: var(--fs-xs); }
|
|
1490
1532
|
.us-scan { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
|
|
1491
1533
|
.us-totals { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-3); margin: 0; }
|
|
@@ -1551,7 +1593,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1551
1593
|
.cmd-palette .cmd-arg { color: var(--text-3); }
|
|
1552
1594
|
.cmd-palette .cmd-none { color: var(--text-3); cursor: default; }
|
|
1553
1595
|
.cmd-card { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-2); padding: var(--s-2) var(--s-3); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); }
|
|
1554
|
-
.cmd-card.bad {
|
|
1596
|
+
.cmd-card.bad { --lbar-color: var(--danger); padding-left: calc(var(--s-3) + 3px); }
|
|
1555
1597
|
.cmd-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
|
|
1556
1598
|
.cmd-name { font-weight: var(--fw-semibold); }
|
|
1557
1599
|
.cmd-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--font-ui); color: var(--text-2); }
|
|
@@ -1900,19 +1942,22 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1900
1942
|
.tb-count { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-3); }
|
|
1901
1943
|
.tb-drop-line { height: 3px; border-radius: 2px; background: var(--accent); }
|
|
1902
1944
|
|
|
1903
|
-
.tb-tile { display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-3); border-radius: var(--r-md); background: var(--bg); border: 1px solid var(--border);
|
|
1904
|
-
.tb-tile:hover { border-color: var(--border-strong); }
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
.tb-tile.st-
|
|
1908
|
-
.tb-tile.st-
|
|
1945
|
+
.tb-tile { display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-3) var(--s-3) var(--s-3) calc(var(--s-3) + 2px); border-radius: var(--r-md); background: var(--bg); border: 1px solid var(--border); box-shadow: var(--shadow-1); --lbar-color: transparent; cursor: pointer; font-size: var(--fs-sm); min-width: 0; }
|
|
1946
|
+
.tb-tile:hover { border-color: var(--border-strong); box-shadow: var(--shadow-2); }
|
|
1947
|
+
/* As taskhall: the shared straight bar (#2330) only while the card is under way (in progress, blocked, waiting for
|
|
1948
|
+
you); none on to do or done, and a done tile is dimmed. */
|
|
1949
|
+
.tb-tile.st-claimed { --lbar-color: var(--accent); }
|
|
1950
|
+
.tb-tile.st-blocked { --lbar-color: var(--danger); }
|
|
1951
|
+
.tb-tile.st-review { --lbar-color: var(--warn); }
|
|
1952
|
+
.tb-tile.st-done { background: color-mix(in srgb, var(--bg) 60%, var(--surface)); box-shadow: none; }
|
|
1953
|
+
.tb-tile.st-done .tb-tile-title { color: var(--text-2); }
|
|
1909
1954
|
.tb-tile.dragging { opacity: 0.4; }
|
|
1910
1955
|
.tb-tile.flash { animation: tb-flash 1.6s var(--ease); }
|
|
1911
1956
|
@keyframes tb-flash { from { box-shadow: 0 0 0 3px var(--accent-dim); background: var(--accent-dim); } to { box-shadow: none; } }
|
|
1912
1957
|
.tb-tile-top { display: flex; align-items: center; gap: var(--s-2); }
|
|
1913
|
-
.tb-size { font-size: var(--
|
|
1958
|
+
.tb-size { padding: 0 5px; border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 11px; font-weight: var(--fw-bold); line-height: 16px; color: var(--text-3); }
|
|
1914
1959
|
/* The tile's control: its title, a plain-looking button (Enter opens the card, Alt+arrows move it). */
|
|
1915
|
-
.tb-tile-title { display: block; width: 100%; padding: 0; background: none; border: 0; border-radius: var(--r-sm); color: var(--text); font: inherit; font-weight: var(--fw-
|
|
1960
|
+
.tb-tile-title { display: block; width: 100%; padding: 0; background: none; border: 0; border-radius: var(--r-sm); color: var(--text); font: inherit; font-weight: var(--fw-semibold); line-height: 1.4; text-align: left; cursor: pointer; overflow-wrap: anywhere; }
|
|
1916
1961
|
.tb-tile-title:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
1917
1962
|
.tb-tile:has(.tb-tile-title:focus-visible) { border-color: var(--focus); }
|
|
1918
1963
|
.tb-tile-note { display: flex; gap: var(--s-1); align-items: flex-start; font-size: var(--fs-xs); color: var(--text-2); overflow-wrap: anywhere; }
|
|
@@ -1939,12 +1984,47 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1939
1984
|
.tb-sub-blocked { padding-left: 22px; font-size: var(--fs-xs); color: var(--danger); overflow-wrap: anywhere; }
|
|
1940
1985
|
.tb-sub-more { font-size: var(--fs-xs); padding-left: var(--s-1); }
|
|
1941
1986
|
.tb-tile-foot { display: flex; align-items: center; gap: var(--s-2); }
|
|
1942
|
-
.tb-tile-foot > .tb-who { flex: 1; min-width: 0; max-width: none; }
|
|
1987
|
+
.tb-tile-foot > .tb-who, .tb-tile-foot > .tb-person, .tb-tile-foot > .tb-people { flex: 1; min-width: 0; max-width: none; }
|
|
1988
|
+
.tb-people { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-3); }
|
|
1989
|
+
/* Who (fleet-task-common.js): a round initial — the instance's identity colour when it has one — then the name. */
|
|
1990
|
+
.tb-person { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
|
|
1991
|
+
.tb-person > .tb-who { min-width: 0; }
|
|
1992
|
+
.tb-person.none > .tb-who { color: var(--text-3); }
|
|
1993
|
+
.tb-av { display: inline-grid; place-items: center; width: 20px; height: 20px; flex: none; border-radius: 50%; font-size: 11px; font-weight: var(--fw-bold); line-height: 1;
|
|
1994
|
+
background: color-mix(in srgb, var(--id, var(--text-3)) 16%, var(--bg)); color: var(--id-name, var(--text-2)); }
|
|
1943
1995
|
.tb-tile-stats { display: inline-flex; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-3); }
|
|
1944
1996
|
.tb-tile-stats > span { display: inline-flex; align-items: center; gap: 2px; }
|
|
1945
1997
|
.tb-tile-stats > .all { color: var(--ok); }
|
|
1946
1998
|
.tb-tile-stats > .reply { color: var(--accent); }
|
|
1947
1999
|
|
|
2000
|
+
/* #2246 step 3: who works on what (fleet-task-work.js) — the board's Instance drawer and the Details page's block. */
|
|
2001
|
+
.tw { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
|
|
2002
|
+
.tw-head { margin: 0; font-size: var(--fs-sm); }
|
|
2003
|
+
.tw-error { margin: 0; color: var(--danger); font-size: var(--fs-sm); }
|
|
2004
|
+
.tw-group { display: flex; flex-direction: column; gap: var(--s-2); }
|
|
2005
|
+
.tw-group-head { display: flex; align-items: center; gap: var(--s-2); margin: 0; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); }
|
|
2006
|
+
.tw-inst { display: flex; flex-direction: column; gap: var(--s-1); padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg); min-width: 0; }
|
|
2007
|
+
.tw-inst-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
|
|
2008
|
+
.tw-inst-head .av { width: 24px; height: 24px; font-size: 11px; }
|
|
2009
|
+
.tw-inst-head .av .av-dot { box-shadow: 0 0 0 2px var(--bg); }
|
|
2010
|
+
.tw-name { font-weight: var(--fw-semibold); font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
2011
|
+
.tw-state { font-size: var(--fs-xs); white-space: nowrap; }
|
|
2012
|
+
.tw-alt { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
2013
|
+
.tw-desc { margin: 0; font-size: var(--fs-xs); overflow-wrap: anywhere; }
|
|
2014
|
+
.tw-none { margin: 0; font-size: var(--fs-xs); }
|
|
2015
|
+
.tw-lines { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
|
|
2016
|
+
.tw-line { display: flex; align-items: baseline; gap: var(--s-2); width: 100%; padding: 2px var(--s-1); background: none; border: 0; border-radius: var(--r-sm); color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); min-width: 0; }
|
|
2017
|
+
.tw-line:hover { background: var(--surface-2); }
|
|
2018
|
+
.tw-line:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
|
|
2019
|
+
.tw-kind { flex-shrink: 0; min-width: 4.5em; font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-2); }
|
|
2020
|
+
.tw-kind.k-doing { color: var(--accent); }
|
|
2021
|
+
.tw-kind.k-blocked, .tw-kind.k-back { color: var(--danger); }
|
|
2022
|
+
.tw-kind.k-review { color: var(--warn); }
|
|
2023
|
+
.tw-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2024
|
+
.tw-note { flex-shrink: 0; font-size: var(--fs-xs); white-space: nowrap; }
|
|
2025
|
+
.tw-unread { flex-shrink: 0; display: inline-flex; color: var(--accent); }
|
|
2026
|
+
.d-board .tw-lines { margin-top: var(--s-1); }
|
|
2027
|
+
|
|
1948
2028
|
/* One card, in the app's dialog. */
|
|
1949
2029
|
.tc { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; }
|
|
1950
2030
|
.tc-head { display: flex; align-items: center; gap: var(--s-2); }
|
|
@@ -1954,7 +2034,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1954
2034
|
.tc-ver { font-size: var(--fs-xs); }
|
|
1955
2035
|
.tc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding-bottom: var(--s-3); border-bottom: 1px solid var(--border); }
|
|
1956
2036
|
.tc-hint { font-size: var(--fs-xs); }
|
|
1957
|
-
.tc-meta { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s-2) var(--s-4); margin: 0; font-size: var(--fs-sm); align-items: center; }
|
|
2037
|
+
.tc-meta { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s-2) var(--s-4); margin: 0; padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); align-items: center; }
|
|
1958
2038
|
.tc-meta dt { color: var(--text-2); }
|
|
1959
2039
|
.tc-meta dd { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin: 0; min-width: 0; }
|
|
1960
2040
|
.tc-value { color: var(--text); overflow-wrap: anywhere; }
|
|
@@ -1992,6 +2072,8 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1992
2072
|
.tb-col { min-height: 0; }
|
|
1993
2073
|
.tb-form-row { grid-template-columns: minmax(0, 1fr); }
|
|
1994
2074
|
.tb-search { flex: 1 1 100%; }
|
|
2075
|
+
/* The card's sheet keeps its fields full width (the grey block is the desk drawer's). */
|
|
2076
|
+
.tc-meta { padding: 0; background: none; }
|
|
1995
2077
|
/* #2299: a phone's waiting row: pill and title on one line, the actions under them (assignee left, buttons right). */
|
|
1996
2078
|
.tb-wait-main > .tb-pill { min-width: 0; }
|
|
1997
2079
|
.tb-wait-actions { flex-basis: 100%; margin-left: 0; }
|
|
@@ -2002,7 +2084,22 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
2002
2084
|
/* …and they do not pile down the board: an older confirmation gives way to two newer toasts; an error never does. */
|
|
2003
2085
|
.shell:has(.tb-home, .tb-board-page) .toasts > .toast.ok:nth-last-child(n+3) { display: none; }
|
|
2004
2086
|
}
|
|
2087
|
+
/* On a desk a project's columns reach the bottom of the page, as taskhall's: a card drops anywhere down a column, and
|
|
2088
|
+
an empty column still reads as one. The page's column, the board and its scroller pass the height down as flex. */
|
|
2089
|
+
@media (min-width: 900px) {
|
|
2090
|
+
.col:has(> .tb > .tb-board-page) { display: flex; flex-direction: column; min-height: 100%; }
|
|
2091
|
+
.tb:has(> .tb-board-page) { flex: 1; }
|
|
2092
|
+
.tb-board-page { display: flex; flex-direction: column; flex: 1; }
|
|
2093
|
+
.tb-board-page > .tb-scroll { display: flex; flex-direction: column; flex: 1; }
|
|
2094
|
+
.tb-board-page .tb-columns { flex: 1; align-items: stretch; }
|
|
2095
|
+
}
|
|
2005
2096
|
@media (prefers-reduced-motion: reduce) {
|
|
2006
2097
|
.tb-tile.flash { animation: none; }
|
|
2007
2098
|
.tb-chev { transition: none; }
|
|
2008
2099
|
}
|
|
2100
|
+
|
|
2101
|
+
/* #2305: the agent's reactions to a message (its minimal reply), under the bubble — on the person's side for theirs. */
|
|
2102
|
+
.msg-reactions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
|
|
2103
|
+
.msg.user .msg-reactions { justify-content: flex-end; }
|
|
2104
|
+
.msg-reactions .reaction { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 24px; padding: 0 6px;
|
|
2105
|
+
border: 1px solid var(--border); border-radius: var(--r-full); background: var(--surface-2); font-family: var(--font-emoji); font-size: 15px; line-height: 1; }
|