@songsid/agend 2.2.0-beta.9 → 2.3.0-beta.1
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 +40 -24
- package/README.zh-TW.md +40 -24
- package/dist/agent-cli.js +248 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +2 -0
- package/dist/agent-endpoint.js +28 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +30 -0
- package/dist/agent-file-read.js +129 -0
- package/dist/agent-file-read.js.map +1 -0
- package/dist/agent-whats-new.js +20 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/atomic-write.js +9 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +3 -1
- package/dist/auth-api.js +32 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +33 -0
- package/dist/backend/antigravity.js +129 -21
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +3 -0
- package/dist/backend/claude-code.js +9 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +33 -0
- package/dist/backend/codex-metadata.js +122 -18
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -0
- package/dist/backend/codex.js +17 -1
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/effort-metadata.d.ts +37 -1
- package/dist/backend/effort-metadata.js +86 -15
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.d.ts +3 -0
- package/dist/backend/grok.js +9 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +3 -1
- package/dist/backend/kiro.js +7 -3
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.d.ts +61 -0
- package/dist/backend/launch-effort.js +170 -0
- package/dist/backend/launch-effort.js.map +1 -0
- package/dist/backend/muse.js +10 -2
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +24 -0
- package/dist/backend/types.js +12 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-command.d.ts +91 -0
- package/dist/backend-command.js +122 -0
- package/dist/backend-command.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +14 -0
- package/dist/channel/adapters/discord.js +66 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +26 -1
- package/dist/channel/adapters/telegram.js +98 -7
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +36 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.d.ts +2 -0
- package/dist/channel/tool-router.js +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +31 -0
- package/dist/cli.js +124 -24
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +2 -2
- package/dist/command-table.js +5 -2
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.d.ts +86 -0
- package/dist/compact-watch.js +288 -0
- package/dist/compact-watch.js.map +1 -0
- package/dist/config-validator.js +55 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +9 -0
- package/dist/daemon.js +394 -29
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +8 -1
- package/dist/delivery-outbox.js +6 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.js +7 -0
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-context.d.ts +12 -0
- package/dist/fleet-manager.d.ts +247 -9
- package/dist/fleet-manager.js +1227 -142
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +4 -3
- package/dist/forged-envelope-scan.js +4 -3
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +258 -0
- package/dist/install-lock.d.ts +18 -1
- package/dist/install-lock.js +30 -3
- package/dist/install-lock.js.map +1 -1
- package/dist/instance-avatar.d.ts +5 -4
- package/dist/instance-avatar.js +15 -8
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instance-config-impact.js +3 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.js +9 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.js +2 -2
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.d.ts +38 -0
- package/dist/kiro-compact-pane.js +57 -0
- package/dist/kiro-compact-pane.js.map +1 -0
- package/dist/launchd-handoff.d.ts +43 -0
- package/dist/launchd-handoff.js +56 -0
- package/dist/launchd-handoff.js.map +1 -0
- package/dist/locale.js +202 -30
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +10 -2
- package/dist/log-service.js.map +1 -1
- package/dist/login-shell.d.ts +21 -0
- package/dist/login-shell.js +98 -0
- package/dist/login-shell.js.map +1 -0
- package/dist/needs-you-hub.d.ts +4 -0
- package/dist/needs-you-hub.js +31 -6
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +1 -13
- package/dist/needs-you.js +3 -37
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +32 -0
- package/dist/outbound-handlers.js +150 -45
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +76 -0
- package/dist/outbound-schemas.js +65 -4
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +29 -0
- package/dist/provider-probe.js +198 -2
- package/dist/provider-probe.js.map +1 -1
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +25 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.d.ts +1 -1
- package/dist/quickstart-api.js +8 -6
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +12 -0
- package/dist/quickstart.js +36 -6
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +86 -5
- package/dist/reply-buttons-controller.js +271 -7
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-buttons.d.ts +48 -3
- package/dist/reply-buttons.js +105 -10
- package/dist/reply-buttons.js.map +1 -1
- package/dist/reply-polls.d.ts +85 -0
- package/dist/reply-polls.js +154 -0
- package/dist/reply-polls.js.map +1 -0
- package/dist/repo-worktree-guard.d.ts +36 -0
- package/dist/repo-worktree-guard.js +143 -0
- package/dist/repo-worktree-guard.js.map +1 -0
- package/dist/restart-guard.d.ts +6 -3
- package/dist/restart-guard.js +6 -3
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +0 -2
- package/dist/restart-progress.js +0 -2
- package/dist/restart-progress.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts +58 -1
- package/dist/scheduler/scheduler.js +176 -10
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/sd-notify.d.ts +22 -1
- package/dist/sd-notify.js +63 -10
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-activation.d.ts +15 -7
- package/dist/service-activation.js +42 -26
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +24 -0
- package/dist/service-installer.js +49 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +11 -0
- package/dist/service-plan.js +23 -0
- package/dist/service-plan.js.map +1 -1
- package/dist/settings-api.js +74 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +8 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +16 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +5 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/systemd-peer-bus.d.ts +95 -0
- package/dist/systemd-peer-bus.js +430 -0
- package/dist/systemd-peer-bus.js.map +1 -0
- package/dist/systemd-runtime.d.ts +27 -1
- package/dist/systemd-runtime.js +69 -7
- package/dist/systemd-runtime.js.map +1 -1
- package/dist/tool-permissions.js +53 -3
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +72 -2
- package/dist/topic-commands.js +156 -38
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.d.ts +128 -0
- package/dist/topic-link.js +269 -0
- package/dist/topic-link.js.map +1 -0
- package/dist/transcript-jsonl.d.ts +7 -2
- package/dist/transcript-jsonl.js +13 -7
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-sources.js +6 -1
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/ui/app-effects.js +187 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-effect-posters.js +42 -0
- package/dist/ui/chat-effects.js +72 -0
- package/dist/ui/chat-live-replies.js +58 -0
- package/dist/ui/chat-render.js +59 -14
- package/dist/ui/chat-store.js +78 -8
- package/dist/ui/chat-strings.js +43 -16
- package/dist/ui/chat-thread.js +175 -31
- package/dist/ui/chat-tour.js +18 -15
- package/dist/ui/effect-trial-controller.js +119 -0
- package/dist/ui/effect-trial-offer.js +31 -0
- package/dist/ui/effect-trial-panel.js +37 -0
- package/dist/ui/image-lightbox.js +1 -1
- package/dist/ui/panel-chat.js +101 -27
- package/dist/ui/panel-details.js +18 -5
- package/dist/ui/panel-fleet.js +18 -5
- package/dist/ui/panel-log.js +10 -10
- package/dist/ui/panel-needs.js +13 -10
- package/dist/ui/panel-settings.js +66 -12
- package/dist/ui/preview-panel.js +25 -9
- package/dist/ui/settings-appearance.js +325 -0
- package/dist/ui/settings-dialogs.js +11 -6
- package/dist/ui/settings-effects.js +201 -0
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-mods.js +257 -0
- package/dist/ui/settings-owner-effects.js +80 -0
- package/dist/ui/settings-strings.js +269 -10
- package/dist/ui/settings-token.js +7 -0
- package/dist/ui/settings-wizard.js +5 -3
- package/dist/ui/shared/agend-auth.js +27 -3
- package/dist/ui/shared/agent-widget.js +248 -0
- package/dist/ui/shared/app-i18n.js +3 -1
- package/dist/ui/shared/app-prefs.js +30 -10
- package/dist/ui/shared/app-route.js +23 -1
- package/dist/ui/shared/app-session.js +1 -1
- package/dist/ui/shared/app-shell.js +29 -16
- package/dist/ui/shared/app-store.js +2 -0
- package/dist/ui/shared/app-stream.js +15 -7
- package/dist/ui/shared/app-themes.js +188 -0
- package/dist/ui/shared/app.css +266 -11
- package/dist/ui/shared/app.js +6 -0
- package/dist/ui/shared/card-strings.js +28 -0
- package/dist/ui/shared/effect-app-runtime.js +248 -0
- package/dist/ui/shared/effect-baseline.js +64 -0
- package/dist/ui/shared/effect-chat-runtime.js +154 -0
- package/dist/ui/shared/effect-cursor.js +125 -0
- package/dist/ui/shared/effect-frame.js +127 -0
- package/dist/ui/shared/effect-geometry.js +122 -0
- package/dist/ui/shared/effect-host-style.js +10 -0
- package/dist/ui/shared/effect-owner-regions.js +74 -0
- package/dist/ui/shared/effect-owner-source.js +115 -0
- package/dist/ui/shared/effect-policy.js +137 -0
- package/dist/ui/shared/effect-poster-reader.js +98 -0
- package/dist/ui/shared/effect-posters.js +117 -0
- package/dist/ui/shared/effect-profiler.js +162 -0
- package/dist/ui/shared/effect-profiles.js +65 -0
- package/dist/ui/shared/effect-registry.js +496 -0
- package/dist/ui/shared/effect-runtime-loader.js +234 -0
- package/dist/ui/shared/effect-safety.js +153 -0
- package/dist/ui/shared/effect-stock-snapshot.js +34 -0
- package/dist/ui/shared/effect-stock-trust.js +165 -0
- package/dist/ui/shared/effect-trial-source.js +103 -0
- package/dist/ui/shared/effect-trial-stage.js +147 -0
- package/dist/ui/shared/header-tools.js +35 -15
- package/dist/ui/shared/identity-card.js +202 -0
- package/dist/ui/shared/identity-color.js +261 -0
- package/dist/ui/shared/instance-nav.js +22 -14
- package/dist/ui/shared/instance-switch.js +5 -2
- package/dist/ui/shared/owner-css.js +221 -0
- package/dist/ui/shared/owner-effect-prefs.js +117 -0
- package/dist/ui/shared/panel-view.js +96 -12
- package/dist/ui/shared/signin.js +17 -9
- package/dist/ui/shared/ui-dialog.js +1 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/ui-menu.js +1 -1
- package/dist/ui/shared/ui-toast.js +1 -1
- package/dist/ui/shared/view-strings.js +40 -2
- package/dist/ui/signin.html +9 -3
- package/dist/update-check.d.ts +31 -0
- package/dist/update-check.js +47 -0
- package/dist/update-check.js.map +1 -1
- package/dist/update-launch.d.ts +48 -1
- package/dist/update-launch.js +159 -5
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/providers.d.ts +28 -8
- package/dist/usage/providers.js +96 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.d.ts +29 -0
- package/dist/view-api.js +214 -17
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +86 -2
- package/dist/web-api.js +1160 -92
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-limits.d.ts +82 -0
- package/dist/web-appearance-limits.js +83 -0
- package/dist/web-appearance-limits.js.map +1 -0
- package/dist/web-appearance-policy.d.ts +66 -0
- package/dist/web-appearance-policy.js +94 -0
- package/dist/web-appearance-policy.js.map +1 -0
- package/dist/web-appearance-tools.d.ts +50 -0
- package/dist/web-appearance-tools.js +105 -0
- package/dist/web-appearance-tools.js.map +1 -0
- package/dist/web-appearance-view.d.ts +99 -0
- package/dist/web-appearance-view.js +163 -0
- package/dist/web-appearance-view.js.map +1 -0
- package/dist/web-appearance.d.ts +79 -0
- package/dist/web-appearance.js +298 -0
- package/dist/web-appearance.js.map +1 -0
- package/dist/web-asset-parts.d.ts +98 -0
- package/dist/web-asset-parts.js +133 -0
- package/dist/web-asset-parts.js.map +1 -0
- package/dist/web-auth.js +17 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-card.d.ts +96 -0
- package/dist/web-card.js +232 -0
- package/dist/web-card.js.map +1 -0
- package/dist/web-chat-history.d.ts +39 -1
- package/dist/web-chat-history.js +69 -9
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +39 -3
- package/dist/web-commands.js +22 -5
- package/dist/web-commands.js.map +1 -1
- package/dist/web-effect-bundle.d.ts +28 -0
- package/dist/web-effect-bundle.js +126 -0
- package/dist/web-effect-bundle.js.map +1 -0
- package/dist/web-effect-canonical.d.ts +8 -0
- package/dist/web-effect-canonical.js +27 -0
- package/dist/web-effect-canonical.js.map +1 -0
- package/dist/web-effect-library.d.ts +114 -0
- package/dist/web-effect-library.js +530 -0
- package/dist/web-effect-library.js.map +1 -0
- package/dist/web-effect-poster.d.ts +8 -0
- package/dist/web-effect-poster.js +52 -0
- package/dist/web-effect-poster.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +118 -0
- package/dist/web-effect-profiles.js +180 -0
- package/dist/web-effect-profiles.js.map +1 -0
- package/dist/web-effect-service.d.ts +86 -0
- package/dist/web-effect-service.js +312 -0
- package/dist/web-effect-service.js.map +1 -0
- package/dist/web-effect-tools.d.ts +47 -0
- package/dist/web-effect-tools.js +126 -0
- package/dist/web-effect-tools.js.map +1 -0
- package/dist/web-effect-trials.d.ts +86 -0
- package/dist/web-effect-trials.js +204 -0
- package/dist/web-effect-trials.js.map +1 -0
- package/dist/web-effect-upload.d.ts +29 -0
- package/dist/web-effect-upload.js +190 -0
- package/dist/web-effect-upload.js.map +1 -0
- package/dist/web-effect-worker.d.ts +8 -0
- package/dist/web-effect-worker.js +170 -0
- package/dist/web-effect-worker.js.map +1 -0
- package/dist/web-effect.d.ts +89 -0
- package/dist/web-effect.js +132 -0
- package/dist/web-effect.js.map +1 -0
- package/dist/web-identity-color.d.ts +87 -0
- package/dist/web-identity-color.js +209 -0
- package/dist/web-identity-color.js.map +1 -0
- package/dist/web-identity-palette.d.ts +113 -0
- package/dist/web-identity-palette.js +84 -0
- package/dist/web-identity-palette.js.map +1 -0
- package/dist/web-image-meta.d.ts +25 -0
- package/dist/web-image-meta.js +200 -0
- package/dist/web-image-meta.js.map +1 -0
- package/dist/web-login.d.ts +14 -0
- package/dist/web-login.js +4 -2
- package/dist/web-login.js.map +1 -1
- package/dist/web-mod-agent.d.ts +50 -0
- package/dist/web-mod-agent.js +203 -0
- package/dist/web-mod-agent.js.map +1 -0
- package/dist/web-mod-bundle.d.ts +144 -0
- package/dist/web-mod-bundle.js +464 -0
- package/dist/web-mod-bundle.js.map +1 -0
- package/dist/web-mod-export.d.ts +59 -0
- package/dist/web-mod-export.js +79 -0
- package/dist/web-mod-export.js.map +1 -0
- package/dist/web-mod-store.d.ts +283 -0
- package/dist/web-mod-store.js +624 -0
- package/dist/web-mod-store.js.map +1 -0
- package/dist/web-org.d.ts +3 -3
- package/dist/web-org.js +11 -17
- package/dist/web-org.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +180 -0
- package/dist/web-owner-css-store.js +384 -0
- package/dist/web-owner-css-store.js.map +1 -0
- package/dist/web-owner-css.d.ts +58 -0
- package/dist/web-owner-css.js +552 -0
- package/dist/web-owner-css.js.map +1 -0
- package/dist/web-prefs.d.ts +66 -0
- package/dist/web-prefs.js +243 -35
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +9 -1
- package/dist/web-preview.js +24 -7
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.d.ts +32 -0
- package/dist/web-profile.js +132 -0
- package/dist/web-profile.js.map +1 -0
- package/dist/web-session.d.ts +14 -0
- package/dist/web-session.js +10 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +18 -0
- package/dist/web-settings-patch.js +51 -0
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-theme-store.d.ts +218 -0
- package/dist/web-theme-store.js +516 -0
- package/dist/web-theme-store.js.map +1 -0
- package/dist/web-theme.d.ts +121 -0
- package/dist/web-theme.js +407 -0
- package/dist/web-theme.js.map +1 -0
- package/dist/web-upload.d.ts +119 -4
- package/dist/web-upload.js +252 -39
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.d.ts +72 -0
- package/dist/web-widget.js +245 -0
- package/dist/web-widget.js.map +1 -0
- package/launcher/install-admission.cjs +61 -6
- package/package.json +3 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** #1629: closed host display metadata. Neither this object nor its token grants a trial read. */
|
|
2
|
+
const KEYS = ["v", "offer", "id", "title", "expiresAt"], ID = /^[0-9a-f]{32}$/;
|
|
3
|
+
const FORBIDDEN = /(?!\u200d)[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
4
|
+
const VISIBLE = /[^\p{M}\p{C}\p{Z}\u115f\u1160\u3164\uffa0\u2800]/u;
|
|
5
|
+
let graphemes = null;
|
|
6
|
+
export function checkEffectTrialOffer(value) {
|
|
7
|
+
try {
|
|
8
|
+
if (!value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return null;
|
|
9
|
+
const keys = Reflect.ownKeys(value);
|
|
10
|
+
if (keys.length !== KEYS.length || keys.some(k => typeof k !== "string" || !KEYS.includes(k))) return null;
|
|
11
|
+
const x = Object.create(null);
|
|
12
|
+
for (const key of KEYS) {
|
|
13
|
+
const d = Object.getOwnPropertyDescriptor(value, key);
|
|
14
|
+
if (!d || !("value" in d) || !d.enumerable) return null;
|
|
15
|
+
x[key] = d.value;
|
|
16
|
+
}
|
|
17
|
+
if (x.v !== 1 || typeof x.offer !== "string" || !ID.test(x.offer) || typeof x.id !== "string" || !ID.test(x.id)
|
|
18
|
+
|| typeof x.title !== "string" || x.title.length > 400 || x.title.normalize("NFC") !== x.title || x.title.trim() !== x.title
|
|
19
|
+
|| FORBIDDEN.test(x.title) || !VISIBLE.test(x.title) || !Number.isSafeInteger(x.expiresAt) || x.expiresAt < 0) return null;
|
|
20
|
+
graphemes ??= new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
21
|
+
let count = 0; for (const _part of graphemes.segment(x.title)) if (++count > 40) return null;
|
|
22
|
+
if (count < 1) return null;
|
|
23
|
+
return Object.freeze({ v: 1, offer: x.offer, id: x.id, title: x.title, expiresAt: x.expiresAt });
|
|
24
|
+
} catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
/** Role and sender are host fields, never inferred from a message's text. Start must separately authorize. */
|
|
27
|
+
export function effectTrialMessage(message) {
|
|
28
|
+
if (!message || message.role !== "status" || message.sender !== "agend" || typeof message.instance !== "string"
|
|
29
|
+
|| message.instance.length < 1 || message.instance.length > 128) return null;
|
|
30
|
+
return checkEffectTrialOffer(message.effectTrial);
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** #1629: fixed host producer. Creates no frame or request; the admitted app controller owns its lease. */
|
|
2
|
+
import { html, useLayoutEffect, useRef } from "/assets/app-html.js";
|
|
3
|
+
import { register, t } from "/assets/app-i18n.js";
|
|
4
|
+
import { createEffectTrialStage } from "/assets/effect-trial-stage.js";
|
|
5
|
+
register("effectTrial", {
|
|
6
|
+
en: { label: "Trial", stop: "Stop trial", close: "Close", note: "A bounded sample. Nothing is applied or saved." },
|
|
7
|
+
"zh-TW": { label: "試播", stop: "停止試播", close: "關閉", note: "僅在此區塊試播,不會套用或儲存。" },
|
|
8
|
+
});
|
|
9
|
+
/** The caller owns authenticated admission, lease/deadline and shared pool. No script/HTML is rendered here. */
|
|
10
|
+
export function EffectTrialPanel({ window: host = globalThis.window, binding, title, current, ownerCss, onStage, onStop, onClose }) {
|
|
11
|
+
const panel = useRef(null), stage = useRef(null), life = useRef(null), latest = useRef(null);
|
|
12
|
+
latest.current = { current, ownerCss, onStage, onStop, onClose };
|
|
13
|
+
const stop = close => {
|
|
14
|
+
const entry = life.current; if (!entry || (close ? entry.closed : entry.dead)) return;
|
|
15
|
+
if (close) entry.closed = true;
|
|
16
|
+
if (!entry.dead) { entry.dead = true; entry.api?.dispose(); }
|
|
17
|
+
try { (close ? entry.onClose : entry.onStop)?.("stopped"); } catch { /* lease already ended */ }
|
|
18
|
+
};
|
|
19
|
+
useLayoutEffect(() => {
|
|
20
|
+
const entry = { dead: false, closed: false, api: null, onStop, onClose }; life.current = entry;
|
|
21
|
+
const ended = reason => { if (entry.dead) return; entry.dead = true; try { entry.onStop?.(reason); } catch { /* never revive */ } };
|
|
22
|
+
try {
|
|
23
|
+
entry.api = createEffectTrialStage({ window: host, panel: panel.current, stage: stage.current, binding,
|
|
24
|
+
current: own => !entry.dead && life.current === entry && latest.current.current?.(own) === true,
|
|
25
|
+
ownerCss: () => latest.current.ownerCss?.(), onStop: ended });
|
|
26
|
+
if (!entry.api) ended("stage_unavailable");
|
|
27
|
+
else { latest.current.onStage?.(entry.api); }
|
|
28
|
+
} catch { entry.api?.dispose(); ended("stage_unavailable"); }
|
|
29
|
+
return () => { entry.api?.dispose(); entry.dead = true; if (life.current === entry) life.current = null; };
|
|
30
|
+
}, [host, binding]);
|
|
31
|
+
return html`<aside ref=${panel} data-trust="preview" class="pv-panel effect-trial-panel" aria-label=${t("effectTrial.label")}>
|
|
32
|
+
<header class="effect-trial-head"><strong>${t("effectTrial.label")}</strong><span>${typeof title === "string" ? title : ""}</span><button type="button" class="btn" onClick=${() => stop(true)}>${t("effectTrial.close")}</button></header>
|
|
33
|
+
<div class="effect-trial-controls"><button type="button" class="btn" onClick=${() => stop(false)}>${t("effectTrial.stop")}</button></div>
|
|
34
|
+
<div class="effect-trial-body"><div ref=${stage} class="effect-trial-stage" aria-hidden="true"></div></div>
|
|
35
|
+
<p class="effect-trial-note">${t("effectTrial.note")}</p>
|
|
36
|
+
</aside>`;
|
|
37
|
+
}
|
|
@@ -90,7 +90,7 @@ function ImageLightbox({ items, index, opener, onClose }) {
|
|
|
90
90
|
return () => { d.removeEventListener("cancel", onCancel); d.removeEventListener("close", onNativeClose); d.removeEventListener("click", onClick); d.removeEventListener("keydown", onKey); };
|
|
91
91
|
}, [onClose, many, items.length]);
|
|
92
92
|
const label = item.name ? t("chat.lbLabel", item.name) : t("chat.lbLabelNoName");
|
|
93
|
-
return html`<dialog ref=${ref} class="lb" role="dialog" aria-modal="true" aria-label=${label}>
|
|
93
|
+
return html`<dialog data-trust="lightbox" ref=${ref} class="lb" role="dialog" aria-modal="true" aria-label=${label}>
|
|
94
94
|
<div class="lb-bar">
|
|
95
95
|
<span class="lb-name" title=${item.name}>${item.name}</span>
|
|
96
96
|
${many ? html`<span class="lb-count">${t("chat.lbCount", at + 1, items.length)}</span>` : null}
|
package/dist/ui/panel-chat.js
CHANGED
|
@@ -12,10 +12,10 @@ import { appStore, useStore } from "/assets/app-store.js";
|
|
|
12
12
|
import { useLease } from "/assets/app-ctx.js";
|
|
13
13
|
import { namesOf, namesStore } from "/assets/instance-nav.js";
|
|
14
14
|
import { PanelHeader, onPanelKey, setTitle, statusClass, statusLabel, openDrawer, requestNewInstance } from "/assets/app-shell.js";
|
|
15
|
-
import { detailsPath } from "/assets/app-route.js";
|
|
15
|
+
import { detailsPath, textLinkSegments } from "/assets/app-route.js";
|
|
16
16
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
17
17
|
import { HeaderTools } from "/assets/header-tools.js";
|
|
18
|
-
import { navigate } from "/assets/app-nav.js";
|
|
18
|
+
import { navigate, navStore } from "/assets/app-nav.js";
|
|
19
19
|
import { Menu } from "/assets/ui-menu.js";
|
|
20
20
|
import { Dialog } from "/assets/ui-dialog.js";
|
|
21
21
|
import { Empty, Skeleton } from "/assets/ui-states.js";
|
|
@@ -23,6 +23,26 @@ import { Icon } from "/assets/ui-icons.js";
|
|
|
23
23
|
import { toast } from "/assets/ui-toast.js";
|
|
24
24
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
25
25
|
import { savePref } from "/assets/app-prefs.js";
|
|
26
|
+
import { applyTheme, resolvedMode, themeFor, themeImageUrl, themeMenuItems, themesStore } from "/assets/app-themes.js";
|
|
27
|
+
import { colorMenuItem } from "/assets/identity-color.js";
|
|
28
|
+
import { IdentityCard, useCard } from "/assets/identity-card.js";
|
|
29
|
+
import { AgentWidget, instanceBinds, widgetFor } from "/assets/agent-widget.js";
|
|
30
|
+
|
|
31
|
+
// #1629 r4 §1: the identity card folded into the chat's header — folded by default; open or not is this device's choice.
|
|
32
|
+
const CHAT_CARD_KEY = "agend_chat_card";
|
|
33
|
+
const chatCardOpen = () => { try { return localStorage.getItem(CHAT_CARD_KEY) === "open"; } catch { return false; } };
|
|
34
|
+
function ChatCard({ name, card }) {
|
|
35
|
+
const [open, setOpen] = useState(chatCardOpen);
|
|
36
|
+
if (!card) return null;
|
|
37
|
+
const toggle = () => { const next = !open; setOpen(next); try { if (next) localStorage.setItem(CHAT_CARD_KEY, "open"); else localStorage.removeItem(CHAT_CARD_KEY); } catch { /* this page only */ } };
|
|
38
|
+
return html`<div data-trust="card" class=${`chat-card${open ? " open" : ""}`}>
|
|
39
|
+
<button type="button" class="chat-card-toggle" aria-expanded=${open ? "true" : "false"} onClick=${toggle}>
|
|
40
|
+
<${Icon} name="chevron" size=${14} cls=${open ? "caret" : "caret flipped"} /><span>${t(open ? "card.hide" : "card.show")}</span>
|
|
41
|
+
${!open && card.tagline ? html`<span class="chat-card-peek">${card.tagline.text}</span>` : null}
|
|
42
|
+
</button>
|
|
43
|
+
${open ? html`<${IdentityCard} name=${name} card=${card} compact=${true} />` : null}
|
|
44
|
+
</div>`;
|
|
45
|
+
}
|
|
26
46
|
import "./chat-strings.js";
|
|
27
47
|
import { confirmedWrite } from "./settings-confirm.js";
|
|
28
48
|
import { createChatStore } from "./chat-store.js";
|
|
@@ -33,8 +53,10 @@ import { createMentionIndex } from "./chat-mentions.js";
|
|
|
33
53
|
import { PreviewPanel, claimPanel, openPanel, panelClaims, panelStore, panelVersion, shownKey } from "./preview-panel.js";
|
|
34
54
|
import { needsArgument, paletteFor, parseCommandLine } from "./chat-commands.js";
|
|
35
55
|
import { installTour, refreshTourSpot } from "./chat-tour.js";
|
|
36
|
-
import { FirstRunCard } from "./first-run.js";
|
|
37
56
|
import { LightboxHost, openLightbox } from "./image-lightbox.js";
|
|
57
|
+
import { ChatEffectPosters } from "/ui/js/chat-effect-posters.js";
|
|
58
|
+
import { ChatEffects, chatEffectsMenuAvailable } from "./chat-effects.js";
|
|
59
|
+
import { startAppEffects, getAppEffects } from "./app-effects.js";
|
|
38
60
|
|
|
39
61
|
const R = () => globalThis.AgendChatRender;
|
|
40
62
|
const P = () => globalThis.AgendPreview;
|
|
@@ -94,6 +116,7 @@ export function boot({ stream, boot: bootData, deps = {} }) {
|
|
|
94
116
|
}
|
|
95
117
|
// #1604: the preview opt-in and Tour live in Settings → This device now (and on each preview card's menu).
|
|
96
118
|
installTour();
|
|
119
|
+
startAppEffects({ store });
|
|
97
120
|
return store;
|
|
98
121
|
}
|
|
99
122
|
|
|
@@ -148,14 +171,15 @@ export function ChatPanel({ route, navKey }) {
|
|
|
148
171
|
}, [name, !!inst]);
|
|
149
172
|
useEffect(() => { setTitle(name || t("app.chat")); }, [name, navKey]);
|
|
150
173
|
if (!name) {
|
|
151
|
-
// #
|
|
174
|
+
// #1854 (rank 7): one instruction — pick an agent, or with none at all, the one way to make one. Connecting a chat
|
|
175
|
+
// app (the first-run card, #1519 P7) is offered in Settings, not here: it competed with the first agent.
|
|
152
176
|
const none = app.ready && !app.instances.length;
|
|
153
177
|
return html`<div class="panel p-chat"><${PanelHeader} title=${t("app.chat")} />
|
|
154
|
-
<div class="panel-body center"
|
|
155
|
-
${none ? html`<${Empty} icon="bot" title=${t("
|
|
156
|
-
action=${html`<button type="button" class="btn btn-primary" onClick=${requestNewInstance}><${Icon} name="plus" size=${16} />${t("
|
|
157
|
-
: html`<${Empty} icon="chat" title=${t("chat.pick")}
|
|
158
|
-
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} />`}</div></div
|
|
178
|
+
<div class="panel-body center">
|
|
179
|
+
${none ? html`<${Empty} icon="bot" title=${t("chat.noAgents")}
|
|
180
|
+
action=${html`<button type="button" class="btn btn-primary" onClick=${requestNewInstance}><${Icon} name="plus" size=${16} />${t("chat.newAgent")}</button>`} />`
|
|
181
|
+
: html`<${Empty} icon="chat" title=${t("chat.pick")}
|
|
182
|
+
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} />`}</div></div>`;
|
|
159
183
|
}
|
|
160
184
|
if (!app.ready) return html`<div class="panel p-chat"><${PanelHeader} title=${name} /><div class="panel-body"><${Skeleton} lines=${5} /></div></div>`;
|
|
161
185
|
if (!inst) return html`<${NotFound} name=${name} />`;
|
|
@@ -171,11 +195,40 @@ function NotFound({ name }) {
|
|
|
171
195
|
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} /></div></div>`;
|
|
172
196
|
}
|
|
173
197
|
|
|
198
|
+
/**
|
|
199
|
+
* #1629: the mode the page is drawn in, followed live (the chosen theme, or the system's for "system"), so an agent's
|
|
200
|
+
* light and dark palettes swap with it.
|
|
201
|
+
*/
|
|
202
|
+
function useResolvedMode(lease) {
|
|
203
|
+
const [mode, setMode] = useState(resolvedMode);
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
const T = globalThis.AgendTheme;
|
|
206
|
+
const update = () => setMode(resolvedMode());
|
|
207
|
+
const off = T && typeof T.onChange === "function" ? T.onChange(update) : null;
|
|
208
|
+
let mq = null;
|
|
209
|
+
try { mq = globalThis.matchMedia ? globalThis.matchMedia("(prefers-color-scheme: light)") : null; } catch { mq = null; }
|
|
210
|
+
if (mq && typeof mq.addEventListener === "function") lease.on(mq, "change", update);
|
|
211
|
+
return () => { if (typeof off === "function") off(); };
|
|
212
|
+
}, [lease]);
|
|
213
|
+
return mode;
|
|
214
|
+
}
|
|
215
|
+
|
|
174
216
|
function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
175
217
|
const names = useStore(namesStore); // #1722: which name leads (the title)
|
|
218
|
+
// #1629: this agent's theme, on this surface only; redrawn when the themes, the viewer's switch or the mode move.
|
|
219
|
+
useStore(themesStore);
|
|
220
|
+
const mode = useResolvedMode(lease);
|
|
221
|
+
const theme = themeFor(name);
|
|
222
|
+
const themeKey = JSON.stringify(theme);
|
|
223
|
+
const card = useCard(name, inst.card_v);
|
|
176
224
|
const [dialog, setDialog] = useState(null); // "delete" | null
|
|
177
225
|
const [wrap, setWrap] = useState(codeWrap);
|
|
178
|
-
const view = useRef(null), split = useRef(null), thread = useRef(null);
|
|
226
|
+
const view = useRef(null), split = useRef(null), thread = useRef(null), bg = useRef(null), effectSurface = useRef(null);
|
|
227
|
+
useLayoutEffect(() => { applyTheme(view.current, theme, mode); }, [themeKey, mode]);
|
|
228
|
+
useLayoutEffect(() => {
|
|
229
|
+
const img = bg.current;
|
|
230
|
+
if (img && img.style && theme && theme.background) img.style.setProperty("--th-bg-opacity", String(theme.background.opacity));
|
|
231
|
+
}, [themeKey]);
|
|
179
232
|
useEffect(() => { wrapListeners.add(setWrap); return () => wrapListeners.delete(setWrap); }, []);
|
|
180
233
|
// First visit to this instance's chat on this page: its history (a navigation — it counts as use). Back again: nothing.
|
|
181
234
|
useEffect(() => { store.openHistory(name, lease); }, [name]);
|
|
@@ -217,6 +270,11 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
217
270
|
running ? null : { key: "start", label: t("chat.start"), icon: "play", onSelect: () => action("start") },
|
|
218
271
|
running ? { key: "restart", label: t("chat.restart"), icon: "restart", onSelect: () => action("restart") } : null,
|
|
219
272
|
running ? { key: "stop", label: t("chat.stopInstance"), icon: "stop", onSelect: () => action("stop") } : null,
|
|
273
|
+
// #1958: its identity colour and where it shows (the public link too, as profile edits).
|
|
274
|
+
colorMenuItem(name, inst),
|
|
275
|
+
// #1629: a person's control over this agent's theme — not over the public link (it only views themes).
|
|
276
|
+
...themeMenuItems(name),
|
|
277
|
+
chatEffectsMenuAvailable() ? { key: "effects", label: t("chatFx.title"), onSelect: () => setDialog("effects") } : null,
|
|
220
278
|
{ key: "delete", label: t("chat.delete"), icon: "trash", danger: true, onSelect: () => setDialog("delete") },
|
|
221
279
|
];
|
|
222
280
|
const cls = statusClass(inst, exec, awaiting);
|
|
@@ -226,17 +284,20 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
226
284
|
${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", inst.model)} aria-label=${t("chat.chipModel", inst.model)} onClick=${() => pick("model")}>${inst.model}</button>` : null}
|
|
227
285
|
${inst.effort ? html`<button type="button" class="hd-chip" title=${t("chat.chipEffort", inst.effort)} aria-label=${t("chat.chipEffort", inst.effort)} onClick=${() => pick("effort")}>${inst.effort}</button>` : null}`;
|
|
228
286
|
return html`<div class=${`panel p-chat${wrap ? " wrap-code" : ""}`} ref=${view}>
|
|
229
|
-
<${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="chat" />`}><${HeaderTools} navKey=${navKey} /><${Menu} items=${items} label=${t("app.more")} /></${PanelHeader}>
|
|
287
|
+
<${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="chat" />`}><${ChatEffectPosters} name=${name} lease=${lease} element=${effectSurface} /><${ChatEffects} name=${name} lease=${lease} element=${effectSurface} store=${store} open=${dialog === "effects"} onClose=${() => setDialog(null)} /><${HeaderTools} navKey=${navKey} /><${Menu} items=${items} label=${t("app.more")} /></${PanelHeader}>
|
|
288
|
+
<${ChatCard} key=${name} name=${name} card=${card} />
|
|
289
|
+
<${AgentWidget} slot="chat_header" widget=${widgetFor(name, "chat_header")} binds=${instanceBinds(inst, exec, awaiting)} />
|
|
230
290
|
<div class="chat-split" ref=${split}>
|
|
231
|
-
<div class
|
|
291
|
+
<div ref=${effectSurface} class=${`chat-main${theme && theme.background ? " has-th-bg" : ""}`}>
|
|
292
|
+
${theme && theme.background ? html`<img ref=${bg} class=${`th-bg th-bg-${theme.background.fit}`} src=${themeImageUrl(name, theme.background.image)} alt="" aria-hidden="true" decoding="async" />` : null}
|
|
232
293
|
<${Thread} name=${name} th=${thread} />
|
|
233
|
-
<${Dock} name=${name} inst=${inst} lease=${lease} exec=${exec} awaiting=${awaiting} />
|
|
294
|
+
<${Dock} name=${name} inst=${inst} lease=${lease} exec=${exec} awaiting=${awaiting} workingLabel=${theme ? theme.workingLabel : undefined} />
|
|
234
295
|
</div>
|
|
235
296
|
<${PreviewPanel} name=${name} split=${split} msgs=${() => store.state.msgs[name] || []} subscribe=${(fn) => store.subscribe(fn)}
|
|
236
297
|
keyOf=${msgKey} reveal=${(k) => thread.current && thread.current.reveal(k)} download=${downloadHtml} allow=${(commit) => setPreviewOptIn(true, commit)} />
|
|
237
298
|
</div>
|
|
238
299
|
<${LightboxHost} />
|
|
239
|
-
<div class="drop-overlay" aria-hidden="true"><div class="drop-card"><${Icon} name="attach" size=${32} /><span>${t("chat.dropHere")}</span></div></div>
|
|
300
|
+
<div data-trust="drop" class="drop-overlay" aria-hidden="true"><div class="drop-card"><${Icon} name="attach" size=${32} /><span>${t("chat.dropHere")}</span></div></div>
|
|
240
301
|
${dialog === "delete" ? html`<${DeleteDialog} name=${name} onClose=${() => setDialog(null)} />` : null}
|
|
241
302
|
</div>`;
|
|
242
303
|
}
|
|
@@ -247,11 +308,16 @@ function Thread({ name, th }) {
|
|
|
247
308
|
const [jump, setJump] = useState({ show: false, unseen: 0 });
|
|
248
309
|
const [empty, setEmpty] = useState(false);
|
|
249
310
|
useLayoutEffect(() => {
|
|
311
|
+
let live = true;
|
|
250
312
|
const thread = createThread(list.current, scroller.current, {
|
|
251
313
|
t, tf: t, isUser: (x) => store.isUser(x, name), onJump: setJump, onEmpty: setEmpty,
|
|
252
314
|
setPreviewOptIn, copyText, download: downloadHtml, toggleWrap,
|
|
315
|
+
canTryEffect: x => getAppEffects()?.canTry(x) === true,
|
|
316
|
+
startEffectTrial: x => { const seq = navStore.get().seq; void getAppEffects()?.startTrial(x).then(ok => { if (!ok && live && navStore.get().seq === seq && document.hasFocus?.() === true && document.visibilityState === "visible") toast(t("chat.effectTrialUnavailable")); }); },
|
|
253
317
|
clickReplyButton: (id, index) => store.clickReplyButton(name, id, index), // #1266
|
|
254
318
|
replyButtonBusy: (id) => store.state.rbBusy.has(id),
|
|
319
|
+
pollMine: (id) => store.state.pollMine[id], // #1823: this device's own vote
|
|
320
|
+
serverNow: () => Date.now() + store.state.clockSkew, // #1823: the deadline is the server's
|
|
255
321
|
panel: { shown: shownKey, open: (spec, o) => openPanel(spec, o), version: panelVersion, claim: claimPanel, claims: panelClaims }, // #1481, #1704
|
|
256
322
|
openImage: openLightbox, // an image, full size, in the page
|
|
257
323
|
emojis: (id) => !!emojiIndex && emojiIndex.known(id), // #1630: the fleet's server emoji
|
|
@@ -271,13 +337,15 @@ function Thread({ name, th }) {
|
|
|
271
337
|
else if (kind === "sent") thread.jumpLatest();
|
|
272
338
|
});
|
|
273
339
|
const offPv = P() ? P().onChange(() => thread.refreshCards()) : () => {};
|
|
340
|
+
const offTrials = getAppEffects()?.subscribeTrial(() => thread.render(store.state.msgs[name] || [])) ?? (() => {});
|
|
274
341
|
const offPanel = panelStore.subscribe(() => thread.refreshCards()); // a card shows whether the panel has its block
|
|
275
342
|
const onScroll = () => { store.state.scrollMemo[name] = thread.onScroll(); };
|
|
276
343
|
const sc = scroller.current, ls = list.current;
|
|
277
344
|
sc.addEventListener("scroll", onScroll, { passive: true });
|
|
278
345
|
ls.addEventListener("click", thread.onClick);
|
|
279
346
|
return () => {
|
|
280
|
-
|
|
347
|
+
live = false;
|
|
348
|
+
off(); offPv(); offPanel(); offTrials(); offEmojis(); offMentions();
|
|
281
349
|
sc.removeEventListener("scroll", onScroll);
|
|
282
350
|
ls.removeEventListener("click", thread.onClick);
|
|
283
351
|
thread.dispose(); // the whole thread goes: every preview in it stops first
|
|
@@ -286,26 +354,26 @@ function Thread({ name, th }) {
|
|
|
286
354
|
}, [name]);
|
|
287
355
|
return html`<div class="scroller" ref=${scroller}>
|
|
288
356
|
<div class="thread" ref=${list} role="log" aria-live="off" aria-label=${t("chat.conversationWith", name)}></div>
|
|
289
|
-
${empty ? html`<${Empty} icon="chat" title=${t("chat.noMessages")}
|
|
290
|
-
${jump.show ? html`<button type="button" class="jump-latest" onClick=${() => th.current && th.current.jumpLatest()}>
|
|
357
|
+
${empty ? html`<${Empty} icon="chat" title=${t("chat.noMessages")} />` : null}
|
|
358
|
+
${jump.show ? html`<button data-trust="thread-control" type="button" class="jump-latest" onClick=${() => th.current && th.current.jumpLatest()}>
|
|
291
359
|
<${Icon} name="down" size=${16} />${jump.unseen > 0 ? t("chat.newBelow", jump.unseen) : t("chat.jumpLatest")}</button>` : null}
|
|
292
360
|
</div>`;
|
|
293
361
|
}
|
|
294
362
|
|
|
295
363
|
/** Everything under the thread: prompts, the working line, a failed send, files waiting, and the composer. */
|
|
296
|
-
function Dock({ name, inst, lease, exec, awaiting }) {
|
|
364
|
+
function Dock({ name, inst, lease, exec, awaiting, workingLabel }) {
|
|
297
365
|
useChatTick(name, ["state"]);
|
|
298
366
|
const s = store.state;
|
|
299
|
-
return html`<div class="dock"><div class="dock-col">
|
|
367
|
+
return html`<div data-trust="composer" class="dock"><div class="dock-col">
|
|
300
368
|
<${Prompts} name=${name} />
|
|
301
|
-
<${WorkBar} name=${name} lease=${lease} exec=${exec} awaiting=${awaiting} />
|
|
369
|
+
<${WorkBar} name=${name} lease=${lease} exec=${exec} awaiting=${awaiting} workingLabel=${workingLabel} />
|
|
302
370
|
<${CommandCard} name=${name} lease=${lease} />
|
|
303
371
|
<${QuickActions} name=${name} inst=${inst} lease=${lease} />
|
|
304
372
|
${s.failedSends[name] ? html`<div class="failed-send" role="alert"><span>${t("chat.notSent")}</span><span class="txt">${s.failedSends[name]}</span>
|
|
305
373
|
<button type="button" class="btn btn-primary btn-sm" onClick=${() => store.putBack(name)}>${t("chat.putBack")}</button>
|
|
306
374
|
<button type="button" class="btn btn-sm" onClick=${() => store.discardFailed(name)}>${t("chat.discard")}</button></div>` : null}
|
|
307
375
|
<${Composer} name=${name} lease=${lease} busy=${R().isBusy(exec)} />
|
|
308
|
-
<p class="hint">${t("chat.composerHint")}</p>
|
|
376
|
+
<p class="hint" title=${t("chat.composerMore")}>${t("chat.composerHint")}</p>
|
|
309
377
|
</div></div>`;
|
|
310
378
|
}
|
|
311
379
|
|
|
@@ -320,6 +388,10 @@ function CommandCard({ name, lease }) {
|
|
|
320
388
|
aria-label=${t("chat.cmdDismiss")} onClick=${() => store.dismissCommand(name)}><${Icon} name="close" size=${14} /></button>`}</div>
|
|
321
389
|
${c.error ? html`<p class="cmd-text">${c.error}</p>` : null}
|
|
322
390
|
${c.text ? html`<pre class="cmd-text">${c.text}</pre>` : null}
|
|
391
|
+
${c.compact ? html`<p class="cmd-text cmd-phase">${c.compact === "running" ? t("chat.compactRunning")
|
|
392
|
+
: c.compact === "done" ? t("chat.compactDone") : c.compact === "timeout" ? t("chat.compactTimeout", "10")
|
|
393
|
+
: c.compact === "lost" ? t("chat.compactLost") : c.compact === "not_compacted" ? t("chat.compactNotCompacted") : t("chat.compactUnknown")}</p>` : null}
|
|
394
|
+
${c.choices && c.choices.prompt ? html`<pre class="cmd-text">${c.choices.prompt}</pre>` : null}
|
|
323
395
|
${c.choices ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdChoose")}>${c.choices.options.map((o) => html`<button key=${o.id} type="button"
|
|
324
396
|
class=${`btn btn-sm${o.id === c.choices.current ? " current" : ""}`} aria-current=${o.id === c.choices.current ? "true" : undefined} onClick=${() => run(o.id)}>${o.label}</button>`)}</div>` : null}
|
|
325
397
|
</div>`;
|
|
@@ -341,14 +413,14 @@ function QuickActions({ name, inst, lease }) {
|
|
|
341
413
|
function Prompts({ name }) {
|
|
342
414
|
const list = store.promptsFor(name);
|
|
343
415
|
if (!list.length) return null;
|
|
344
|
-
return html`<div class="prompts" aria-live="polite">${list.map(p => html`<div key=${p.nonce} class=${`prompt${p.resolved ? " done" : ""}`} role="group" aria-label=${p.text}>
|
|
345
|
-
<div class="txt">${p.resolved ? (p.outcome || t("chat.promptGone")) : p.text}</div>
|
|
416
|
+
return html`<div data-trust="permission" class="prompts" aria-live="polite">${list.map(p => html`<div key=${p.nonce} class=${`prompt${p.resolved ? " done" : ""}`} role="group" aria-label=${p.text}>
|
|
417
|
+
<div class="txt">${p.resolved ? (p.outcome || t("chat.promptGone")) : textLinkSegments(p.text, p.links).map(sg => sg.href ? html`<a data-trust="link" class="st-link" href=${sg.href}>${sg.text}</a>` : sg.text)}</div>
|
|
346
418
|
${p.resolved ? null : html`<div class="acts">${p.actions.map(a => html`<button key=${a.id} type="button" class="btn" disabled=${!!p.busy} onClick=${() => store.answerPrompt(p, a.id)}>${a.label}</button>`)}
|
|
347
419
|
${p.busy ? html`<span class="wait">${t("chat.promptAnswering")}</span>` : null}</div>`}</div>`)}</div>`;
|
|
348
420
|
}
|
|
349
421
|
|
|
350
422
|
/** "<name> is working… 0:42", "looks stuck", "Stopping…", or what it waits on at its terminal. Text only. */
|
|
351
|
-
function WorkBar({ name, lease, exec, awaiting }) {
|
|
423
|
+
function WorkBar({ name, lease, exec, awaiting, workingLabel }) {
|
|
352
424
|
const s = store.state;
|
|
353
425
|
const busy = R().isBusy(exec) ? exec : "";
|
|
354
426
|
const kind = awaiting != null ? "awaiting" : s.stopping[name] && busy ? "stopping" : busy;
|
|
@@ -359,7 +431,9 @@ function WorkBar({ name, lease, exec, awaiting }) {
|
|
|
359
431
|
return () => lease.clear(h);
|
|
360
432
|
}, [kind, lease]);
|
|
361
433
|
if (!kind) return null;
|
|
362
|
-
|
|
434
|
+
// #1629: the agent's own working label (its theme), shown as text — only for "working", never for the other states.
|
|
435
|
+
const label = kind === "working" && workingLabel ? workingLabel
|
|
436
|
+
: t(kind === "stuck" ? "chat.stuck" : kind === "stopping" ? "chat.stopping" : kind === "awaiting" ? "chat.awaiting" : "chat.working", name);
|
|
363
437
|
const since = s.workingSince[name];
|
|
364
438
|
return html`<div class=${`work-bar ${kind}`}><span class="pulse" aria-hidden="true"></span><span class="lbl">${label}</span>
|
|
365
439
|
${kind === "awaiting" ? html`<span class="note" title=${t("chat.approxNote")}>${awaiting || t("chat.approxNote")}</span>`
|
|
@@ -422,7 +496,7 @@ function Composer({ name, lease, busy }) {
|
|
|
422
496
|
};
|
|
423
497
|
const optId = (c) => `cmd-${c.name}`;
|
|
424
498
|
return html`<div class="composer-box">
|
|
425
|
-
${palette ? html`<ul class="cmd-palette" id="cmdPalette" role="listbox" aria-label=${t("chat.cmdCommands")}>
|
|
499
|
+
${palette ? html`<ul data-trust="palette" class="cmd-palette" id="cmdPalette" role="listbox" aria-label=${t("chat.cmdCommands")}>
|
|
426
500
|
${palette.length ? palette.map((c) => html`<li key=${c.name} id=${optId(c)} role="option" aria-selected=${c === pick ? "true" : "false"}
|
|
427
501
|
class=${c === pick ? "on" : ""} onMouseDown=${(e) => { e.preventDefault(); complete(c); }}>
|
|
428
502
|
<span class="cmd-name mono">/${c.name}${c.arg ? html` <span class="cmd-arg">${c.arg}</span>` : null}</span><span class="cmd-desc">${t(`chat.cmd_${c.name}`)}</span></li>`)
|
|
@@ -431,7 +505,7 @@ function Composer({ name, lease, busy }) {
|
|
|
431
505
|
${files.length ? html`<div class="pending-files">${files.map((f, i) => html`<${FileChip} key=${`${f.name}-${i}`} f=${f} i=${i} name=${name} />`)}</div>` : null}
|
|
432
506
|
<div class="composer">
|
|
433
507
|
<button id="attachBtn" type="button" class="icon-btn" title=${t("chat.attachTitle")} aria-label=${t("chat.attachTitle")} onClick=${() => fileIn.current && fileIn.current.click()}><${Icon} name="attach" /></button>
|
|
434
|
-
<input ref=${fileIn} type="file" multiple hidden
|
|
508
|
+
<input ref=${fileIn} type="file" multiple hidden
|
|
435
509
|
onChange=${(e) => { store.addFiles(name, e.target.files); e.target.value = ""; }} />
|
|
436
510
|
<textarea id="msgIn" ref=${input} rows="1" value=${value} placeholder=${t("chat.composerPlaceholder", name)} aria-label=${t("chat.composerPlaceholder", name)}
|
|
437
511
|
autocomplete="off" aria-controls=${palette ? "cmdPalette" : undefined} aria-expanded=${palette ? "true" : "false"}
|
package/dist/ui/panel-details.js
CHANGED
|
@@ -16,6 +16,10 @@ import { settingsPath } from "/assets/app-route.js";
|
|
|
16
16
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
17
17
|
import { HeaderTools } from "/assets/header-tools.js";
|
|
18
18
|
import { Menu } from "/assets/ui-menu.js";
|
|
19
|
+
import { themeMenuItems, themesStore } from "/assets/app-themes.js";
|
|
20
|
+
import { colorMenuItem } from "/assets/identity-color.js";
|
|
21
|
+
import { IdentityCard, useCard } from "/assets/identity-card.js";
|
|
22
|
+
import { AgentWidget, instanceBinds, widgetFor } from "/assets/agent-widget.js";
|
|
19
23
|
import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
|
|
20
24
|
import { toast } from "/assets/ui-toast.js";
|
|
21
25
|
import "./chat-strings.js";
|
|
@@ -27,10 +31,10 @@ export function DetailsPanel({ route, navKey }) {
|
|
|
27
31
|
const name = route.instance;
|
|
28
32
|
const inst = app.instances.find((i) => i.name === name) || null;
|
|
29
33
|
useEffect(() => { setTitle(`${name} · ${t("app.details")}`); }, [name, navKey]);
|
|
30
|
-
if (!app.ready) return html`<div class="panel p-details"><${PanelHeader} title=${name} /><div class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
34
|
+
if (!app.ready) return html`<div data-effect-panel="details" class="panel p-details"><${PanelHeader} title=${name} /><div data-trust="panel-content" class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
31
35
|
if (!inst) {
|
|
32
|
-
return html`<div class="panel p-details"><${PanelHeader} title=${name} />
|
|
33
|
-
<div class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
36
|
+
return html`<div data-effect-panel="details" class="panel p-details"><${PanelHeader} title=${name} />
|
|
37
|
+
<div data-trust="panel-content" class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
34
38
|
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} /></div></div>`;
|
|
35
39
|
}
|
|
36
40
|
return html`<${DetailsView} key=${name} name=${name} inst=${inst} navKey=${navKey} exec=${app.exec[name]}
|
|
@@ -38,7 +42,10 @@ export function DetailsPanel({ route, navKey }) {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
45
|
+
useStore(themesStore); // #1629: Lock / Unlock follows the themes as read
|
|
41
46
|
const lease = useLease(`details:${name}`);
|
|
47
|
+
// #1629 r4 §1: the identity card at the top, read when the status frame's card_v moves.
|
|
48
|
+
const card = useCard(name, inst.card_v);
|
|
42
49
|
const [d, setD] = useState(null);
|
|
43
50
|
const [failed, setFailed] = useState(false);
|
|
44
51
|
const [busy, setBusy] = useState("");
|
|
@@ -92,6 +99,8 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
92
99
|
{ key: "edit", label: t("chat.dEditInSettings"), icon: "settings", onSelect: editInSettings },
|
|
93
100
|
st === "running" ? { key: "pause", label: t("chat.dPause"), icon: "pause", disabled: !!busy, onSelect: () => pauseWake("pause") } : null,
|
|
94
101
|
st === "paused" ? { key: "wake", label: t("chat.dWake"), icon: "play", disabled: !!busy, onSelect: () => pauseWake("wake") } : null,
|
|
102
|
+
colorMenuItem(name, inst), // #1958
|
|
103
|
+
...themeMenuItems(name), // #1629
|
|
95
104
|
] : [
|
|
96
105
|
{ key: "edit", label: t("chat.dEditInSettings"), icon: "settings", onSelect: editInSettings },
|
|
97
106
|
st === "running" ? null : st === "paused" ? null : { key: "start", label: t("chat.start"), icon: "play", disabled: !!busy, onSelect: () => lifecycle("start") },
|
|
@@ -99,6 +108,9 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
99
108
|
st === "running" ? { key: "stop", label: t("chat.stopInstance"), icon: "stop", disabled: !!busy, onSelect: () => lifecycle("stop") } : null,
|
|
100
109
|
st === "running" ? { key: "pause", label: t("chat.dPause"), icon: "pause", disabled: !!busy, onSelect: () => pauseWake("pause") } : null,
|
|
101
110
|
st === "paused" ? { key: "wake", label: t("chat.dWake"), icon: "play", disabled: !!busy, onSelect: () => pauseWake("wake") } : null,
|
|
111
|
+
colorMenuItem(name, inst), // #1958: its identity colour (the public link too)
|
|
112
|
+
// #1629: a person's Lock and Reset of this agent's own web theme (not over the public link).
|
|
113
|
+
...themeMenuItems(name),
|
|
102
114
|
];
|
|
103
115
|
|
|
104
116
|
const cls = statusClass(inst, exec, awaiting);
|
|
@@ -141,8 +153,9 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
141
153
|
<span class="mono muted">${a.timestamp ? new Date(`${a.timestamp.replace(" ", "T")}Z`).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}</span>
|
|
142
154
|
<span class="ev">${a.event}</span> ${a.summary || ""}</div>`) : html`<p class="note">${t("chat.dNoActivity")}</p>`}</section>`;
|
|
143
155
|
}
|
|
144
|
-
return html`<div class="panel p-details">
|
|
156
|
+
return html`<div data-effect-panel="details" class="panel p-details">
|
|
145
157
|
<${PanelHeader} title=${name} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="details" />`}><${HeaderTools} navKey=${navKey} /><${Menu} items=${items} label=${t("app.more")} /></${PanelHeader}>
|
|
146
|
-
<div class="panel-body"><div class="col" ref=${body}>${busy ? html`<p class="note" role="status">${t("chat.dWorking")}</p>` : null}
|
|
158
|
+
<div data-trust="panel-content" class="panel-body"><div class="col" ref=${body}>${busy ? html`<p class="note" role="status">${t("chat.dWorking")}</p>` : null}<${IdentityCard} name=${name} card=${card} />
|
|
159
|
+
<${AgentWidget} slot="details" widget=${widgetFor(name, "details")} binds=${instanceBinds(inst, exec, awaiting)} />${content}</div></div>
|
|
147
160
|
</div>`;
|
|
148
161
|
}
|
package/dist/ui/panel-fleet.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// here re-reads anything). Every read is under the navigation's lease: a list that arrives after the person moved on
|
|
6
6
|
// is dropped (#1408 §4).
|
|
7
7
|
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
8
|
-
import { t, register } from "/assets/app-i18n.js";
|
|
8
|
+
import { t, register, lang } from "/assets/app-i18n.js";
|
|
9
9
|
import { appStore, useStore } from "/assets/app-store.js";
|
|
10
10
|
import { useLease } from "/assets/app-ctx.js";
|
|
11
11
|
import { PanelHeader, setTitle } from "/assets/app-shell.js";
|
|
@@ -27,6 +27,7 @@ register("fleet", {
|
|
|
27
27
|
hostMemory_elevated: "Host memory pressure: elevated — new agents start one at a time, at least 5 s apart",
|
|
28
28
|
hostMemory_critical: "Host memory pressure: critical — new agents wait for memory to recover",
|
|
29
29
|
title: "Fleet", tasks: "Tasks", schedules: "Schedules", teams: "Teams", org: "Org chart", cache: "Cache", config: "Config",
|
|
30
|
+
docs: "Docs", docsNewTab: "Docs (opens in a new tab)",
|
|
30
31
|
newTask: "New task", newSchedule: "New schedule", newTeam: "New team",
|
|
31
32
|
noTasks: "No tasks yet", noTasksHint: "Create one to coordinate fleet work.", noSchedules: "No schedules yet", noSchedulesHint: "Automate recurring work with cron.",
|
|
32
33
|
noTeams: "No teams yet", noTeamsHint: "Group instances for coordinated work.", countTasks: "{0} tasks", countSchedules: "{0} schedules", countTeams: "{0} teams", countTask: "1 task", countSchedule: "1 schedule", countTeam: "1 team",
|
|
@@ -57,6 +58,7 @@ register("fleet", {
|
|
|
57
58
|
hostMemory_elevated: "主機記憶體壓力偏高:新的 agent 一次啟動一個,至少間隔 5 秒",
|
|
58
59
|
hostMemory_critical: "主機記憶體壓力嚴重:新的 agent 會等記憶體恢復再啟動",
|
|
59
60
|
title: "Fleet", tasks: "Tasks", schedules: "排程", teams: "Teams", org: "組織圖", cache: "快取", config: "設定",
|
|
61
|
+
docs: "文件", docsNewTab: "文件(在新分頁開啟)",
|
|
60
62
|
newTask: "新增 task", newSchedule: "新增排程", newTeam: "新增 team",
|
|
61
63
|
noTasks: "還沒有 task", noTasksHint: "建立一個來協調 fleet 的工作。", noSchedules: "還沒有排程", noSchedulesHint: "用 cron 自動執行例行工作。",
|
|
62
64
|
noTeams: "還沒有 team", noTeamsHint: "把 instance 分組一起工作。", countTasks: "{0} 個 task", countSchedules: "{0} 個排程", countTeams: "{0} 個 team", countTask: "1 個 task", countSchedule: "1 個排程", countTeam: "1 個 team",
|
|
@@ -84,6 +86,11 @@ register("fleet", {
|
|
|
84
86
|
},
|
|
85
87
|
});
|
|
86
88
|
|
|
89
|
+
// The project's docs site (website/, GitHub Pages), in the dashboard's language — its own pages, not the app's.
|
|
90
|
+
const DOCS_SITE = "https://songsid.github.io/AgEnD";
|
|
91
|
+
export function docsUrl(language = lang()) {
|
|
92
|
+
return `${DOCS_SITE}${language === "zh-TW" ? "/zh-tw" : ""}/docs/web-guide/`;
|
|
93
|
+
}
|
|
87
94
|
const ICONS = { tasks: "tasks", schedules: "clock", teams: "team", org: "org", cache: "chart", config: "sliders" };
|
|
88
95
|
const BACKENDS = ["claude-code", "codex", "opencode", "kiro-cli", "antigravity", "grok", "muse"];
|
|
89
96
|
|
|
@@ -127,14 +134,20 @@ export function FleetPanel({ route, navKey }) {
|
|
|
127
134
|
// #1685: host memory pressure slowing or holding new agents — shown here, where macOS's routine "elevated" is not a chat notice.
|
|
128
135
|
const { hostMemory } = useStore(appStore);
|
|
129
136
|
const sub = hostMemory ? html`<span class=${`status host-mem ${hostMemory}`} role="status"><span class=${`dot ${hostMemory === "critical" ? "bad" : "warn"}`} aria-hidden="true"></span>${t(`fleet.hostMemory_${hostMemory}`)}</span>` : null;
|
|
130
|
-
return html`<div class="panel p-fleet">
|
|
131
|
-
<${PanelHeader} title=${t("fleet.title")} sub=${sub}><${HeaderTools} navKey=${navKey} /></${PanelHeader}>
|
|
132
|
-
<nav class="seg" aria-label=${t("fleet.title")}>${FLEET_TABS.map(k => html`<a key=${k} href=${fleetPath(k)} class=${`seg-item${k === tab ? " active" : ""}`}
|
|
137
|
+
return html`<div data-effect-panel="fleet" class="panel p-fleet">
|
|
138
|
+
<${PanelHeader} title=${t("fleet.title")} sub=${sub}><${DocsLink} /><${HeaderTools} navKey=${navKey} /></${PanelHeader}>
|
|
139
|
+
<nav data-trust="panel-navigation" class="seg" aria-label=${t("fleet.title")}>${FLEET_TABS.map(k => html`<a key=${k} href=${fleetPath(k)} class=${`seg-item${k === tab ? " active" : ""}`}
|
|
133
140
|
aria-current=${k === tab ? "page" : undefined}><${Icon} name=${ICONS[k]} size=${16} /><span>${t(`fleet.${k}`)}</span></a>`)}</nav>
|
|
134
|
-
<div class="panel-body"><div class=${`col${tab === "org" || tab === "cache" ? " col-wide" : ""}`}><${Body} lease=${lease} /></div></div>
|
|
141
|
+
<div data-trust="panel-content" class="panel-body"><div class=${`col${tab === "org" || tab === "cache" ? " col-wide" : ""}`}><${Body} lease=${lease} /></div></div>
|
|
135
142
|
</div>`;
|
|
136
143
|
}
|
|
137
144
|
|
|
145
|
+
/** #1844: the project's docs, from the overview — a link out (a new tab, no opener), not a Fleet tab; in front of the shared controls. */
|
|
146
|
+
function DocsLink() {
|
|
147
|
+
return html`<a class="btn btn-ghost btn-sm hd-docs" href=${docsUrl()} target="_blank" rel="noopener noreferrer" aria-label=${t("fleet.docsNewTab")} title=${t("fleet.docsNewTab")}>
|
|
148
|
+
<${Icon} name="book" size=${16} /><span class="hide-narrow" aria-hidden="true">${t("fleet.docs")}</span><${Icon} name="external" size=${12} cls="hd-ext" /></a>`;
|
|
149
|
+
}
|
|
150
|
+
|
|
138
151
|
function ListHead({ count, label, action }) {
|
|
139
152
|
return html`<div class="list-head"><span>${count}</span>${action ? html`<button type="button" class="btn btn-primary" onClick=${action.onClick}><${Icon} name="plus" size=${16} />${label}</button>` : null}</div>`;
|
|
140
153
|
}
|
package/dist/ui/panel-log.js
CHANGED
|
@@ -17,7 +17,7 @@ import { appStore, useStore } from "/assets/app-store.js";
|
|
|
17
17
|
import { useLease } from "/assets/app-ctx.js";
|
|
18
18
|
import { PanelHeader, setTitle, statusClass, statusLabel, openDrawer } from "/assets/app-shell.js";
|
|
19
19
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
20
|
-
import { HeaderTools } from "/assets/header-tools.js";
|
|
20
|
+
import { HeaderSlot, HeaderTools } from "/assets/header-tools.js";
|
|
21
21
|
import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
|
|
22
22
|
import { Icon } from "/assets/ui-icons.js";
|
|
23
23
|
import { toast } from "/assets/ui-toast.js";
|
|
@@ -29,7 +29,7 @@ register("log", {
|
|
|
29
29
|
en: {
|
|
30
30
|
offTitle: "The Log is off",
|
|
31
31
|
offBody: "Turn it on to see each agent's work step by step: what it was asked, its replies, every tool call with its arguments and result, errors, and fleet events. It reads the agent's own transcript only while this tab is open, and masks secret values.",
|
|
32
|
-
enable: "Turn on the Log", enabling: "Waiting for a fleet admin to confirm it in General…", enabled: "The Log is on.",
|
|
32
|
+
enable: "Turn on the Log", enabling: "Waiting for a fleet admin to confirm it in chat (General topic) or on the host…", enabled: "The Log is on.",
|
|
33
33
|
enableFailed: "The Log was not turned on: {0}", offPublic: "A fleet admin can turn it on in Settings → Web.",
|
|
34
34
|
unsupported: "{0} has no transcript AgEnD can read, so this Log shows fleet events only. View shows its screen.",
|
|
35
35
|
kiroWhy: "kiro's own steps are shown only when AgEnD can prove which conversation it is in now. {0} Fleet events are shown meanwhile.",
|
|
@@ -67,7 +67,7 @@ register("log", {
|
|
|
67
67
|
"zh-TW": {
|
|
68
68
|
offTitle: "紀錄未開啟",
|
|
69
69
|
offBody: "開啟後可逐步看到每個 agent 的工作:收到的要求、回覆、每次工具呼叫的參數與結果、錯誤,以及 fleet 事件。只在這個分頁開著時讀取 agent 自己的對話紀錄,機密值會遮蔽。",
|
|
70
|
-
enable: "開啟紀錄", enabling: "等待 fleet admin
|
|
70
|
+
enable: "開啟紀錄", enabling: "等待 fleet admin 在聊天(General topic)或主機上確認…", enabled: "紀錄已開啟。",
|
|
71
71
|
enableFailed: "紀錄沒有開啟:{0}", offPublic: "fleet admin 可以在「設定 → 網頁」開啟。",
|
|
72
72
|
unsupported: "{0} 沒有 AgEnD 讀得到的對話紀錄,所以這裡只顯示 fleet 事件。「檢視」可以看它的畫面。",
|
|
73
73
|
kiroWhy: "只有在 AgEnD 能證明 kiro 目前所在的對話時,才會顯示它自己的步驟。{0}目前先顯示 fleet 事件。",
|
|
@@ -200,10 +200,10 @@ export function LogPanel({ route, navKey }) {
|
|
|
200
200
|
const name = route.instance;
|
|
201
201
|
const inst = app.instances.find((i) => i.name === name) || null;
|
|
202
202
|
useEffect(() => { setTitle(`${name} · ${t("app.log")}`); }, [name, navKey]);
|
|
203
|
-
if (!app.ready) return html`<div class="panel p-log"><${PanelHeader} title=${name} /><div class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
203
|
+
if (!app.ready) return html`<div data-effect-panel="log" class="panel p-log"><${PanelHeader} title=${name} /><div data-trust="panel-content" class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
204
204
|
if (!inst) {
|
|
205
|
-
return html`<div class="panel p-log"><${PanelHeader} title=${name} />
|
|
206
|
-
<div class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
205
|
+
return html`<div data-effect-panel="log" class="panel p-log"><${PanelHeader} title=${name} />
|
|
206
|
+
<div data-trust="panel-content" class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
207
207
|
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} /></div></div>`;
|
|
208
208
|
}
|
|
209
209
|
return html`<${LogView} key=${name} name=${name} inst=${inst} navKey=${navKey} exec=${app.exec[name]}
|
|
@@ -372,13 +372,13 @@ function LogView({ name, inst, navKey, exec, awaiting }) {
|
|
|
372
372
|
${items.length ? html`<ol class="log-list" role="log" aria-label=${t("app.log")}>${items.map((x, i) => html`<${Row} key=${`${x.kind}:${x.id}`} x=${x} prev=${items[i - 1]} />`)}</ol>`
|
|
373
373
|
: html`<p class="note log-empty">${tl("empty")}</p>`}`;
|
|
374
374
|
}
|
|
375
|
-
const tools = state.phase === "on" ? html`<div class="log-bar" role="group" aria-label=${tl("filter")}>
|
|
375
|
+
const tools = state.phase === "on" ? html`<div data-trust="panel-controls" class="log-bar" role="group" aria-label=${tl("filter")}>
|
|
376
376
|
${["all", "tools", "errors"].map((k) => html`<button key=${k} type="button" class=${`chip-btn${filter === k ? " on" : ""}`} aria-pressed=${filter === k ? "true" : "false"} onClick=${() => setFilter(k)}>${tl(k)}</button>`)}
|
|
377
377
|
<span class="grow"></span><span class="log-live" title=${tl("live")}><span class="dot running" aria-hidden="true"></span>${tl("live")}</span></div>` : null;
|
|
378
|
-
return html`<div class="panel p-log">
|
|
379
|
-
<${PanelHeader} title=${name} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="log" />`}><${HeaderTools} navKey=${navKey} /></${PanelHeader}>
|
|
378
|
+
return html`<div data-effect-panel="log" class="panel p-log">
|
|
379
|
+
<${PanelHeader} title=${name} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="log" />`}><${HeaderTools} navKey=${navKey} /><${HeaderSlot} /></${PanelHeader}>
|
|
380
380
|
${tools}
|
|
381
|
-
<div class="panel-body log-body" ref=${scroller} onScroll=${onScroll}><div class="col log-col">${content}</div></div>
|
|
381
|
+
<div data-trust="panel-content" class="panel-body log-body" ref=${scroller} onScroll=${onScroll}><div class="col log-col">${content}</div></div>
|
|
382
382
|
</div>`;
|
|
383
383
|
}
|
|
384
384
|
|