@songsid/agend 2.3.4-beta.5 → 2.3.5-alpha.2
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 -0
- package/README.zh-TW.md +2 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/dist/agent-endpoint.d.ts +5 -1
- package/dist/agent-endpoint.js +12 -2
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/backend/claude-code.d.ts +18 -12
- package/dist/backend/claude-code.js +225 -136
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-package.d.ts +5 -2
- package/dist/backend/codex-package.js +1 -5
- package/dist/backend/codex-package.js.map +1 -1
- package/dist/backend/codex.d.ts +136 -113
- package/dist/backend/codex.js +1271 -1219
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok-model-cache.d.ts +7 -0
- package/dist/backend/grok-model-cache.js +65 -0
- package/dist/backend/grok-model-cache.js.map +1 -0
- package/dist/backend/grok.d.ts +2 -0
- package/dist/backend/grok.js +22 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/native-pane.d.ts +9 -0
- package/dist/backend/native-pane.js +59 -0
- package/dist/backend/native-pane.js.map +1 -0
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +2 -0
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +59 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +16 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +62 -5
- package/dist/daemon.js +760 -240
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +15 -3
- package/dist/delivery-consumed-watch.js +23 -1
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.d.ts +5 -0
- package/dist/delivery-outbox.js +32 -4
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +2 -35
- package/dist/delivery-reconciliation.js +2 -156
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -2
- 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 +125 -2
- package/dist/fleet-manager.js +1157 -27
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +92 -0
- package/dist/fleet-windows-runtime.js +373 -0
- package/dist/fleet-windows-runtime.js.map +1 -0
- package/dist/instance-config-impact.js +4 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +20 -3
- package/dist/instance-lifecycle.js +358 -156
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/local-pane-endpoint.d.ts +46 -0
- package/dist/local-pane-endpoint.js +189 -0
- package/dist/local-pane-endpoint.js.map +1 -0
- package/dist/local-pane-launcher.d.ts +2 -0
- package/dist/local-pane-launcher.js +38 -0
- package/dist/local-pane-launcher.js.map +1 -0
- package/dist/local-pane-stage.ps1 +101 -0
- package/dist/locale.js +34 -0
- package/dist/locale.js.map +1 -1
- package/dist/model-catalog-defaults.d.ts +14 -0
- package/dist/model-catalog-defaults.js +20 -0
- package/dist/model-catalog-defaults.js.map +1 -0
- package/dist/native-agent-admission.d.ts +7 -0
- package/dist/native-agent-admission.js +26 -0
- package/dist/native-agent-admission.js.map +1 -0
- package/dist/native-daemon-client.d.ts +13 -0
- package/dist/native-daemon-client.js +28 -0
- package/dist/native-daemon-client.js.map +1 -0
- package/dist/native-instance-api.d.ts +14 -0
- package/dist/native-instance-api.js +205 -0
- package/dist/native-instance-api.js.map +1 -0
- package/dist/native-instance-input.d.ts +84 -0
- package/dist/native-instance-input.js +54 -0
- package/dist/native-instance-input.js.map +1 -0
- package/dist/native-instance-registry.d.ts +32 -0
- package/dist/native-instance-registry.js +105 -0
- package/dist/native-instance-registry.js.map +1 -0
- package/dist/native-mcp.d.ts +40 -0
- package/dist/native-mcp.js +278 -0
- package/dist/native-mcp.js.map +1 -0
- package/dist/native-model-catalog.d.ts +5 -0
- package/dist/native-model-catalog.js +76 -0
- package/dist/native-model-catalog.js.map +1 -0
- package/dist/native-pane-crash-budget.d.ts +20 -0
- package/dist/native-pane-crash-budget.js +60 -0
- package/dist/native-pane-crash-budget.js.map +1 -0
- package/dist/native-pane-create.d.ts +26 -0
- package/dist/native-pane-create.js +53 -0
- package/dist/native-pane-create.js.map +1 -0
- package/dist/native-pane-lifecycle.d.ts +65 -0
- package/dist/native-pane-lifecycle.js +227 -0
- package/dist/native-pane-lifecycle.js.map +1 -0
- package/dist/native-pane-manager.d.ts +58 -0
- package/dist/native-pane-manager.js +563 -0
- package/dist/native-pane-manager.js.map +1 -0
- package/dist/native-pane-output-log.d.ts +15 -0
- package/dist/native-pane-output-log.js +108 -0
- package/dist/native-pane-output-log.js.map +1 -0
- package/dist/native-pane-reconciliation.d.ts +4 -0
- package/dist/native-pane-reconciliation.js +40 -0
- package/dist/native-pane-reconciliation.js.map +1 -0
- package/dist/native-pane-recovery.d.ts +12 -0
- package/dist/native-pane-recovery.js +10 -0
- package/dist/native-pane-recovery.js.map +1 -0
- package/dist/native-pane-tools.d.ts +2 -0
- package/dist/native-pane-tools.js +14 -0
- package/dist/native-pane-tools.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -0
- package/dist/needs-you-hub.js +1 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +12 -1
- package/dist/needs-you.js +8 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +16 -2
- package/dist/outbound-handlers.js +67 -3
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +38 -0
- package/dist/outbound-schemas.js +12 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-port.d.ts +107 -0
- package/dist/pane-port.js +2 -0
- package/dist/pane-port.js.map +1 -0
- package/dist/runtime-api.d.ts +8 -0
- package/dist/runtime-api.js +96 -0
- package/dist/runtime-api.js.map +1 -0
- package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +2 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +19 -0
- package/dist/runtime-assets/@xterm/addon-serialize/package.json +29 -0
- package/dist/runtime-assets/@xterm/headless/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +2 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
- package/dist/runtime-assets/@xterm/headless/package.json +29 -0
- package/dist/runtime-assets/node-pty/CONPTY-LICENSE +21 -0
- package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +503 -0
- package/dist/runtime-assets/node-pty/LICENSE +69 -0
- package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/runtime-assets/node-pty/lib/index.js +52 -0
- package/dist/runtime-assets/node-pty/lib/interfaces.js +7 -0
- package/dist/runtime-assets/node-pty/lib/shared/conout.js +11 -0
- package/dist/runtime-assets/node-pty/lib/terminal.js +190 -0
- package/dist/runtime-assets/node-pty/lib/types.js +7 -0
- package/dist/runtime-assets/node-pty/lib/unixTerminal.js +346 -0
- package/dist/runtime-assets/node-pty/lib/utils.js +39 -0
- package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +125 -0
- package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +320 -0
- package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +199 -0
- package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/runtime-assets/node-pty/package.json +64 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/dist/runtime-bundle.d.ts +17 -0
- package/dist/runtime-bundle.js +147 -0
- package/dist/runtime-bundle.js.map +1 -0
- package/dist/runtime-cli.d.ts +2 -0
- package/dist/runtime-cli.js +117 -0
- package/dist/runtime-cli.js.map +1 -0
- package/dist/runtime-client-store.d.ts +49 -0
- package/dist/runtime-client-store.js +292 -0
- package/dist/runtime-client-store.js.map +1 -0
- package/dist/runtime-client.d.ts +100 -0
- package/dist/runtime-client.js +700 -0
- package/dist/runtime-client.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +82 -0
- package/dist/runtime-coordinator.js +864 -0
- package/dist/runtime-coordinator.js.map +1 -0
- package/dist/runtime-pane-assets.d.ts +17 -0
- package/dist/runtime-pane-assets.js +23 -0
- package/dist/runtime-pane-assets.js.map +1 -0
- package/dist/runtime-pane-boot.d.ts +2 -0
- package/dist/runtime-pane-boot.js +24 -0
- package/dist/runtime-pane-boot.js.map +1 -0
- package/dist/runtime-pane-codex-index.d.ts +1 -0
- package/dist/runtime-pane-codex-index.js +47 -0
- package/dist/runtime-pane-codex-index.js.map +1 -0
- package/dist/runtime-pane-config.d.ts +16 -0
- package/dist/runtime-pane-config.js +54 -0
- package/dist/runtime-pane-config.js.map +1 -0
- package/dist/runtime-pane-host.d.ts +43 -0
- package/dist/runtime-pane-host.js +403 -0
- package/dist/runtime-pane-host.js.map +1 -0
- package/dist/runtime-pane-job-owner.d.ts +1 -0
- package/dist/runtime-pane-job-owner.js +29 -0
- package/dist/runtime-pane-job-owner.js.map +1 -0
- package/dist/runtime-pane-job.ps1 +116 -0
- package/dist/runtime-pane-link.d.ts +40 -0
- package/dist/runtime-pane-link.js +246 -0
- package/dist/runtime-pane-link.js.map +1 -0
- package/dist/runtime-pane-mcp-protocol.d.ts +32 -0
- package/dist/runtime-pane-mcp-protocol.js +39 -0
- package/dist/runtime-pane-mcp-protocol.js.map +1 -0
- package/dist/runtime-pane-mcp-relay.d.ts +17 -0
- package/dist/runtime-pane-mcp-relay.js +70 -0
- package/dist/runtime-pane-mcp-relay.js.map +1 -0
- package/dist/runtime-pane-mcp.d.ts +43 -0
- package/dist/runtime-pane-mcp.js +137 -0
- package/dist/runtime-pane-mcp.js.map +1 -0
- package/dist/runtime-pane-native.d.ts +45 -0
- package/dist/runtime-pane-native.js +65 -0
- package/dist/runtime-pane-native.js.map +1 -0
- package/dist/runtime-pane-output.d.ts +19 -0
- package/dist/runtime-pane-output.js +53 -0
- package/dist/runtime-pane-output.js.map +1 -0
- package/dist/runtime-pane-port.d.ts +134 -0
- package/dist/runtime-pane-port.js +537 -0
- package/dist/runtime-pane-port.js.map +1 -0
- package/dist/runtime-pane-private.d.ts +14 -0
- package/dist/runtime-pane-private.js +51 -0
- package/dist/runtime-pane-private.js.map +1 -0
- package/dist/runtime-pane-private.ps1 +14 -0
- package/dist/runtime-pane-process.d.ts +4 -0
- package/dist/runtime-pane-process.js +108 -0
- package/dist/runtime-pane-process.js.map +1 -0
- package/dist/runtime-pane-protocol.d.ts +169 -0
- package/dist/runtime-pane-protocol.js +189 -0
- package/dist/runtime-pane-protocol.js.map +1 -0
- package/dist/runtime-pane-screen.d.ts +19 -0
- package/dist/runtime-pane-screen.js +76 -0
- package/dist/runtime-pane-screen.js.map +1 -0
- package/dist/runtime-pane-service.d.ts +11 -0
- package/dist/runtime-pane-service.js +221 -0
- package/dist/runtime-pane-service.js.map +1 -0
- package/dist/runtime-pane-stdio-protocol.d.ts +54 -0
- package/dist/runtime-pane-stdio-protocol.js +94 -0
- package/dist/runtime-pane-stdio-protocol.js.map +1 -0
- package/dist/runtime-pane-stdio.d.ts +3 -0
- package/dist/runtime-pane-stdio.js +123 -0
- package/dist/runtime-pane-stdio.js.map +1 -0
- package/dist/runtime-pane-store.d.ts +33 -0
- package/dist/runtime-pane-store.js +164 -0
- package/dist/runtime-pane-store.js.map +1 -0
- package/dist/runtime-pane-transcript-protocol.d.ts +43 -0
- package/dist/runtime-pane-transcript-protocol.js +58 -0
- package/dist/runtime-pane-transcript-protocol.js.map +1 -0
- package/dist/runtime-pane-transcript.d.ts +45 -0
- package/dist/runtime-pane-transcript.js +605 -0
- package/dist/runtime-pane-transcript.js.map +1 -0
- package/dist/runtime-pane-worker.d.ts +1 -0
- package/dist/runtime-pane-worker.js +154 -0
- package/dist/runtime-pane-worker.js.map +1 -0
- package/dist/runtime-protocol.d.ts +149 -0
- package/dist/runtime-protocol.js +19 -0
- package/dist/runtime-protocol.js.map +1 -0
- package/dist/runtime-switches.d.ts +79 -0
- package/dist/runtime-switches.js +90 -0
- package/dist/runtime-switches.js.map +1 -0
- package/dist/runtime-transcript-delta-reader.d.ts +23 -0
- package/dist/runtime-transcript-delta-reader.js +74 -0
- package/dist/runtime-transcript-delta-reader.js.map +1 -0
- package/dist/runtime-transcript-source.d.ts +36 -0
- package/dist/runtime-transcript-source.js +189 -0
- package/dist/runtime-transcript-source.js.map +1 -0
- package/dist/runtime-windows-bridge.d.ts +41 -0
- package/dist/runtime-windows-bridge.js +157 -0
- package/dist/runtime-windows-bridge.js.map +1 -0
- package/dist/settings-api.js +58 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +28 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +15 -1
- package/dist/settings-confirmation.js +46 -9
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +23 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +11 -2
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/tmux-control.d.ts +2 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +2 -1
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-pane-host.d.ts +26 -0
- package/dist/tmux-pane-host.js +25 -0
- package/dist/tmux-pane-host.js.map +1 -0
- package/dist/topic-commands.js +3 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +1 -1
- package/dist/transcript-delta-reader.js +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-monitor.d.ts +3 -0
- package/dist/transcript-monitor.js +22 -46
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-needles.d.ts +35 -0
- package/dist/transcript-needles.js +158 -0
- package/dist/transcript-needles.js.map +1 -0
- package/dist/transcript-records.d.ts +21 -0
- package/dist/transcript-records.js +140 -0
- package/dist/transcript-records.js.map +1 -0
- package/dist/transcript-sources.d.ts +5 -0
- package/dist/transcript-sources.js +8 -79
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/ui/agent-proposals.js +90 -0
- package/dist/ui/agent-runtime.js +106 -0
- package/dist/ui/chat-store.js +13 -2
- package/dist/ui/chat-strings.js +48 -0
- package/dist/ui/cli-picker.js +42 -0
- package/dist/ui/native-instance-settings.js +47 -0
- package/dist/ui/native-pane-recovery.js +45 -0
- package/dist/ui/panel-chat.js +61 -32
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +99 -18
- package/dist/ui/panel-needs.js +152 -3
- package/dist/ui/panel-runtimes.js +231 -0
- package/dist/ui/panel-settings.js +14 -8
- package/dist/ui/panel-windows-agent.js +86 -0
- package/dist/ui/panel-windows-cli.js +143 -0
- package/dist/ui/provider-marks.js +83 -0
- package/dist/ui/runtime-catalog.js +55 -0
- package/dist/ui/settings-catalog.js +37 -10
- package/dist/ui/settings-confirm.js +3 -1
- package/dist/ui/settings-dialogs.js +14 -5
- package/dist/ui/settings-registry.js +5 -0
- package/dist/ui/settings-strings.js +14 -0
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +6 -2
- package/dist/ui/shared/app-shell.js +3 -2
- package/dist/ui/shared/app-store.js +1 -0
- package/dist/ui/shared/app-stream.js +3 -1
- package/dist/ui/shared/app.css +301 -0
- package/dist/ui/shared/app.js +4 -0
- package/dist/ui/shared/header-tools.js +6 -4
- package/dist/ui/shared/instance-nav.js +20 -4
- package/dist/ui/shared/instance-switch.js +4 -3
- package/dist/ui/shared/ui-menu.js +28 -8
- package/dist/ui/shared/view-strings.js +6 -0
- package/dist/ui/windows-agents-nav.js +2 -0
- package/dist/ui/windows-cli-catalog.js +79 -0
- package/dist/update-check.d.ts +8 -2
- package/dist/update-check.js +5 -2
- package/dist/update-check.js.map +1 -1
- package/dist/web-api.d.ts +25 -0
- package/dist/web-api.js +171 -6
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +19 -2
- package/dist/web-chat-history.js +72 -3
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -1
- package/dist/web-shell-routes.js +7 -2
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/windows-agents.d.ts +112 -0
- package/dist/windows-agents.js +463 -0
- package/dist/windows-agents.js.map +1 -0
- package/dist/windows-cli-api.d.ts +23 -0
- package/dist/windows-cli-api.js +158 -0
- package/dist/windows-cli-api.js.map +1 -0
- package/dist/windows-cli-providers.d.ts +115 -0
- package/dist/windows-cli-providers.js +429 -0
- package/dist/windows-cli-providers.js.map +1 -0
- package/dist/windows-cli-worker.d.ts +58 -0
- package/dist/windows-cli-worker.js +479 -0
- package/dist/windows-cli-worker.js.map +1 -0
- package/dist/windows-cli.d.ts +115 -0
- package/dist/windows-cli.js +402 -0
- package/dist/windows-cli.js.map +1 -0
- package/dist/windows-native-mcp.d.ts +19 -0
- package/dist/windows-native-mcp.js +143 -0
- package/dist/windows-native-mcp.js.map +1 -0
- package/dist/windows-pane-mcp.d.ts +26 -0
- package/dist/windows-pane-mcp.js +187 -0
- package/dist/windows-pane-mcp.js.map +1 -0
- package/package.json +9 -3
- package/templates/runtime-assets/conpty-LICENSE +21 -0
- package/templates/runtime-assets/conpty-NOTICE.md +503 -0
- package/templates/runtime-assets/local-pane-stage.ps1 +101 -0
- package/templates/runtime-assets/runtime-pane-job.ps1 +116 -0
- package/templates/runtime-assets/runtime-pane-private.ps1 +14 -0
- package/templates/runtime-assets/xterm-LICENSE +21 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
2
|
+
import { register, t } from "/assets/app-i18n.js";
|
|
3
|
+
import { useLease } from "/assets/app-ctx.js";
|
|
4
|
+
import { PanelHeader, setTitle } from "/assets/app-shell.js";
|
|
5
|
+
import { Icon } from "/assets/ui-icons.js";
|
|
6
|
+
import { CliProductMark, cliLabel } from "./cli-picker.js";
|
|
7
|
+
import { appStore, useStore } from "/assets/app-store.js";
|
|
8
|
+
import { navigate } from "/assets/app-nav.js";
|
|
9
|
+
import { chatPath } from "/assets/app-route.js";
|
|
10
|
+
|
|
11
|
+
register("winagent", {
|
|
12
|
+
"zh-TW": { loading:"正在載入 Windows Agent…", send:"傳送", message:"傳送任務給 Windows Agent", empty:"開始與 Windows Agent 對話", emptyHint:"對話使用 Windows 本機 Codex,後續訊息會接續同一個對話。", settings:"Windows CLI 設定", waiting:"Windows Codex 正在處理…", cancel:"取消任務", you:"你", refresh:"更新", read:"唯讀", write:"工作目錄可寫入", limit:"每次執行最多五分鐘後請求取消,同時一個 Windows 任務。", uncertain:"提交結果不明,請先更新確認,避免重複派工。", blocked:"上次執行的結束狀態不明。請先檢查 Windows 程序是否已停止。", recover:"已確認程序停止,解除鎖定" },
|
|
13
|
+
en: { loading:"Loading Windows agent…", send:"Send", message:"Send a task to the Windows agent", empty:"Start a Windows conversation", emptyHint:"Runs native Windows Codex. Follow-up messages continue the same conversation.", settings:"Windows CLI settings", waiting:"Windows Codex is working…", cancel:"Cancel task", you:"You", refresh:"Refresh", read:"Read only", write:"Workspace write", limit:"Cancellation after five minutes per turn; one Windows task at a time.", uncertain:"Submission outcome is unknown. Refresh before sending again.", blocked:"The last execution outcome is unknown. Check that its Windows processes have stopped.", recover:"Processes stopped — unlock agent" },
|
|
14
|
+
});
|
|
15
|
+
const tn = key => t(`winagent.${key}`);
|
|
16
|
+
register("winagent", {
|
|
17
|
+
"zh-TW": { emptyHint:"使用所選 Windows 本機 CLI,後續訊息會接續同一個對話。", waiting:"Windows CLI 正在處理…", write:"使用本機 CLI 權限" },
|
|
18
|
+
en: { emptyHint:"Runs the selected native Windows CLI. Follow-up messages continue the same conversation.", waiting:"Windows CLI is working…", write:"Native CLI permissions" },
|
|
19
|
+
});
|
|
20
|
+
register("winagent", {
|
|
21
|
+
"zh-TW": { starting:"準備啟動", running:"執行中", cancelling:"正在取消", completed:"已完成", failed:"失敗", cancelled:"已取消", interrupted:"已中斷", noOutput:"這次執行沒有文字輸出。" },
|
|
22
|
+
en: { starting:"Starting", running:"Running", cancelling:"Cancelling", completed:"Completed", failed:"Failed", cancelled:"Cancelled", interrupted:"Interrupted", noOutput:"This turn returned no text." },
|
|
23
|
+
});
|
|
24
|
+
export function WindowsAgentPanel({ route, navKey }) {
|
|
25
|
+
const lease = useLease(navKey);
|
|
26
|
+
const { instances = [] } = useStore(appStore);
|
|
27
|
+
const canonical = route.panel === "windows-agent" ? instances.find(instance => instance.runtime === "windows" && instance.native_agent_id === route.instance)?.name : route.instance;
|
|
28
|
+
useEffect(() => { if (route.panel === "windows-agent" && canonical) navigate(chatPath(canonical),{replace:true}); },[canonical,route.panel]);
|
|
29
|
+
const [data,setData] = useState(null), [prompt,setPrompt] = useState(""), [error,setError] = useState("");
|
|
30
|
+
const [submitting,setSubmitting] = useState(false);
|
|
31
|
+
const request = useRef(null), polling = useRef(false), generation = useRef(0);
|
|
32
|
+
const api = async (path, body) => {
|
|
33
|
+
const r = await lease.fetch(path,{credentials:"same-origin",...(body === undefined ? {} : {method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})});
|
|
34
|
+
const value = await r.json();
|
|
35
|
+
if (!r.ok) { const e = new Error(value.error || `HTTP ${r.status}`); e.rejected = true; throw e; }
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
const common = route.panel === "chat";
|
|
39
|
+
const root = common ? `/ui/instances/${encodeURIComponent(route.instance)}` : `/ui/windows-cli/agents/${route.instance}`;
|
|
40
|
+
const refresh = async () => {
|
|
41
|
+
const mine = ++generation.current;
|
|
42
|
+
try {
|
|
43
|
+
const value = await api(root);
|
|
44
|
+
if (!lease.current() || mine !== generation.current) return;
|
|
45
|
+
setData({...value.agent,_route:route.instance}); setTitle(`${value.agent.name} · Windows`);
|
|
46
|
+
if (request.current && value.agent.turns.some(turn => turn.id === request.current.id)) { request.current = null; setSubmitting(false); setPrompt(""); }
|
|
47
|
+
} catch(e) { if (lease.current()) setError(e.message); }
|
|
48
|
+
};
|
|
49
|
+
useEffect(() => { request.current = null; setSubmitting(false); setPrompt(""); setError(""); void refresh(); },[lease]);
|
|
50
|
+
const agent = data?._route === route.instance ? data : null;
|
|
51
|
+
const { sandbox: fileAccess } = agent || {};
|
|
52
|
+
const busy = !!agent?.activeId;
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!busy || agent?.blocked) return;
|
|
55
|
+
const timer = lease.interval(async () => { if (polling.current) return; polling.current = true; try { await refresh(); } finally { polling.current = false; } },1000);
|
|
56
|
+
return () => lease.clear(timer);
|
|
57
|
+
},[lease,busy,agent?.blocked]);
|
|
58
|
+
const send = async e => {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
if (!agent || busy || submitting || request.current || !prompt.trim()) return;
|
|
61
|
+
const message = request.current = { id:crypto.randomUUID(), prompt };
|
|
62
|
+
setSubmitting(true); setError("");
|
|
63
|
+
try { await api(`${root}/messages`,{requestId:message.id,prompt:message.prompt}); }
|
|
64
|
+
catch(e) {
|
|
65
|
+
if (!lease.current()) return;
|
|
66
|
+
setError(e.rejected ? e.message : tn("uncertain"));
|
|
67
|
+
if (e.rejected) { request.current = null; setSubmitting(false); }
|
|
68
|
+
}
|
|
69
|
+
if (lease.current()) await refresh();
|
|
70
|
+
};
|
|
71
|
+
const cancel = async () => { try { await api(common ? `${root}/cancel` : `/ui/windows-cli/tasks/${agent.activeId}/cancel`,{}); if (lease.current()) await refresh(); } catch(e) { if (lease.current()) setError(e.message); } };
|
|
72
|
+
const recover = async () => { try { await api(`${root}/recover`,{confirmedStopped:true}); if (lease.current()) await refresh(); } catch(e) { if (lease.current()) setError(e.message); } };
|
|
73
|
+
return html`<div class="panel p-windows-agent"><${PanelHeader} title=${agent?.name || "Windows Agent"}>
|
|
74
|
+
<a class="btn btn-ghost btn-sm" href="/settings/agents"><${Icon} name="settings" size=${16} />${t("app.settings")}</a>
|
|
75
|
+
</${PanelHeader}>
|
|
76
|
+
<div class="panel-body"><div class="col windows-agent-conversation">
|
|
77
|
+
${agent ? html`<div class="windows-agent-identity"><span class="windows-cli-brand"><${CliProductMark} id=${agent.cli || "codex"} size=${24} /></span><div><strong>Windows · ${cliLabel(agent.cli || "codex")}${agent.model ? ` · ${agent.model}` : ""}</strong><code>${agent.cwd}</code></div><span class="pill">${tn(fileAccess === "read-only" ? "read" : "write")}</span></div>
|
|
78
|
+
${agent.description ? html`<p class="note">${agent.description}</p>` : null}
|
|
79
|
+
${!agent.turns.length ? html`<div class="windows-agent-empty"><${Icon} name="chat" size=${32} /><h2>${tn("empty")}</h2><p>${tn("emptyHint")}</p></div>` : agent.turns.map(turn => html`<article key=${turn.id} class="windows-agent-turn"><div class="windows-agent-human"><strong>${tn("you")}</strong><p>${turn.prompt}</p></div><div class="windows-agent-reply"><strong><${CliProductMark} id=${agent.cli || "codex"} size=${18} />${cliLabel(agent.cli || "codex")}</strong><pre tabIndex="0">${turn.output || tn(["starting","running","cancelling"].includes(turn.status) ? "waiting" : "noOutput")}</pre>${turn.error ? html`<p class="error">${turn.error}</p>` : null}<small>${tn(turn.status)}</small></div></article>`)}
|
|
80
|
+
` : html`<p class="note">${tn("loading")}</p>`}
|
|
81
|
+
${error ? html`<p class="error" role="alert">${error}</p>` : null}
|
|
82
|
+
${agent?.blocked ? html`<div class="windows-agent-blocked"><p>${tn("blocked")}</p><button type="button" class="btn" onClick=${recover}>${tn("recover")}</button></div>` : null}
|
|
83
|
+
</div></div>
|
|
84
|
+
<form class="windows-agent-composer" onSubmit=${send}><div class="windows-agent-input"><textarea aria-label=${tn("message")} placeholder=${tn("message")} rows="3" maxLength=${8000} value=${prompt} disabled=${!agent || busy || submitting} onInput=${e => setPrompt(e.target.value)} /><div><button type="button" class="icon-btn" aria-label=${tn("refresh")} onClick=${refresh}><${Icon} name="restart" size=${17} /></button>${busy && !agent?.blocked ? html`<button type="button" class="btn" onClick=${cancel}><${Icon} name="stop" size=${15} />${tn("cancel")}</button>` : html`<button type="submit" class="btn btn-primary" disabled=${!agent || busy || submitting || !prompt.trim()}><${Icon} name="send" size=${16} />${tn("send")}</button>`}</div></div><p class="note">${tn("limit")}</p></form>
|
|
85
|
+
</div>`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
2
|
+
import { t, register } from "/assets/app-i18n.js";
|
|
3
|
+
import { useLease } from "/assets/app-ctx.js";
|
|
4
|
+
import { PanelHeader, setTitle } from "/assets/app-shell.js";
|
|
5
|
+
import { Icon } from "/assets/ui-icons.js";
|
|
6
|
+
import { CliPicker, CliProductMark, cliLabel } from "./cli-picker.js";
|
|
7
|
+
import { ModelSelect } from "./settings-dialogs.js";
|
|
8
|
+
import { useWindowsCliCatalog, WindowsCliDiscoveryStatus } from "./windows-cli-catalog.js";
|
|
9
|
+
|
|
10
|
+
register("wincli", {
|
|
11
|
+
"zh-TW": { intro:"在 Windows 上執行一次性任務,使用本機已安裝的 CLI 和登入。", probe:"偵測 Windows CLI", probing:"正在偵測…", newTask:"派送 Windows Codex 任務", folder:"Windows 工作目錄", prompt:"任務內容", access:"檔案存取", readOnly:"唯讀", write:"工作目錄可寫入", limits:"目前支援 Codex 單次任務,同時一個,五分鐘後請求取消。使用 CLI 的沙箱與核准政策;此頁不提供互動核准按鈕。Claude 目前提供偵測。", run:"開始任務", results:"任務與結果", refresh:"更新", signedIn:"已登入", signedOut:"尚未登入", unknown:"登入狀態未知", missing:"未找到執行檔", empty:"還沒有任務。", cancel:"取消任務", starting:"準備啟動", running:"執行中", cancelling:"正在取消", cancelled:"已取消", completed:"已完成", failed:"失敗", waiting:"正在接收 Windows CLI 的輸出…", uncertain:"提交結果不明,請按「更新」確認任務狀態,勿立即重送。" },
|
|
12
|
+
en: { intro:"Run a one-off Windows task using locally installed CLIs and their sign-ins.", probe:"Detect Windows CLIs", probing:"Detecting…", newTask:"Run a Windows Codex task", folder:"Windows working directory", prompt:"Task", access:"File access", readOnly:"Read only", write:"Workspace write", limits:"Codex one-off tasks only: one at a time, cancellation requested after five minutes. The CLI owns sandbox and approval policy; this page has no interactive approval controls. Claude is detection-only for now.", run:"Start task", results:"Tasks and results", refresh:"Refresh", signedIn:"Signed in", signedOut:"Not signed in", unknown:"Sign-in unknown", missing:"Executable not found", empty:"No tasks yet.", cancel:"Cancel task", starting:"Starting", running:"Running", cancelling:"Cancelling", cancelled:"Cancelled", completed:"Completed", failed:"Failed", waiting:"Waiting for Windows CLI output…", uncertain:"Submission outcome is unknown. Refresh to check the task before sending it again." },
|
|
13
|
+
});
|
|
14
|
+
register("wincli", {
|
|
15
|
+
"zh-TW": { workspace:"Windows 本機工作區", native:"Windows 本機", providers:"本機 CLI", available:"可派工", unavailableBadge:"尚未就緒", detectionOnly:"僅偵測", notDetected:"尚未偵測", checking:"檢查中", path:"執行檔路徑", taskHint:"使用 Windows Codex,在指定專案中執行一次性任務。", folderHint:"請填入已存在的 Windows 專案資料夾。", promptPlaceholder:"例如:檢查這個專案的結構,說明如何在 Windows 上啟動。", readHint:"適合檢查、查詢與分析", writeHint:"適合修改程式與檔案", taskLimits:"同時 1 個任務 · 5 分鐘後請求取消", policy:"存取與核准方式", policyText:"沿用本機 CLI 的沙箱與核准政策,包含已設定的自動審查。此頁不提供互動核准按鈕。", ready:"Codex 已就緒", busy:"Windows 任務執行中", unavailable:"請先確認 Codex 已安裝並登入", historyHint:"查看執行狀態與 CLI 輸出", emptyHint:"派送第一個任務後,進度與結果會出現在這裡。", noOutput:"這個任務沒有回傳輸出。", records:"筆", historyNote:"保留最近 20 筆,重啟後清空", output:"執行輸出", submitting:"正在提交…" },
|
|
16
|
+
en: { workspace:"Your Windows workspace", native:"Native Windows", providers:"Local CLIs", available:"Tasks enabled", unavailableBadge:"Not ready", detectionOnly:"Detection only", notDetected:"Not detected yet", checking:"Checking", path:"Executable path", taskHint:"Run a one-off task in your project with Windows Codex.", folderHint:"Use an existing Windows project folder.", promptPlaceholder:"For example: inspect this project and explain how to run it on Windows.", readHint:"Inspect, query and analyze", writeHint:"Edit code and files", taskLimits:"One task at a time · Cancellation after 5 min", policy:"Access and approvals", policyText:"Uses the local CLI's sandbox and approval policy, including any configured automatic reviewer. This page has no interactive approval controls.", ready:"Codex is ready", busy:"Windows task in progress", unavailable:"Check that Codex is installed and signed in", historyHint:"Execution status and CLI output", emptyHint:"Send your first task to see its progress and results here.", noOutput:"This task returned no output.", records:"tasks", historyNote:"Latest 20 tasks; cleared on restart", output:"Execution output", submitting:"Submitting…" },
|
|
17
|
+
});
|
|
18
|
+
const tn = key => t(`wincli.${key}`);
|
|
19
|
+
register("wincli", {
|
|
20
|
+
"zh-TW": { newTask:"派送 Windows CLI 任務", taskHint:"選擇本機 CLI 與模型,在指定專案中執行任務。", ready:"CLI 已就緒", unavailable:"請先確認 CLI 已安裝並登入", model:"模型", defaultModel:"使用 CLI 預設模型", write:"使用本機 CLI 權限", writeHint:"依照此 CLI 的本機核准設定", writeHintClaude:"可修改工作目錄內的檔案;目錄外的寫入、會修改檔案的 Shell 指令與網路都會被拒絕(唯讀指令仍會執行)", noReadOnly:"此 CLI 無法保證唯讀,請明確選擇本機 CLI 權限。", noProviders:"沒有找到已安裝的 CLI。安裝後可重新偵測。" },
|
|
21
|
+
en: { newTask:"Run a Windows CLI task", taskHint:"Choose a local CLI and model, then run a task in your project.", ready:"CLI is ready", unavailable:"Check that the CLI is installed and signed in", model:"Model", defaultModel:"Use the CLI default model", write:"Use native CLI permissions", writeHint:"Uses this CLI's local approval settings", writeHintClaude:"Edits files in the working directory; writes outside it, shell commands that change files and network access are denied (read-only commands still run)", noReadOnly:"This CLI cannot guarantee read-only access. Choose native CLI permissions explicitly.", noProviders:"No installed CLIs found. Detect again after installation." },
|
|
22
|
+
});
|
|
23
|
+
const active = task => ["starting","running","cancelling"].includes(task.status);
|
|
24
|
+
|
|
25
|
+
function CliCard({ cli, probing }) {
|
|
26
|
+
const signedIn = cli.authenticated === true;
|
|
27
|
+
const checking = probing && !cli.path;
|
|
28
|
+
const authKey = checking ? "checking" : !cli.path ? "missing" : signedIn ? "signedIn" : cli.authenticated === false ? "signedOut" : "unknown";
|
|
29
|
+
const providerLabel = cli.company || ({codex:"OpenAI","claude-code":"Anthropic",antigravity:"Google",grok:"xAI","kiro-cli":"AWS",opencode:"Anomaly",muse:"Meta"})[cli.id];
|
|
30
|
+
return html`<article class=${`windows-cli-provider is-${cli.id}`}>
|
|
31
|
+
<div class="windows-cli-provider-head">
|
|
32
|
+
<span class="windows-cli-brand"><${CliProductMark} id=${cli.id} size=${28} /></span>
|
|
33
|
+
<div class="windows-cli-provider-name"><span>${providerLabel}</span><h3>${cliLabel(cli.id)}</h3></div>
|
|
34
|
+
<span class=${`windows-cli-badge ${cli.runnable ? "tone-ready" : "tone-neutral"}`}>${tn(cli.runnable ? "available" : cli.supports?.execution === false ? "detectionOnly" : checking ? "checking" : "unavailableBadge")}</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="windows-cli-provider-status"><span class=${`windows-cli-auth ${signedIn ? "tone-ready" : "tone-neutral"}`}><span class="windows-cli-dot"></span>${tn(authKey)}</span><span class="windows-cli-version">${cli.version || "—"}</span></div>
|
|
37
|
+
<details class="windows-cli-location"><summary>${tn("path")}<${Icon} name="chevron" size=${14} /></summary><code class="windows-cli-path">${cli.path || tn(checking ? "checking" : "notDetected")}</code></details>
|
|
38
|
+
${cli.reason ? html`<p class="note">${cli.reason}</p>` : null}
|
|
39
|
+
</article>`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function TaskResult({ task, latest, cancel }) {
|
|
43
|
+
const [expanded, setExpanded] = useState(latest || active(task));
|
|
44
|
+
const tone = task.status === "completed" ? "ready" : task.status === "failed" ? "failed" : active(task) ? "working" : "neutral";
|
|
45
|
+
return html`<details class="windows-cli-task" open=${expanded || active(task)} onToggle=${e => setExpanded(e.currentTarget.open)}>
|
|
46
|
+
<summary><span class=${`windows-cli-task-state tone-${tone}`}><span class="windows-cli-dot"></span>${tn(task.status)}</span><time dateTime=${new Date(task.startedAt).toISOString()}>${new Date(task.startedAt).toLocaleTimeString([], { hour:"2-digit", minute:"2-digit" })}</time><${Icon} name="chevron" size=${16} /></summary>
|
|
47
|
+
<code class="windows-cli-path windows-cli-task-cwd">${task.cwd}</code>
|
|
48
|
+
<div class="windows-cli-task-detail"><span class="windows-cli-output-label"><${Icon} name="view" size=${14} />${tn("output")}</span><pre class="windows-cli-output" tabIndex="0">${task.output || tn(active(task) ? "waiting" : "noOutput")}</pre>${task.error ? html`<p class="error">${task.error}</p>` : null}
|
|
49
|
+
${["starting","running"].includes(task.status) ? html`<button type="button" class="btn btn-sm btn-ghost danger" onClick=${() => cancel(task.id)}><${Icon} name="stop" size=${14} />${tn("cancel")}</button>` : null}
|
|
50
|
+
</div>
|
|
51
|
+
</details>`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function WindowsCliPanel({ navKey, embedded = false }) {
|
|
55
|
+
const lease = useLease(navKey);
|
|
56
|
+
const discovery = useWindowsCliCatalog();
|
|
57
|
+
const clis = discovery.data?.clis || [];
|
|
58
|
+
const probing = discovery.loading;
|
|
59
|
+
const [tasks,setTasks] = useState([]), [cwd,setCwd] = useState("");
|
|
60
|
+
const [prompt,setPrompt] = useState(""), [sandbox,setSandbox] = useState("read-only");
|
|
61
|
+
const [selected,setSelected] = useState("codex"), [model,setModel] = useState("");
|
|
62
|
+
const [submitting,setSubmitting] = useState(false), [error,setError] = useState("");
|
|
63
|
+
const submission = useRef(null), claimed = useRef(false), readGeneration = useRef(0), polling = useRef(false);
|
|
64
|
+
const api = async (path,body) => {
|
|
65
|
+
const r = await lease.fetch(path, { credentials:"same-origin", ...(body === undefined ? {} : { method:"POST", headers:{ "Content-Type":"application/json" }, body:JSON.stringify(body) }) });
|
|
66
|
+
const data = await r.json();
|
|
67
|
+
if (!r.ok) { const e = new Error(data.error || `HTTP ${r.status}`); e.rejected = true; throw e; }
|
|
68
|
+
return data;
|
|
69
|
+
};
|
|
70
|
+
const refresh = async () => {
|
|
71
|
+
const generation = ++readGeneration.current;
|
|
72
|
+
try {
|
|
73
|
+
const data = await api("/ui/windows-cli/tasks");
|
|
74
|
+
if (!lease.current() || generation !== readGeneration.current) return;
|
|
75
|
+
setTasks(data.tasks);
|
|
76
|
+
if (submission.current && data.tasks.some(task => task.id === submission.current)) { submission.current = null; claimed.current = false; setSubmitting(false); }
|
|
77
|
+
} catch (e) { if (lease.current()) setError(e.message); }
|
|
78
|
+
};
|
|
79
|
+
const probe = () => discovery.refresh();
|
|
80
|
+
useEffect(() => { if (!embedded) setTitle("Windows CLI"); void refresh(); },[lease]);
|
|
81
|
+
useEffect(() => { if (discovery.data) setCwd(old => old || discovery.data.home); },[discovery.data]);
|
|
82
|
+
const running = tasks.some(active);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (!running) return;
|
|
85
|
+
const timer = lease.interval(async () => { if (polling.current) return; polling.current = true; try { await refresh(); } finally { polling.current = false; } },1000);
|
|
86
|
+
return () => lease.clear(timer);
|
|
87
|
+
},[lease,running]);
|
|
88
|
+
const run = async () => {
|
|
89
|
+
if (claimed.current) return;
|
|
90
|
+
claimed.current = true; setSubmitting(true); setError("");
|
|
91
|
+
const input = { requestId:crypto.randomUUID(), cli:selected, ...(model.trim() ? {model:model.trim()} : {}), cwd:cwd.trim(), prompt, sandbox };
|
|
92
|
+
submission.current = input.requestId;
|
|
93
|
+
try { await api("/ui/windows-cli/tasks",input); }
|
|
94
|
+
catch (e) {
|
|
95
|
+
if (!lease.current()) return;
|
|
96
|
+
setError(e.rejected ? e.message : `${e.message}\n${tn("uncertain")}`);
|
|
97
|
+
if (e.rejected) { submission.current = null; claimed.current = false; setSubmitting(false); }
|
|
98
|
+
}
|
|
99
|
+
if (lease.current()) await refresh();
|
|
100
|
+
};
|
|
101
|
+
const cancel = async id => { try { await api(`/ui/windows-cli/tasks/${id}/cancel`,{}); if (lease.current()) await refresh(); } catch(e) { if (lease.current()) setError(e.message); } };
|
|
102
|
+
const current = clis.find(cli => cli.id === selected);
|
|
103
|
+
const permissionReady = sandbox !== "read-only" || current?.readOnlySupport !== false;
|
|
104
|
+
const runnable = current?.runnable === true && permissionReady;
|
|
105
|
+
const providers = clis.filter(cli => cli.path);
|
|
106
|
+
const choices = providers.filter(cli => cli.supports?.execution !== false).map(cli => ({value:cli.id,label:cliLabel(cli.id),disabled:!cli.runnable,description:cli.authenticated === false ? tn("signedOut") : cli.version || "Windows"}));
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (clis.length && !choices.some(choice => choice.value === selected)) {
|
|
109
|
+
const first = choices.find(choice => !choice.disabled) || choices[0];
|
|
110
|
+
if (first) { setSelected(first.value); setModel(""); }
|
|
111
|
+
}
|
|
112
|
+
},[clis]);
|
|
113
|
+
return html`<div class=${embedded ? "p-windows-cli windows-cli-settings" : "panel p-windows-cli"}>${!embedded ? html`<${PanelHeader} title="Windows CLI" />` : null}
|
|
114
|
+
<div class=${embedded ? "windows-cli-settings-body" : "panel-body"}><div class="windows-cli-content">
|
|
115
|
+
<header class="windows-cli-intro"><div><span class="windows-cli-eyebrow"><${Icon} name="view" size=${14} />${tn("native")}</span><h2>${tn("workspace")}</h2><p>${tn("intro")}</p></div>
|
|
116
|
+
<button type="button" class="btn windows-cli-probe" disabled=${probing} onClick=${probe}><${Icon} name="restart" size=${16} cls=${probing ? "windows-cli-spin" : ""} />${tn(probing ? "probing" : "probe")}</button>
|
|
117
|
+
</header>
|
|
118
|
+
<${WindowsCliDiscoveryStatus} state=${discovery} />
|
|
119
|
+
<section class="windows-cli-cards" aria-label=${tn("providers")}>${providers.map(cli => html`<${CliCard} key=${cli.id} cli=${cli} probing=${probing} />`)}${discovery.data && !providers.length && !probing && !discovery.error ? html`<p class="note">${tn("noProviders")}</p>` : null}</section>
|
|
120
|
+
${error ? html`<p class="error windows-cli-error" role="alert"><${Icon} name="alert" size=${18} /><span>${error}</span></p>` : null}
|
|
121
|
+
<div class="windows-cli-workbench">
|
|
122
|
+
<section class="windows-cli-card windows-cli-composer" aria-labelledby="windows-task-title"><div class="windows-cli-section-head"><span class="windows-cli-section-icon"><${Icon} name="edit" size=${19} /></span><div><h2 id="windows-task-title">${tn("newTask")}</h2><p>${tn("taskHint")}</p></div></div>
|
|
123
|
+
<form onSubmit=${e => { e.preventDefault(); if (runnable && !submitting && !running && cwd.trim() && prompt.trim()) void run(); }}>
|
|
124
|
+
<div class="windows-cli-field"><label>CLI</label><${CliPicker} label="CLI" value=${selected} choices=${choices} disabled=${!choices.length || submitting || running} onChange=${value => { setSelected(value); setModel(""); }} /></div>
|
|
125
|
+
<div class="windows-cli-field"><label for="windows-model">${tn("model")}</label><${ModelSelect} key=${selected} id="windows-model" value=${model} onChange=${setModel} catalogOverride=${current?.models || []} inherit=${tn("defaultModel")} /></div>
|
|
126
|
+
<div class="windows-cli-field"><label for="windows-cwd">${tn("folder")}</label><input id="windows-cwd" class="windows-cli-directory" value=${cwd} placeholder="J:\\Project\\Game" aria-describedby="windows-cwd-hint" required spellcheck=${false} onInput=${e => setCwd(e.target.value)} /><p id="windows-cwd-hint">${tn("folderHint")}</p></div>
|
|
127
|
+
<div class="windows-cli-field"><label for="windows-prompt">${tn("prompt")}</label><textarea id="windows-prompt" rows="5" value=${prompt} placeholder=${tn("promptPlaceholder")} required maxLength=${16384} onInput=${e => setPrompt(e.target.value)} /></div>
|
|
128
|
+
<fieldset class="windows-cli-access"><legend>${tn("access")}</legend><div class="windows-cli-access-options">
|
|
129
|
+
${[["read-only","readOnly","readHint","eye"],["workspace-write","write","writeHint","edit"]].map(([value,label,hint,icon]) => html`<label key=${value} class=${`windows-cli-access-option${sandbox === value ? " selected" : ""}`}><input type="radio" name="windows-sandbox" value=${value} checked=${sandbox === value} disabled=${value === "read-only" && current?.readOnlySupport === false} onChange=${() => setSandbox(value)} /><span><strong><${Icon} name=${icon} size=${15} />${tn(label)}</strong><small>${tn(value === "workspace-write" && current?.id === "claude-code" ? "writeHintClaude" : hint)}</small></span></label>`)}
|
|
130
|
+
</div></fieldset>
|
|
131
|
+
${!permissionReady ? html`<p class="note">${tn("noReadOnly")}</p>` : null}
|
|
132
|
+
<details class="windows-cli-policy"><summary><${Icon} name="info" size=${14} />${tn("policy")}<${Icon} name="chevron" size=${14} /></summary><p>${tn("policyText")}</p></details>
|
|
133
|
+
<div class="windows-cli-submit"><span class=${`windows-cli-readiness ${runnable && !running ? "tone-ready" : "tone-neutral"}`} role="status"><span class="windows-cli-dot"></span>${tn(running ? "busy" : runnable ? "ready" : "unavailable")}</span><button type="submit" class="btn btn-primary" disabled=${!runnable || submitting || running || !cwd.trim() || !prompt.trim()}><${Icon} name=${submitting ? "clock" : "play"} size=${16} />${tn(submitting ? "submitting" : "run")}</button></div>
|
|
134
|
+
<p class="windows-cli-limits"><${Icon} name="clock" size=${13} />${tn("taskLimits")}</p>
|
|
135
|
+
</form>
|
|
136
|
+
</section>
|
|
137
|
+
<section class="windows-cli-card windows-cli-history" aria-labelledby="windows-history-title"><div class="windows-cli-section-head"><span class="windows-cli-section-icon"><${Icon} name="clock" size=${19} /></span><div><h2 id="windows-history-title">${tn("results")} <span class="windows-cli-count">${tasks.length}</span></h2><p>${tn("historyHint")}</p></div><button type="button" class="icon-btn" aria-label=${tn("refresh")} title=${tn("refresh")} onClick=${refresh}><${Icon} name="restart" size=${16} /></button></div>
|
|
138
|
+
<div class="windows-cli-task-list">${!tasks.length ? html`<div class="windows-cli-empty"><span><${Icon} name="view" size=${28} /></span><h3>${tn("empty")}</h3><p>${tn("emptyHint")}</p></div>` : tasks.map((task,index) => html`<${TaskResult} key=${task.id} task=${task} cancel=${cancel} latest=${index === 0} />`)}</div>
|
|
139
|
+
<p class="windows-cli-history-note">${tn("historyNote")}</p>
|
|
140
|
+
</section>
|
|
141
|
+
</div>
|
|
142
|
+
</div></div></div>`;
|
|
143
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Provider marks identify the installed CLI, separate from AgEnD's own UI icons. Sources (THIRD_PARTY_NOTICES.md
|
|
2
|
+
// "CLI provider marks"; retrieved 2026-11-02), each bundled unmodified:
|
|
3
|
+
// - OpenAI: https://openai.com/brand/ (official site's inline Blossom).
|
|
4
|
+
// - Anthropic: https://www.anthropic.com/ (company mark, separate from the Claude product).
|
|
5
|
+
// - Claude: https://claude.com/icon.svg (official Claude product mark and original orange fill).
|
|
6
|
+
// - Kiro: https://kiro.dev/icon.svg (official product icon).
|
|
7
|
+
// - Antigravity: https://antigravity.google/press — the press kit's "Icon - Full Color" SVG.
|
|
8
|
+
// - Grok, OpenCode, Muse: @lobehub/icons 1.102.0 (MIT, https://github.com/lobehub/lobe-icons) — grok.svg ("Grok (xAI)"),
|
|
9
|
+
// opencode.svg ("opencode", opencode.ai), muse-color.svg ("Muse (Meta)", muse.ai).
|
|
10
|
+
// Trademarks and logos belong to their respective owners and are used only to identify the supported CLIs; no
|
|
11
|
+
// affiliation or endorsement is implied.
|
|
12
|
+
import { html } from "/assets/app-html.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Takedown switch (one line to edit): brandMarks: false shows every provider's generic tile instead of its mark; or list
|
|
16
|
+
* a provider in withheld (e.g. new Set(["grok"])) to withhold only its mark. The generic tile is AgEnD's own (TILES).
|
|
17
|
+
*/
|
|
18
|
+
export const MARK_SWITCH = { brandMarks: true, withheld: new Set([]) };
|
|
19
|
+
|
|
20
|
+
/** The generic tile per provider: two letters on a neutral rounded square (no third-party artwork). */
|
|
21
|
+
export const TILES = { openai: "Oa", claude: "Cl", anthropic: "An", kiro: "Ki", antigravity: "Ag", grok: "Gk", opencode: "Oc", muse: "Mu" };
|
|
22
|
+
|
|
23
|
+
const MARKS = {
|
|
24
|
+
"openai": {
|
|
25
|
+
"viewBox": "0 0 41 41",
|
|
26
|
+
"paths": [
|
|
27
|
+
"M37.5324 16.8707C37.9808 15.5241 38.1363 14.0974 37.9886 12.6859C37.8409 11.2744 37.3934 9.91076 36.676 8.68622C35.6126 6.83404 33.9882 5.3676 32.0373 4.4985C30.0864 3.62941 27.9098 3.40259 25.8215 3.85078C24.8796 2.7893 23.7219 1.94125 22.4257 1.36341C21.1295 0.785575 19.7249 0.491269 18.3058 0.500197C16.1708 0.495044 14.0893 1.16803 12.3614 2.42214C10.6335 3.67624 9.34853 5.44666 8.6917 7.47815C7.30085 7.76286 5.98686 8.3414 4.8377 9.17505C3.68854 10.0087 2.73073 11.0782 2.02839 12.312C0.956464 14.1591 0.498905 16.2988 0.721698 18.4228C0.944492 20.5467 1.83612 22.5449 3.268 24.1293C2.81966 25.4759 2.66413 26.9026 2.81182 28.3141C2.95951 29.7256 3.40701 31.0892 4.12437 32.3138C5.18791 34.1659 6.8123 35.6322 8.76321 36.5013C10.7141 37.3704 12.8907 37.5973 14.9789 37.1492C15.9208 38.2107 17.0786 39.0587 18.3747 39.6366C19.6709 40.2144 21.0755 40.5087 22.4946 40.4998C24.6307 40.5054 26.7133 39.8321 28.4418 38.5772C30.1704 37.3223 31.4556 35.5506 32.1119 33.5179C33.5027 33.2332 34.8167 32.6547 35.9659 31.821C37.115 30.9874 38.0728 29.9178 38.7752 28.684C39.8458 26.8371 40.3023 24.6979 40.0789 22.5748C39.8556 20.4517 38.9639 18.4544 37.5324 16.8707ZM22.4978 37.8849C20.7443 37.8874 19.0459 37.2733 17.6994 36.1501C17.7601 36.117 17.8666 36.0586 17.936 36.0161L25.9004 31.4156C26.1003 31.3019 26.2663 31.137 26.3813 30.9378C26.4964 30.7386 26.5563 30.5124 26.5549 30.2825V19.0542L29.9213 20.998C29.9389 21.0068 29.9541 21.0198 29.9656 21.0359C29.977 21.052 29.9842 21.0707 29.9867 21.0902V30.3889C29.9842 32.375 29.1946 34.2791 27.7909 35.6841C26.3872 37.0892 24.4838 37.8806 22.4978 37.8849ZM6.39227 31.0064C5.51397 29.4888 5.19742 27.7107 5.49804 25.9832C5.55718 26.0187 5.66048 26.0818 5.73461 26.1244L13.699 30.7248C13.8975 30.8408 14.1233 30.902 14.3532 30.902C14.583 30.902 14.8088 30.8408 15.0073 30.7248L24.731 25.1103V28.9979C24.7321 29.0177 24.7283 29.0376 24.7199 29.0556C24.7115 29.0736 24.6988 29.0893 24.6829 29.1012L16.6317 33.7497C14.9096 34.7416 12.8643 35.0097 10.9447 34.4954C9.02506 33.9811 7.38785 32.7263 6.39227 31.0064ZM4.29707 13.6194C5.17156 12.0998 6.55279 10.9364 8.19885 10.3327C8.19885 10.4013 8.19491 10.5228 8.19491 10.6071V19.808C8.19351 20.0378 8.25334 20.2638 8.36823 20.4629C8.48312 20.6619 8.64893 20.8267 8.84863 20.9404L18.5723 26.5542L15.206 28.4979C15.1894 28.5089 15.1703 28.5155 15.1505 28.5173C15.1307 28.5191 15.1107 28.516 15.0924 28.5082L7.04046 23.8557C5.32135 22.8601 4.06716 21.2235 3.55289 19.3046C3.03862 17.3858 3.30624 15.3413 4.29707 13.6194ZM31.955 20.0556L22.2312 14.4411L25.5976 12.4981C25.6142 12.4872 25.6333 12.4805 25.6531 12.4787C25.6729 12.4769 25.6928 12.4801 25.7111 12.4879L33.7631 17.1364C34.9967 17.849 36.0017 18.8982 36.6606 20.1613C37.3194 21.4244 37.6047 22.849 37.4832 24.2684C37.3617 25.6878 36.8382 27.0432 35.9743 28.1759C35.1103 29.3086 33.9415 30.1717 32.6047 30.6641C32.6047 30.5947 32.6047 30.4733 32.6047 30.3889V21.188C32.6066 20.9586 32.5474 20.7328 32.4332 20.5338C32.319 20.3348 32.154 20.1698 31.955 20.0556ZM35.3055 15.0128C35.2464 14.9765 35.1431 14.9142 35.069 14.8717L27.1045 10.2712C26.906 10.1554 26.6803 10.0943 26.4504 10.0943C26.2206 10.0943 25.9948 10.1554 25.7963 10.2712L16.0726 15.8858V11.9982C16.0715 11.9783 16.0753 11.9585 16.0837 11.9405C16.0921 11.9225 16.1048 11.9068 16.1207 11.8949L24.1719 7.25025C25.4053 6.53903 26.8158 6.19376 28.2383 6.25482C29.6608 6.31589 31.0364 6.78077 32.2044 7.59508C33.3723 8.40939 34.2842 9.53945 34.8334 10.8531C35.3826 12.1667 35.5464 13.6095 35.3055 15.0128ZM14.2424 21.9419L10.8752 19.9981C10.8576 19.9893 10.8423 19.9763 10.8309 19.9602C10.8195 19.9441 10.8122 19.9254 10.8098 19.9058V10.6071C10.8107 9.18295 11.2173 7.78848 11.9819 6.58696C12.7466 5.38544 13.8377 4.42659 15.1275 3.82264C16.4173 3.21869 17.8524 2.99464 19.2649 3.1767C20.6775 3.35876 22.0089 3.93941 23.1034 4.85067C23.0427 4.88379 22.937 4.94215 22.8668 4.98473L14.9024 9.58517C14.7025 9.69878 14.5366 9.86356 14.4215 10.0626C14.3065 10.2616 14.2466 10.4877 14.2479 10.7175L14.2424 21.9419ZM16.071 17.9991L20.4018 15.4978L24.7325 17.9975V22.9985L20.4018 25.4983L16.071 22.9985V17.9991Z"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"claude": {
|
|
31
|
+
"viewBox": "0 0 248 248",
|
|
32
|
+
"fill": "#D97757",
|
|
33
|
+
"paths": [
|
|
34
|
+
"M52.4285 162.873L98.7844 136.879L99.5485 134.602L98.7844 133.334H96.4921L88.7237 132.862L62.2346 132.153L39.3113 131.207L17.0249 130.026L11.4214 128.844L6.2 121.873L6.7094 118.447L11.4214 115.257L18.171 115.847L33.0711 116.911L55.485 118.447L71.6586 119.392L95.728 121.873H99.5485L100.058 120.337L98.7844 119.392L97.7656 118.447L74.5877 102.732L49.4995 86.1905L36.3823 76.62L29.3779 71.7757L25.8121 67.2858L24.2839 57.3608L30.6515 50.2716L39.3113 50.8623L41.4763 51.4531L50.2636 58.1879L68.9842 72.7209L93.4357 90.6804L97.0015 93.6343L98.4374 92.6652L98.6571 91.9801L97.0015 89.2625L83.757 65.2772L69.621 40.8192L63.2534 30.6579L61.5978 24.632C60.9565 22.1032 60.579 20.0111 60.579 17.4246L67.8381 7.49965L71.9133 6.19995L81.7193 7.49965L85.7946 11.0443L91.9074 24.9865L101.714 46.8451L116.996 76.62L121.453 85.4816L123.873 93.6343L124.764 96.1155H126.292V94.6976L127.566 77.9197L129.858 57.3608L132.15 30.8942L132.915 23.4505L136.608 14.4708L143.994 9.62643L149.725 12.344L154.437 19.0788L153.8 23.4505L150.998 41.6463L145.522 70.1215L141.957 89.2625H143.994L146.414 86.7813L156.093 74.0206L172.266 53.698L179.398 45.6635L187.803 36.802L193.152 32.5484H203.34L210.726 43.6549L207.415 55.1159L196.972 68.3492L188.312 79.5739L175.896 96.2095L168.191 109.585L168.882 110.689L170.738 110.53L198.755 104.504L213.91 101.787L231.994 98.7149L240.144 102.496L241.036 106.395L237.852 114.311L218.495 119.037L195.826 123.645L162.07 131.592L161.696 131.893L162.137 132.547L177.36 133.925L183.855 134.279H199.774L229.447 136.524L237.215 141.605L241.8 147.867L241.036 152.711L229.065 158.737L213.019 154.956L175.45 145.977L162.587 142.787H160.805V143.85L171.502 154.366L191.242 172.089L215.82 195.011L217.094 200.682L213.91 205.172L210.599 204.699L188.949 188.394L180.544 181.069L161.696 165.118H160.422V166.772L164.752 173.152L187.803 207.771L188.949 218.405L187.294 221.832L181.308 223.959L174.813 222.777L161.187 203.754L147.305 182.486L136.098 163.345L134.745 164.2L128.075 235.42L125.019 239.082L117.887 241.8L111.902 237.31L108.718 229.984L111.902 215.452L115.722 196.547L118.779 181.541L121.58 162.873L123.291 156.636L123.14 156.219L121.773 156.449L107.699 175.752L86.304 204.699L69.3663 222.777L65.291 224.431L58.2867 220.768L58.9235 214.27L62.8713 208.48L86.304 178.705L100.44 160.155L109.551 149.507L109.462 147.967L108.959 147.924L46.6977 188.512L35.6182 189.93L30.7788 185.44L31.4156 178.115L33.7079 175.752L52.4285 162.873Z"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"anthropic": {
|
|
38
|
+
"viewBox": "0 0 35 24",
|
|
39
|
+
"paths": [
|
|
40
|
+
"M-0.00143743 24L9.56656 -1.90735e-06H15.0546L24.6226 24H19.2626L17.3106 18.96H7.29456L5.34256 24H-0.00143743ZM9.02256 14.496H15.5826L12.3026 6.064L9.02256 14.496ZM29.0386 24L19.4706 -1.90735e-06H24.7186L34.2866 24H29.0386Z"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"kiro": {
|
|
44
|
+
"svg64": "PHN2ZyB3aWR0aD0iMTIwMCIgaGVpZ2h0PSIxMjAwIiB2aWV3Qm94PSIwIDAgMTIwMCAxMjAwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cmVjdCB3aWR0aD0iMTIwMCIgaGVpZ2h0PSIxMjAwIiByeD0iMjYwIiBmaWxsPSIjOTA0NkZGIi8+CjxtYXNrIGlkPSJtYXNrMF8xMTA2XzQ4NTYiIG1hc2stdHlwZT0ibHVtaW5hbmNlIiBtYXNrVW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4PSIyNzIiIHk9IjIwMiIgd2lkdGg9IjY1NSIgaGVpZ2h0PSI3OTYiPgo8cGF0aCBkPSJNOTI2LjU3OCAyMDIuNzkzSDI3Mi42MzdWOTk3Ljg1N0g5MjYuNTc4VjIwMi43OTNaIiBmaWxsPSJ3aGl0ZSIvPgo8L21hc2s+CjxnIG1hc2s9InVybCgjbWFzazBfMTEwNl80ODU2KSI+CjxwYXRoIGQ9Ik0zOTguNTU0IDgxOC45MTRDMzE2LjMxNSAxMDAxLjAzIDQ5MS40NzcgMTA0Ni43NCA2MjAuNjcyIDk0MC4xNTZDNjU4LjY4NyAxMDU5LjY2IDgwMS4wNTIgOTcwLjQ3MyA4NTIuMjM0IDg3Ny43OTVDOTY0Ljc4NyA2NzMuNTY3IDkxOS4zMTggNDY1LjM1NyA5MDcuNjQgNDIyLjM3NEM4MjcuNjM3IDEyOS40NDMgNDI3LjYyMyAxMjguOTQ2IDM1OC44IDQyMy44NjVDMzQyLjY1MSA0NzUuNTQ0IDM0Mi40MDIgNTM0LjE4IDMzMy40NTggNTk1LjA1MUMzMjguOTg2IDYyNS44NiAzMjUuNTA3IDY0NS40ODggMzEzLjgzIDY3Ny43ODVDMzA2Ljg3MyA2OTYuNDI0IDI5Ny42OCA3MTIuODE5IDI4Mi43NzMgNzQwLjY0NUMyNTkuOTE1IDc4My44ODEgMjY5LjYwNCA4NjcuMTEzIDM4Ny44NyA4MjMuODgzTDM5OS4wNTEgODE4LjkxNEgzOTguNTU0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYzNi4xMjMgNTQ5LjM1M0M2MDMuMzI4IDU0OS4zNTMgNTk4LjM1OSA1MTAuMDk3IDU5OC4zNTkgNDg2Ljc0MkM1OTguMzU5IDQ2NS42MjMgNjAyLjA4NiA0NDguOTc3IDYwOS4yOTMgNDM4LjI5M0M2MTUuNTA0IDQyOC44NTIgNjI0LjY5NyA0MjQuMTMxIDYzNi4xMjMgNDI0LjEzMUM2NDcuNTU1IDQyNC4xMzEgNjU3LjQ5MiA0MjguODUyIDY2NC40NDcgNDM4LjU0MUM2NzIuMzk4IDQ0OS40NzQgNjc2LjYyMyA0NjYuMTIgNjc2LjYyMyA0ODYuNzQyQzY3Ni42MjMgNTI1Ljk5OCA2NjEuNDcxIDU0OS4zNTMgNjM2LjM3NSA1NDkuMzUzSDYzNi4xMjNaIiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNNzcxLjI0IDU0OS4zNTNDNzM4LjQ0NSA1NDkuMzUzIDczMy40NzcgNTEwLjA5NyA3MzMuNDc3IDQ4Ni43NDJDNzMzLjQ3NyA0NjUuNjIzIDczNy4yMDMgNDQ4Ljk3NyA3NDQuNDEgNDM4LjI5M0M3NTAuNjIxIDQyOC44NTIgNzU5LjgxNCA0MjQuMTMxIDc3MS4yNCA0MjQuMTMxQzc4Mi42NzIgNDI0LjEzMSA3OTIuNjA5IDQyOC44NTIgNzk5LjU2NCA0MzguNTQxQzgwNy41MTYgNDQ5LjQ3NCA4MTEuNzQgNDY2LjEyIDgxMS43NCA0ODYuNzQyQzgxMS43NCA1MjUuOTk4IDc5Ni41ODggNTQ5LjM1MyA3NzEuNDkyIDU0OS4zNTNINzcxLjI0WiIgZmlsbD0iYmxhY2siLz4KPC9nPgo8L3N2Zz4="
|
|
45
|
+
},
|
|
46
|
+
"antigravity": {
|
|
47
|
+
"svg64": "PHN2ZyB3aWR0aD0iMTgwIiBoZWlnaHQ9IjE4MCIgdmlld0JveD0iMCAwIDE4MCAxODAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDQuMjQ4IDE0OS4wNjJDMTUxLjc0OCAxNTQuNjg4IDE2Mi45OTggMTUwLjkzOCAxNTIuNjg1IDE0MC42MjVDMTIxLjc0OCAxMTAuNjI1IDEyOC4zMSAyOC4xMjUgODkuODcyNyAyOC4xMjVDNTEuNDM1MiAyOC4xMjUgNTcuOTk3NyAxMTAuNjI1IDI3LjA2MDIgMTQwLjYyNUMxNS44MTAyIDE1MS44NzUgMjcuOTk3NyAxNTQuNjg4IDM1LjQ5NzcgMTQ5LjA2MkM2NC41NjAyIDEyOS4zNzUgNjIuNjg1MiA5NC42ODc1IDg5Ljg3MjcgOTQuNjg3NUMxMTcuMDYgOTQuNjg3NSAxMTUuMTg1IDEyOS4zNzUgMTQ0LjI0OCAxNDkuMDYyWiIgZmlsbD0iIzMxODZGRiIvPgo8bWFzayBpZD0ibWFzazBfNjAwMV80MDkiIHN0eWxlPSJtYXNrLXR5cGU6YWxwaGEiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjIyIiB5PSIyOCIgd2lkdGg9IjEzNiIgaGVpZ2h0PSIxMjUiPgo8cGF0aCBkPSJNMTQ0LjI0OCAxNDkuMDYyQzE1MS43NDggMTU0LjY4OCAxNjIuOTk4IDE1MC45MzggMTUyLjY4NSAxNDAuNjI1QzEyMS43NDggMTEwLjYyNSAxMjguMzEgMjguMTI1IDg5Ljg3MjcgMjguMTI1QzUxLjQzNTIgMjguMTI1IDU3Ljk5NzcgMTEwLjYyNSAyNy4wNjAyIDE0MC42MjVDMTUuODEwMiAxNTEuODc1IDI3Ljk5NzcgMTU0LjY4OCAzNS40OTc3IDE0OS4wNjJDNjQuNTYwMiAxMjkuMzc1IDYyLjY4NTIgOTQuNjg3NSA4OS44NzI3IDk0LjY4NzVDMTE3LjA2IDk0LjY4NzUgMTE1LjE4NSAxMjkuMzc1IDE0NC4yNDggMTQ5LjA2MloiIGZpbGw9IndoaXRlIi8+CjwvbWFzaz4KPGcgbWFzaz0idXJsKCNtYXNrMF82MDAxXzQwOSkiPgo8ZyBmaWx0ZXI9InVybCgjZmlsdGVyMF9mXzYwMDFfNDA5KSI+CjxlbGxpcHNlIGN4PSIzNi42MjI1IiBjeT0iNDMuMDg3MiIgcng9IjM2LjYyMjUiIHJ5PSI0My4wODcyIiB0cmFuc2Zvcm09Im1hdHJpeCgtMC4xMTI3ODQgMC45OTM2MiAtMC45OTM2MiAtMC4xMTI3ODEgMTA2LjU1NyAtMjYuNDg0NykiIGZpbGw9IiNGRkU0MzIiLz4KPC9nPgo8ZyBmaWx0ZXI9InVybCgjZmlsdGVyMV9mXzYwMDFfNDA5KSI+CjxlbGxpcHNlIGN4PSIxNTUuMTYzIiBjeT0iNTQuOTI5MiIgcng9IjQ3LjQxMTgiIHJ5PSI0OC40NTQxIiB0cmFuc2Zvcm09InJvdGF0ZSg3Ni45MjQzIDE1NS4xNjMgNTQuOTI5MikiIGZpbGw9IiNGQzQxM0QiLz4KPC9nPgo8ZyBmaWx0ZXI9InVybCgjZmlsdGVyMl9mXzYwMDFfNDA5KSI+CjxlbGxpcHNlIGN4PSIxNC42MDA2IiBjeT0iNjUuNDQyNSIgcng9IjQ5LjU1MTUiIHJ5PSI2NC4xOTIiIHRyYW5zZm9ybT0icm90YXRlKDc0LjEyNTcgMTQuNjAwNiA2NS40NDI1KSIgZmlsbD0iIzAwQjk1QyIvPgo8L2c+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIzX2ZfNjAwMV80MDkpIj4KPGVsbGlwc2UgY3g9IjE0LjYwMDYiIGN5PSI2NS40NDI1IiByeD0iNDkuNTUxNSIgcnk9IjY0LjE5MiIgdHJhbnNmb3JtPSJyb3RhdGUoNzQuMTI1NyAxNC42MDA2IDY1LjQ0MjUpIiBmaWxsPSIjMDBCOTVDIi8+CjwvZz4KPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjRfZl82MDAxXzQwOSkiPgo8ZWxsaXBzZSBjeD0iMTguMTIyNiIgY3k9IjY3LjQxNCIgcng9IjQ4LjU2NzkiIHJ5PSI1My40Njg4IiB0cmFuc2Zvcm09InJvdGF0ZSg0NS42MDY1IDE4LjEyMjYgNjcuNDE0KSIgZmlsbD0iIzAwQjk1QyIvPgo8L2c+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXI1X2ZfNjAwMV80MDkpIj4KPGVsbGlwc2UgY3g9IjEyMS44MzciIGN5PSIxNjYuOTQ1IiByeD0iNDYuNjM1NiIgcnk9IjQ0LjkwODQiIHRyYW5zZm9ybT0icm90YXRlKDc2LjkyNDMgMTIxLjgzNyAxNjYuOTQ1KSIgZmlsbD0iIzMxODZGRiIvPgo8L2c+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXI2X2ZfNjAwMV80MDkpIj4KPGVsbGlwc2UgY3g9IjUzLjk0NTYiIGN5PSI1Ni44OTk3IiByeD0iNTMuOTQ1NiIgcnk9IjU2Ljg5OTciIHRyYW5zZm9ybT0ibWF0cml4KC0wLjQwOTUzOSAwLjkxMjI5MyAtMC45MTIyOTQgLTAuNDA5NTM3IDE2Mi44MTEgLTI1Ljg5NSkiIGZpbGw9IiNGQkJDMDQiLz4KPC9nPgo8ZyBmaWx0ZXI9InVybCgjZmlsdGVyN19mXzYwMDFfNDA5KSI+CjxwYXRoIGQ9Ik00LjIxNTU3IDIzOS4wNjNDLTI1LjMyMzEgMjI3LjQ2NyAyNS4xNTc3IDEzMi4wNjEgMzcuNzEwNSAxMDAuMDg1QzUwLjI2MzQgNjguMTA5NyA4NC4zODUzIDUxLjU4ODggMTEzLjkyNCA2My4xODQ4QzE0My40NjMgNzQuNzgwOSAxNzguNDc0IDEzOC42NSAxNjUuOTIxIDE3MC42MjZDMTUzLjM2OCAyMDIuNjAxIDMzLjc1NDMgMjUwLjY1OSA0LjIxNTU3IDIzOS4wNjNaIiBmaWxsPSIjMzE4NkZGIi8+CjwvZz4KPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjhfZl82MDAxXzQwOSkiPgo8cGF0aCBkPSJNMTgzLjE5NyAxMjAuMzE1QzE3NS4yODkgMTI5LjU0NSAxNTQuNjUyIDEyNC44MzkgMTM3LjEwMiAxMDkuODAzQzExOS41NTMgOTQuNzY2OCAxMTEuNzM4IDc1LjA5NTUgMTE5LjY0NiA2NS44NjU2QzEyNy41NTQgNTYuNjM1NyAxNDguMTkxIDYxLjM0MjMgMTY1Ljc0IDc2LjM3ODJDMTgzLjI4OSA5MS40MTQgMTkxLjEwNSAxMTEuMDg1IDE4My4xOTcgMTIwLjMxNVoiIGZpbGw9IiM3NDlCRkYiLz4KPC9nPgo8ZyBmaWx0ZXI9InVybCgjZmlsdGVyOV9mXzYwMDFfNDA5KSI+CjxlbGxpcHNlIGN4PSIxNDguOTI4IiBjeT0iMzYuNzI1MiIgcng9IjcxLjEwMTgiIHJ5PSI0NC4xOTkiIHRyYW5zZm9ybT0icm90YXRlKDM0LjA3NjMgMTQ4LjkyOCAzNi43MjUyKSIgZmlsbD0iI0ZDNDEzRCIvPgo8L2c+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIxMF9mXzYwMDFfNDA5KSI+CjxlbGxpcHNlIGN4PSIzNy44NDgiIGN5PSI0Ni4wMzQ2IiByeD0iMzguMTAwOCIgcnk9IjIyLjE1NzUiIHRyYW5zZm9ybT0icm90YXRlKDExMi41MTYgMzcuODQ4IDQ2LjAzNDYpIiBmaWxsPSIjRkZFRTQ4Ii8+CjwvZz4KPC9nPgo8ZGVmcz4KPGZpbHRlciBpZD0iZmlsdGVyMF9mXzYwMDFfNDA5IiB4PSI0LjA5NTkxIiB5PSItNDQuMTc2MSIgd2lkdGg9IjExMS4wMzciIGhlaWdodD0iOTguNDQxNiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI2LjI1MjM0Ii8+CjwvZmlsdGVyPgo8ZmlsdGVyIGlkPSJmaWx0ZXIxX2ZfNjAwMV80MDkiIHg9IjQ2LjI5NzQiIHk9Ii01My4wMDA5IiB3aWR0aD0iMjE3LjczMSIgaGVpZ2h0PSIyMTUuODYiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMzAuMjI2OCIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyMl9mXzYwMDFfNDA5IiB4PSItMTAwLjAxOCIgeT0iLTM2Ljc1NTgiIHdpZHRoPSIyMjkuMjM4IiBoZWlnaHQ9IjIwNC4zOTciIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMjUuNjk1NyIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyM19mXzYwMDFfNDA5IiB4PSItMTAwLjAxOCIgeT0iLTM2Ljc1NTgiIHdpZHRoPSIyMjkuMjM4IiBoZWlnaHQ9IjIwNC4zOTciIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMjUuNjk1NyIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyNF9mXzYwMDFfNDA5IiB4PSItODQuMzk4NSIgeT0iLTM1LjAwMyIgd2lkdGg9IjIwNS4wNDIiIGhlaWdodD0iMjA0LjgzNCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyNS42OTU3Ii8+CjwvZmlsdGVyPgo8ZmlsdGVyIGlkPSJmaWx0ZXI1X2ZfNjAwMV80MDkiIHg9IjI3Ljk5MTUiIHk9IjcxLjU0OTMiIHdpZHRoPSIxODcuNjkxIiBoZWlnaHQ9IjE5MC43OTEiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMjQuNDE4NCIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyNl9mXzYwMDFfNDA5IiB4PSItMTEuODgwOCIgeT0iLTk4LjcwODUiIHdpZHRoPSIyMDEuMzgiIGhlaWdodD0iMTk3LjQ1IiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+CjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIyLjEzMDEiLz4KPC9maWx0ZXI+CjxmaWx0ZXIgaWQ9ImZpbHRlcjdfZl82MDAxXzQwOSIgeD0iLTQ0LjQ0MzIiIHk9IjE5Ljk1MjIiIHdpZHRoPSIyNTIuNTEzIiBoZWlnaHQ9IjI2MC40MDQiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMTkuNzYzMSIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyOF9mXzYwMDFfNDA5IiB4PSI4MS4xOTE1IiB5PSIyNS43NzIyIiB3aWR0aD0iMTQwLjQ2IiBoZWlnaHQ9IjEzNC42MzciIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMTcuNjg0MyIvPgo8L2ZpbHRlcj4KPGZpbHRlciBpZD0iZmlsdGVyOV9mXzYwMDFfNDA5IiB4PSI1NS4xNDk5IiB5PSItNDcuMjUzMSIgd2lkdGg9IjE4Ny41NTUiIGhlaWdodD0iMTY3Ljk1NyIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIxNC45MzY1Ii8+CjwvZmlsdGVyPgo8ZmlsdGVyIGlkPSJmaWx0ZXIxMF9mXzYwMDFfNDA5IiB4PSItMjQuMjYzMyIgeT0iLTI3LjE1MTUiIHdpZHRoPSIxMjQuMjIzIiBoZWlnaHQ9IjE0Ni4zNzIiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMTguNDg2NSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K"
|
|
48
|
+
},
|
|
49
|
+
"grok": {
|
|
50
|
+
"viewBox": "0 0 24 24",
|
|
51
|
+
"fillRule": "evenodd",
|
|
52
|
+
"paths": [
|
|
53
|
+
"M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"opencode": {
|
|
57
|
+
"viewBox": "0 0 24 24",
|
|
58
|
+
"fillRule": "evenodd",
|
|
59
|
+
"paths": [
|
|
60
|
+
"M16 6H8v12h8V6zm4 16H4V2h16v20z"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"muse": {
|
|
64
|
+
"svg64": "PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjFlbSIgc3R5bGU9ImZsZXg6bm9uZTtsaW5lLWhlaWdodDoxIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxZW0iIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPk11c2U8L3RpdGxlPjxwYXRoIGQ9Ik01LjkxIDMuODY5QzYuNzc3IDMuODY5IDcuMzk2IDQuNTQ2IDcuMzk2IDUuNjA3IDcuMzk2IDYuNjY5IDcuMjI1IDcuNjI2IDYuOTQxIDkuNjU5IDYuNzM4IDExLjA4NCA2LjM4OSAxMy4yNTggNi4yNDMgMTQuMTYyIDYuNTIzIDEzLjYyOCA3LjE3OCAxMi4zNzggNy4yOTQgMTIuMTQ0IDguNjY2IDkuMzc1IDEwLjA5NiA2LjkwMSAxMC41MDggNi4yNDYgMTEuMDU0IDUuMzcyIDExLjUzNSA1LjAyMSAxMi4yNzggNS4wMjEgMTIuNjY0IDUuMDIyIDEzLjEyNCA1LjIxNyAxMy4zNTIgNS40NzcgMTMuNjYgNS44MjkgMTMuNzI1IDYuMzk4IDEzLjcxNCA3LjAxOSAxMy42OTggNy45NyAxMy41NzQgOS40ODYgMTMuNDA1IDExLjE3NyAxMy4zMyAxMS45MjkgMTMuMTg1IDEzLjQ2NiAxMy4wODcgMTQuNDk2IDEzLjk2NSAxMi45MjUgMTUuNTkxIDEwLjAzNSAxNi4yNDYgOS4wMjUgMTYuODE3IDguMTQ2IDE3LjM5MiA3LjU3OSAxOC4xNjQgNy41NzkgMTguODMgNy41NzkgMTkuNjUxIDguMDUgMTkuNjAzIDkuMzAyIDE5LjUzMSAxMS4xNDkgMTkuMjY0IDE1LjE3NCAxOS4xNDMgMTYuOTc5IDE5Ljk2IDE1Ljc5IDIxLjAzMyAxNC4wMjkgMjEuNDM2IDEzLjM2NyAyMS44NDIgMTIuNjk4IDIyLjI2IDEyLjE1NyAyMi44OTQgMTIuMTM5IDIzLjU0NCAxMi4xMiAyMy45NzkgMTIuNTYyIDIzLjk5OSAxMy4yNDQgMjQuMDE5IDEzLjkyNyAyMy42MTIgMTQuNjk0IDIzLjA3MiAxNS41NjUgMjIuNDg2IDE2LjUxMSAyMS44MzEgMTcuNTIzIDIxLjAzMyAxOC40NjggMjAuMjM2IDE5LjQxMyAxOS41MDIgMjAuMTMxIDE4LjM4NCAyMC4xMzEgMTcuMzgyIDIwLjEzMSAxNi42NzcgMTkuNDY1IDE2LjYyOCAxOC4yNDYgMTYuNjAyIDE3LjYwNyAxNi43MjMgMTYuMjM0IDE2LjgxNCAxNS4xNiAxNi45MiAxMy45MTcgMTcuMDQ4IDEyLjcxNyAxNy4xMzcgMTEuOTIzIDE2LjI1NiAxMy41MzUgMTQuNDAyIDE2LjkxMiAxMy41NjggMTguMjMgMTIuNzUyIDE5LjUyIDEyLjM1NSAxOS45NzQgMTEuNDkzIDE5Ljk3NSAxMC42MzEgMTkuOTc1IDEwLjI1MyAxOS4zNTQgMTAuMjQxIDE4LjQyIDEwLjIyNyAxNy40MDcgMTAuOTg4IDExLjMyNCAxMS4yNDYgOS4yOTcgMTAuODI4IDEwLjE5MSA5LjgwMSAxMi4zODUgOS4xNTcgMTMuNjkgOC41MzQgMTQuOTUzIDcuNDg5IDE3LjEzNSA2LjczIDE4LjM5MyA2LjE4NCAxOS4yOTggNS41NyAxOS45NzUgNC42NiAxOS45NzUgMy43NSAxOS45NzUgMy4yMzYgMTkuMzYzIDMuMjM2IDE4LjM3OSAzLjIzNiAxNy4zOTUgMy41MjEgMTUuNzU2IDMuODI3IDEzLjcyMyAzLjk4IDEyLjczOSA0LjE1NSAxMS42NjcgNC4zNTIgMTAuNTMgNC40OTYgOS43MDggNC43NDYgOC4yNiA0LjkgNy4zNzEgNC4yIDguNDYxIDIuOTQxIDEwLjQyMyAyLjU1OCAxMS4wMTQgMi4xMzEgMTEuNjcxIDEuNzQ5IDEyLjE1IDEuMTE1IDEyLjE1IDAuNDE2IDEyLjE1IDAgMTEuNjA1IDAgMTAuOTcxIDAgMTAuMzM3IDAuMzIyIDkuODQ4IDAuODQ2IDguOTg4IDEuNTE4IDcuODgzIDIuNzI2IDYuMzc3IDMuMzg4IDUuNTg2IDQuMTY4IDQuNjU0IDQuOTQ3IDMuODY5IDUuOTEgMy44NjlaIiBmaWxsPSJ1cmwoI2xvYmUtaWNvbnMtbXVzZS1fUl8wXykiPjwvcGF0aD48ZGVmcz48bGluZWFyR3JhZGllbnQgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJsb2JlLWljb25zLW11c2UtX1JfMF8iIHgxPSIzMS45NzkiIHgyPSI1Ljk4MSIgeTE9IjI2LjE3MSIgeTI9Ii0zLjAxNCI+PHN0b3Agb2Zmc2V0PSIuMjU1IiBzdG9wLWNvbG9yPSIjMDA4MkZCIj48L3N0b3A+PHN0b3Agb2Zmc2V0PSIuNjk3IiBzdG9wLWNvbG9yPSIjMDA2NEUwIj48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA0MERDIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PC9zdmc+"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** Whether `provider`'s own mark is shown (else its generic tile). */
|
|
69
|
+
export function showsBrandMark(provider) { return MARK_SWITCH.brandMarks && !MARK_SWITCH.withheld.has(provider) && !!MARKS[provider]; }
|
|
70
|
+
|
|
71
|
+
function GenericTile({ letters, size }) {
|
|
72
|
+
return html`<svg width=${size} height=${size} viewBox="0 0 24 24" aria-hidden="true" focusable="false" class="provider-tile"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" fill-opacity="0.14" /><text x="12" y="16" text-anchor="middle" font-size="10" font-weight="600" font-family="system-ui, sans-serif" fill="currentColor">${letters}</text></svg>`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function ProviderMark({ provider, size = 28 }) {
|
|
76
|
+
const mark = MARKS[provider];
|
|
77
|
+
if (!mark && !TILES[provider]) return null;
|
|
78
|
+
if (!showsBrandMark(provider)) return TILES[provider] ? html`<${GenericTile} letters=${TILES[provider]} size=${size} />` : null;
|
|
79
|
+
// Complete marks (gradients, masks) are isolated images, byte for byte as published (base64): their ids cannot
|
|
80
|
+
// collide, their colours are their own, and nothing in them is rewritten.
|
|
81
|
+
if (mark.svg64) return html`<img width=${size} height=${size} src=${"data:image/svg+xml;base64," + mark.svg64} alt="" aria-hidden="true" />`;
|
|
82
|
+
return html`<svg width=${size} height=${size} viewBox=${mark.viewBox} fill=${mark.fill || "currentColor"} fill-rule=${mark.fillRule || undefined} aria-hidden="true" focusable="false">${mark.paths.map(d => html`<path d=${d} />`)}</svg>`;
|
|
83
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Machine inventory is a fast central snapshot. Reading it never launches a model or a CLI probe.
|
|
2
|
+
import { useEffect } from "/assets/app-html.js";
|
|
3
|
+
import { createStore, useStore } from "/assets/app-store.js";
|
|
4
|
+
import { useLease } from "/assets/app-ctx.js";
|
|
5
|
+
|
|
6
|
+
const initial = () => ({ data:null, loading:false, error:"", checkedAt:0 });
|
|
7
|
+
export function createRuntimeCatalog({ fetcher = (...args) => fetch(...args), now = () => Date.now(), ttlMs = 5000, timeoutMs = 15_000 } = {}) {
|
|
8
|
+
const store = createStore(initial());
|
|
9
|
+
let pending = null, controller = null, generation = 0;
|
|
10
|
+
const load = ({ force = false } = {}) => {
|
|
11
|
+
if (pending) return pending;
|
|
12
|
+
if (!force && store.get().data && now()-store.get().checkedAt < ttlMs) return Promise.resolve(store.get().data);
|
|
13
|
+
const mine = generation, abort = controller = new AbortController();
|
|
14
|
+
const timer = setTimeout(() => abort.abort(),timeoutMs);
|
|
15
|
+
store.set({loading:true,error:""});
|
|
16
|
+
pending = Promise.resolve().then(async () => {
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetcher("/ui/runtimes",{credentials:"same-origin",signal:abort.signal});
|
|
19
|
+
const value = await response.json();
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
if (mine === generation && [401,403].includes(response.status)) store.set({data:null,checkedAt:0});
|
|
22
|
+
throw new Error(value?.error || `HTTP ${response.status}`);
|
|
23
|
+
}
|
|
24
|
+
if (!value || !Array.isArray(value.machines)) throw new Error("Invalid runtime inventory response");
|
|
25
|
+
if (mine === generation) store.set({data:value,checkedAt:now(),error:""});
|
|
26
|
+
return value;
|
|
27
|
+
} catch(error) {
|
|
28
|
+
if (mine === generation) store.set({error:error?.message || "Runtime inventory unavailable"});
|
|
29
|
+
return null;
|
|
30
|
+
} finally {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
if (mine === generation) { pending = null; controller = null; store.set({loading:false}); }
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return pending;
|
|
36
|
+
};
|
|
37
|
+
return {get:store.get,subscribe:store.subscribe,load,clear(){generation++;controller?.abort();controller=null;pending=null;store.set(initial());}};
|
|
38
|
+
}
|
|
39
|
+
const catalog = createRuntimeCatalog();
|
|
40
|
+
export const forgetRuntimeCatalog = () => catalog.clear();
|
|
41
|
+
export function useRuntimeCatalog(enabled = true) {
|
|
42
|
+
const state = useStore(catalog), lease = useLease(`runtime-catalog:${enabled}`);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!enabled) return;
|
|
45
|
+
void catalog.load();
|
|
46
|
+
const timer = lease.interval(() => { void catalog.load(); },5000);
|
|
47
|
+
return () => lease.clear(timer);
|
|
48
|
+
},[lease,enabled]);
|
|
49
|
+
return {...(enabled ? state : initial()),refresh:() => catalog.load({force:true})};
|
|
50
|
+
}
|
|
51
|
+
export const instanceMachineId = instance => instance?.machine_id || instance?.machineId || "";
|
|
52
|
+
/** Inventory can be viewed offline; only online, installed, supported providers can receive new work. */
|
|
53
|
+
export function runtimeCliChoices(machine) {
|
|
54
|
+
return (machine?.inventory?.clis || []).filter(cli => cli.path && cli.supports?.execution !== false && cli.supports?.resume !== false);
|
|
55
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// signed in, new enough: /ui/backends) and the model catalog of that backend for that instance's account (/ui/models).
|
|
3
3
|
// Both answers are the server's cached ones; nothing here makes the server probe. A page asks once and reuses the answer
|
|
4
4
|
// for a short while, so opening several dialogs costs one request each.
|
|
5
|
-
import { useEffect, useState } from "/assets/app-html.js";
|
|
5
|
+
import { useEffect, useRef, useState } from "/assets/app-html.js";
|
|
6
6
|
|
|
7
7
|
const TTL_MS = 30_000;
|
|
8
8
|
const cache = new Map(); // url → { at, value, pending }
|
|
@@ -13,10 +13,10 @@ async function getJson(url) {
|
|
|
13
13
|
return res.json();
|
|
14
14
|
}
|
|
15
15
|
/** The answer for `url`, shared by every field on the page while it is fresh; null when it cannot be read. */
|
|
16
|
-
function cached(url) {
|
|
16
|
+
function cached(url, force = false) {
|
|
17
17
|
const hit = cache.get(url), now = performance.now();
|
|
18
|
-
if (hit && (hit.pending || now - hit.at < TTL_MS)) return hit.pending ?? Promise.resolve(hit.value);
|
|
19
|
-
const pending = getJson(url).then((value) => { cache.set(url, { at: performance.now(), value, pending: null }); return value; })
|
|
18
|
+
if (hit && (hit.pending || !force && now - hit.at < TTL_MS)) return hit.pending ?? Promise.resolve(hit.value);
|
|
19
|
+
const pending = getJson(force ? `${url}&refresh=1` : url).then((value) => { cache.set(url, { at: performance.now(), value, pending: null }); return value; })
|
|
20
20
|
.catch(() => { cache.delete(url); return null; });
|
|
21
21
|
cache.set(url, { at: now, value: null, pending });
|
|
22
22
|
return pending;
|
|
@@ -45,12 +45,39 @@ export function useBackendRows() {
|
|
|
45
45
|
return answer && Array.isArray(answer.backends) ? answer.backends : answer === undefined ? undefined : null;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
export function
|
|
50
|
-
const url = backend ? `/ui/models?backend=${encodeURIComponent(backend)}${instance ? `&instance=${encodeURIComponent(instance)}` : ""}` : null;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
/** Runtime and account are part of the key: Windows never borrows a WSL catalog. */
|
|
49
|
+
export function useModelCatalogState(backend, instance, runtime, machineId) {
|
|
50
|
+
const url = backend ? `/ui/models?backend=${encodeURIComponent(backend)}${instance ? `&instance=${encodeURIComponent(instance)}` : ""}${runtime === "windows" ? "&runtime=windows" : ""}${machineId ? `&machineId=${encodeURIComponent(machineId)}` : ""}` : null;
|
|
51
|
+
const [state, setState] = useState({ url:null, answer:null, loading:false });
|
|
52
|
+
const generation = useRef(0), active = useRef(url);
|
|
53
|
+
active.current = url;
|
|
54
|
+
const load = (force = false) => {
|
|
55
|
+
if (!url) return;
|
|
56
|
+
const mine = ++generation.current;
|
|
57
|
+
setState(old => ({ url, answer:old.url === url ? old.answer : null, loading:true }));
|
|
58
|
+
cached(url, force).then(answer => {
|
|
59
|
+
if (active.current === url && generation.current === mine) setState({ url, answer, loading:false });
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (url) load();
|
|
64
|
+
return () => { generation.current++; };
|
|
65
|
+
}, [url]);
|
|
66
|
+
const current = state.url === url ? state : { answer:null, loading:!!url };
|
|
67
|
+
const valid = current.answer && Array.isArray(current.answer.models);
|
|
68
|
+
return {
|
|
69
|
+
models: valid ? current.answer.models : [],
|
|
70
|
+
loading: !!url && current.loading,
|
|
71
|
+
error: !!url && !current.loading && !valid,
|
|
72
|
+
source: valid ? current.answer.source : null,
|
|
73
|
+
refresh: () => load(true),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Compatibility for callers that only need the model list. */
|
|
78
|
+
export function useModelCatalog(backend, instance, runtime) {
|
|
79
|
+
const state = useModelCatalogState(backend, instance, runtime);
|
|
80
|
+
return state.loading && !state.models.length ? undefined : state.models;
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
/** A state that keeps a backend from being chosen (shown, disabled, with why); "unknown" never does. */
|
|
@@ -196,7 +196,9 @@ export async function confirmedWrite(path, { method = "POST", body, key = newKey
|
|
|
196
196
|
/** A decided request as the write's own answer. */
|
|
197
197
|
export function outcomeResponse(view) {
|
|
198
198
|
if (view.state === "applied") return { ok: true, status: 200, body: (view.outcome && view.outcome.result) || {}, confirmed: view };
|
|
199
|
-
const
|
|
199
|
+
const base = (view.outcome && (view.outcome.message || view.outcome.reason_code)) || view.state;
|
|
200
|
+
// S-35: a failed apply says why (the store bounds and sanitizes the reason).
|
|
201
|
+
const reason = view.outcome && view.outcome.detail ? `${base} (${view.outcome.detail})` : base;
|
|
200
202
|
return { ok: false, status: 409, body: { error: reason, pending_state: view.state }, confirmed: view };
|
|
201
203
|
}
|
|
202
204
|
|
|
@@ -18,7 +18,7 @@ import { goToTarget } from "./settings-registry.js";
|
|
|
18
18
|
import { sectionPath } from "/assets/app-route.js";
|
|
19
19
|
import { backendLabel } from "/assets/instance-nav.js";
|
|
20
20
|
import "./settings-strings.js"; // its words, wherever a picker of this file is used (#2072: Fleet's create dialog too)
|
|
21
|
-
import { backendChoices, modelChoices, OTHER_MODEL, useBackendRows,
|
|
21
|
+
import { backendChoices, modelChoices, OTHER_MODEL, useBackendRows, useModelCatalogState } from "./settings-catalog.js";
|
|
22
22
|
import {
|
|
23
23
|
ACCESS_MODES, AGENT_MODES, CH_TYPES, DASHBOARD_CHOICES, DASHBOARD_FEATURES, HANG_TIMEOUT_DEFAULT_MINUTES, LOG_LEVELS, TOOL_PROGRESS, TOOL_SETS,
|
|
24
24
|
VISIBILITY_MODES, accessConfirmations, agentForm, agentPatch, backendOptions, changedFields, channelId, channelsOf,
|
|
@@ -60,16 +60,25 @@ export function BackendSelect({ value, onChange, disabled, id }) {
|
|
|
60
60
|
* the current value in it: choosing "Other…" alone changes nothing — emptying the box is what inherits, #2098 review).
|
|
61
61
|
* `inherit`: the label of the empty choice (inherit / none), or omit it when the field has none.
|
|
62
62
|
*/
|
|
63
|
-
export function ModelSelect({ value, onChange, disabled, id, backend, instance, inherit }) {
|
|
64
|
-
const
|
|
63
|
+
export function ModelSelect({ value, onChange, disabled, id, backend, instance, runtime, machineId, inherit, catalogOverride }) {
|
|
64
|
+
const state = useModelCatalogState(catalogOverride === undefined ? backend : null, instance, runtime, machineId);
|
|
65
|
+
const catalog = catalogOverride === undefined ? state.models : catalogOverride;
|
|
65
66
|
const [typing, setTyping] = useState(false);
|
|
67
|
+
useEffect(() => { setTyping(false); }, [backend, instance, runtime]);
|
|
66
68
|
const opts = modelChoices(catalog || [], value, { notListed: tn("modelNotListed"), other: tn("modelOther") }, inherit);
|
|
69
|
+
const managed = catalogOverride === undefined && !!backend;
|
|
70
|
+
const sourceNote = state.source === "cli-list" ? "modelCatalogCliList" : state.source === "cli-cache" ? "modelCatalogCliCache"
|
|
71
|
+
: ["documented", "official-catalog", "cli-alias"].includes(state.source) ? "modelCatalogOfficial" : "modelCatalogCached";
|
|
72
|
+
const note = state.loading ? "modelCatalogLoading" : state.error ? "modelCatalogFailed" : !catalog?.length ? "modelCatalogEmpty"
|
|
73
|
+
: sourceNote;
|
|
67
74
|
return html`<div class="model-pick">
|
|
68
|
-
<select id=${id} value=${typing ? OTHER_MODEL : value} disabled=${disabled}
|
|
75
|
+
<select id=${id} value=${typing ? OTHER_MODEL : value} disabled=${disabled} aria-busy=${managed && state.loading ? "true" : undefined}
|
|
69
76
|
onChange=${(e) => { const v = e.target.value; if (v === OTHER_MODEL) setTyping(true); else { setTyping(false); onChange(v); } }}>
|
|
70
77
|
${opts.map((o) => html`<option key=${o.value} value=${o.value}>${o.label}</option>`)}</select>
|
|
71
78
|
${typing ? html`<input type="text" aria-label=${tn("modelOtherLabel")} placeholder=${tn("modelOtherPlaceholder")} disabled=${disabled}
|
|
72
|
-
value=${value} onInput=${(e) => onChange(e.target.value)} />` : null}
|
|
79
|
+
value=${value} onInput=${(e) => onChange(e.target.value)} />` : null}
|
|
80
|
+
${managed ? html`<div class="model-catalog-status"><span class="note" role=${state.error ? "alert" : "status"} aria-live="polite">${state.loading ? html`<span class="out-spin" aria-hidden="true"></span> ` : null}${tn(note)}</span><button type="button" class="btn btn-ghost btn-sm" disabled=${disabled || state.loading} onClick=${state.refresh}>${tn(state.error || !catalog?.length ? "modelCatalogRetry" : "modelCatalogRefresh")}</button></div>` : null}
|
|
81
|
+
</div>`;
|
|
73
82
|
}
|
|
74
83
|
export function Impact({ schema, field }) { return html`<span class="impact">${impactText(impactOf(schema, field))}</span>`; }
|
|
75
84
|
export function Label({ text, schema, field, htmlFor, mark }) {
|
|
@@ -32,6 +32,11 @@ const ROWS = [
|
|
|
32
32
|
// Fleet · Agents
|
|
33
33
|
["agents.new", "agents", "#newAgentBtn", "settings.newAgent", null, ["new agent", "create", "add agent", "instance"], ["新增 agent", "建立", "新 agent"]],
|
|
34
34
|
["agents.provider-keys", "agents", ".s-provider-keys", "settings.providerKeys", "web.provider_secrets", ["api key", "provider", "openai", "anthropic", "token", "secret"], ["API 金鑰", "金鑰", "供應商", "token"]],
|
|
35
|
+
// M-2255: the two switches (fleet.yaml runtimes.*).
|
|
36
|
+
["runtimes.windows-cli", "runtimes", "#runtimeWindowsCli", null, "runtimes.windows_cli", ["windows cli", "this pc", "local windows", "AGEND_WINDOWS_CLI", "codex", "claude code"], ["Windows CLI", "這台電腦", "本機"], L("Use this PC's Windows CLIs", "使用這台電腦 Windows 上的 CLI")],
|
|
37
|
+
["runtimes.remote-runtime", "runtimes", "#runtimeRemoteRuntime", null, "runtimes.remote_runtime", ["pair", "remote", "other computer", "AGEND_REMOTE_RUNTIME", "tailscale", "ssh"], ["配對", "遠端", "其他電腦"], L("Allow other Windows PCs to pair", "允許其他 Windows 電腦配對")],
|
|
38
|
+
["runtimes.max-agents", "runtimes", "#runtimeMaxAgents", null, "runtimes.max_agents_per_machine", ["concurrent", "at once", "limit", "parallel", "how many agents"], ["同時", "上限", "並行", "數量"], L("Agents at once on each Windows PC", "每台 Windows 電腦同時執行的 Agent 數")],
|
|
39
|
+
["runtimes.machines", "runtimes", ".runtime-settings", "settings.sec_runtimes", null, ["runtime", "computer", "machine", "pair", "connect", "windows", "linux", "CLI"], ["執行環境", "電腦", "機器", "配對", "連接", "Windows", "CLI"]],
|
|
35
40
|
["defaults.tips", "agent-defaults", "#g-tips", "settings.dailyTips", "defaults.tips", ["daily tips", "notices"], ["每日提示"]],
|
|
36
41
|
["web.notify-login", "access", "#webNotifyLogin", "settings.webNotifyLogin", "web.notify_login", ["sign in", "login", "notices"], ["登入通知"]],
|
|
37
42
|
// Fleet · Agent defaults
|